mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-08 03:32:27 +09:00
Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38b7c63431 | ||
|
|
57d08cd091 | ||
|
|
91e2d31614 | ||
|
|
d375dc7946 | ||
|
|
3fffce2a4a |
@@ -11859,7 +11859,39 @@
|
||||
},
|
||||
"process_count": {"$ref": "#/components/schemas/Int32Type"},
|
||||
"process_limit": {"$ref": "#/components/schemas/Int32Type"},
|
||||
"uptime_seconds": {"$ref": "#/components/schemas/Int32Type"}
|
||||
"uptime_seconds": {"$ref": "#/components/schemas/Int32Type"},
|
||||
"cluster_metrics": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"gateway_cluster_member_count": {"$ref": "#/components/schemas/Int32Type"},
|
||||
"gateway_cluster_discovery_resolve_failures_total": {"$ref": "#/components/schemas/Int32Type"},
|
||||
"gateway_cluster_membership_transitions_total": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"up": {"$ref": "#/components/schemas/Int32Type"},
|
||||
"down": {"$ref": "#/components/schemas/Int32Type"}
|
||||
},
|
||||
"required": ["up", "down"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"gateway_node_router_owner_resolutions_total": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"self": {"$ref": "#/components/schemas/Int32Type"},
|
||||
"peer": {"$ref": "#/components/schemas/Int32Type"}
|
||||
},
|
||||
"required": ["self", "peer"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"gateway_cluster_member_count",
|
||||
"gateway_cluster_discovery_resolve_failures_total",
|
||||
"gateway_cluster_membership_transitions_total",
|
||||
"gateway_node_router_owner_resolutions_total"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"node_id",
|
||||
|
||||
@@ -1355,6 +1355,7 @@ export class MessageSendService {
|
||||
attachments: attachmentsToProcess,
|
||||
attachmentUploadUserId: user.id,
|
||||
processedAttachments: favoriteMemeAttachment ? [favoriteMemeAttachment] : undefined,
|
||||
stickerIds: data.sticker_ids ? data.sticker_ids.flatMap((stickerId) => createStickerID(stickerId)) : undefined,
|
||||
messageReference,
|
||||
messageSnapshots,
|
||||
guildId: null,
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
import type {WebhookEvent} from 'livekit-server-sdk';
|
||||
import {describe, expect, it, vi} from 'vitest';
|
||||
import type {ChannelID, GuildID} from '../../BrandedTypes';
|
||||
import {createChannelID, createGuildID} from '../../BrandedTypes';
|
||||
import type {IVoiceRepository} from '../../voice/IVoiceRepository';
|
||||
import {VoiceTopology} from '../../voice/VoiceTopology';
|
||||
import type {IGatewayService} from '../IGatewayService';
|
||||
import type {ILiveKitService} from '../ILiveKitService';
|
||||
@@ -29,7 +29,12 @@ function harness(pinnedServerId: string | null) {
|
||||
} as unknown as IVoiceRoomStore;
|
||||
const gatewayService = {disconnectAllVoiceUsersInChannel} as unknown as IGatewayService;
|
||||
const liveKitService = {} as unknown as ILiveKitService;
|
||||
const service = new LiveKitWebhookService(voiceRoomStore, gatewayService, liveKitService, new VoiceTopology());
|
||||
const service = new LiveKitWebhookService(
|
||||
voiceRoomStore,
|
||||
gatewayService,
|
||||
liveKitService,
|
||||
new VoiceTopology({} as unknown as IVoiceRepository, null),
|
||||
);
|
||||
return {service, deleteRoomServer, disconnectAllVoiceUsersInChannel};
|
||||
}
|
||||
|
||||
|
||||
@@ -1140,6 +1140,20 @@ export const NodeStatsResponse = z.object({
|
||||
process_count: Int32Type,
|
||||
process_limit: Int32Type,
|
||||
uptime_seconds: Int32Type,
|
||||
cluster_metrics: z
|
||||
.object({
|
||||
gateway_cluster_member_count: Int32Type,
|
||||
gateway_cluster_discovery_resolve_failures_total: Int32Type,
|
||||
gateway_cluster_membership_transitions_total: z.object({
|
||||
up: Int32Type,
|
||||
down: Int32Type,
|
||||
}),
|
||||
gateway_node_router_owner_resolutions_total: z.object({
|
||||
self: Int32Type,
|
||||
peer: Int32Type,
|
||||
}),
|
||||
})
|
||||
.optional(),
|
||||
}),
|
||||
)
|
||||
.max(1000),
|
||||
|
||||
+57
-16
@@ -446,27 +446,39 @@ fn run_promote(args: PromoteArgs) -> Result<()> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
for other in COMPONENTS
|
||||
.iter()
|
||||
.filter(|other| other.image != component.image)
|
||||
{
|
||||
for tag in &tags {
|
||||
inspect_digest(&format!("{}/{}:{tag}", args.registry, other.image)).with_context(
|
||||
|| {
|
||||
format!(
|
||||
"Refusing to advance {tag} for {}: {} has no published {tag} image; run the build-{} workflow first",
|
||||
component.image,
|
||||
other.image,
|
||||
workflow_suffix(other.image)
|
||||
)
|
||||
},
|
||||
)?;
|
||||
}
|
||||
for warning in unpublished_moving_tags(&args.registry, component.image, &tags, |reference| {
|
||||
inspect_digest(reference).is_ok()
|
||||
}) {
|
||||
println!("warning: {warning}");
|
||||
}
|
||||
|
||||
run_command(promote_command(&image, &digest, &tags))
|
||||
}
|
||||
|
||||
fn unpublished_moving_tags<F>(
|
||||
registry: &str,
|
||||
component: &str,
|
||||
tags: &[String],
|
||||
mut published: F,
|
||||
) -> Vec<String>
|
||||
where
|
||||
F: FnMut(&str) -> bool,
|
||||
{
|
||||
let mut warnings = Vec::new();
|
||||
for other in COMPONENTS.iter().filter(|other| other.image != component) {
|
||||
for tag in tags {
|
||||
if !published(&format!("{registry}/{}:{tag}", other.image)) {
|
||||
warnings.push(format!(
|
||||
"{} has no published {tag} image, so {tag} stays an incomplete set until the build-{} workflow runs",
|
||||
other.image,
|
||||
workflow_suffix(other.image)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
warnings
|
||||
}
|
||||
|
||||
fn write_release_files(out_dir: &Path, manifest: &ImageSetManifest) -> Result<()> {
|
||||
fs::create_dir_all(out_dir)
|
||||
.with_context(|| format!("Failed to create {}", out_dir.display()))?;
|
||||
@@ -1097,6 +1109,35 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unpublished_moving_tags_are_reported_without_blocking_the_promote() {
|
||||
let tags = ["v1".to_string(), "latest".to_string()];
|
||||
let complete = unpublished_moving_tags("ghcr.io/fluxerapp", "fluxer-docs", &tags, |_| true);
|
||||
assert!(complete.is_empty());
|
||||
|
||||
let bootstrapping =
|
||||
unpublished_moving_tags("ghcr.io/fluxerapp", "fluxer-docs", &tags, |reference| {
|
||||
!reference.starts_with("ghcr.io/fluxerapp/fluxer-recon:")
|
||||
});
|
||||
assert_eq!(
|
||||
bootstrapping,
|
||||
[
|
||||
"fluxer-recon has no published v1 image, so v1 stays an incomplete set until the build-recon workflow runs",
|
||||
"fluxer-recon has no published latest image, so latest stays an incomplete set until the build-recon workflow runs",
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unpublished_moving_tags_never_reports_the_component_being_promoted() {
|
||||
let tags = ["v1".to_string()];
|
||||
let warnings =
|
||||
unpublished_moving_tags("ghcr.io/fluxerapp", "fluxer-recon", &tags, |reference| {
|
||||
!reference.starts_with("ghcr.io/fluxerapp/fluxer-recon:")
|
||||
});
|
||||
assert!(warnings.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn calver_tag_for_digest_picks_the_single_calver_tag() {
|
||||
let tags = ["2026.630.20736", "latest", "v1"].map(str::to_string);
|
||||
|
||||
Reference in New Issue
Block a user