fix(cicd): match PaC repositories by public Gitea URL
This commit is contained in:
@@ -15,6 +15,7 @@ GitHub remains the upstream write authority. A delivery should be triggered by m
|
||||
- Historical snapshot prefixes containing `gitea-actions` are retained only for existing refs. They do not mean Gitea Actions is the active trigger architecture.
|
||||
- Node-level status for these consumers is `bun scripts/cli.ts cicd status --node <NODE>`. Consumer drill-down is `platform-infra pipelines-as-code status|history|closeout --target <NODE> --consumer <id>`.
|
||||
- Multi-node PaC consumers that share a GitHub upstream must not share a webhook bridge URL. Each target node declares its own GitHub webhook public path and FRP remote port in `config/platform-infra/gitea.yaml#targets[].webhookSync`, then `platform-infra gitea apply --target <NODE> --confirm` renders the node-local bridge, FRPC proxy and PK01 Caddy path.
|
||||
- PaC Repository CR `spec.url` matches the URL in Gitea webhook payloads. Keep `config/platform-infra/pipelines-as-code.yaml#repositories[].url` on the public Gitea repository URL, and keep k8s-internal service URLs only in `cloneUrl` or `params.git_read_url`; otherwise PaC logs `cannot find a repository match` and no PipelineRun is created.
|
||||
|
||||
## Coverage Matrix
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ templates:
|
||||
name: "agentrun-${nodeLower}-v02"
|
||||
namespace: agentrun-ci
|
||||
providerType: gitea
|
||||
url: http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-agentrun
|
||||
url: https://gitea.pikapython.com/mirrors/pikasTech-agentrun
|
||||
cloneUrl: http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-agentrun.git
|
||||
owner: mirrors
|
||||
repo: pikasTech-agentrun
|
||||
@@ -138,7 +138,7 @@ templates:
|
||||
name: "sentinel-${nodeLower}-v03"
|
||||
namespace: devops-infra
|
||||
providerType: gitea
|
||||
url: http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-unidesk
|
||||
url: https://gitea.pikapython.com/mirrors/pikasTech-unidesk
|
||||
cloneUrl: http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-unidesk.git
|
||||
owner: mirrors
|
||||
repo: pikasTech-unidesk
|
||||
@@ -164,7 +164,7 @@ templates:
|
||||
name: "hwlab-${nodeLower}-v03"
|
||||
namespace: hwlab-ci
|
||||
providerType: gitea
|
||||
url: http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-HWLAB
|
||||
url: https://gitea.pikapython.com/mirrors/pikasTech-HWLAB
|
||||
cloneUrl: http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-HWLAB.git
|
||||
owner: mirrors
|
||||
repo: pikasTech-HWLAB
|
||||
@@ -215,4 +215,4 @@ templates:
|
||||
pipelineRunPrefix: "hwlab-${nodeLower}-v03-ci-poll"
|
||||
argoNamespace: argocd
|
||||
argoApplication: hwlab-node-v03
|
||||
closeoutGitOpsMirrorFlush: true
|
||||
closeoutGitOpsMirrorFlush: true
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
- Target webhook FRP remote ports must be checked against the live PK01 FRP listener set as well as YAML declarations. `frpc` log `port already used` means the GitHub delivery may hit an unrelated service and return 404; a port outside the PK01 published listener set can return 502 from Caddy. Fix the YAML port, re-apply with rollout wait, then use a fresh GitHub PR merge as the trigger evidence.
|
||||
- `platform-infra gitea mirror webhook status --target <node>` is the default webhook closeout surface: it must show hook readiness, GitHub head, Gitea branch/snapshot, latest delivery status and bridge log event so a node-specific webhook problem can be diagnosed without reading source code or raw logs.
|
||||
- The canonical PaC entrypoints are `bun scripts/cli.ts platform-infra pipelines-as-code plan|apply|status|history|webhook-test --target <node>`. PaC status is the operator-facing closeout surface for migrated CI lanes and must expose webhook count, latest PipelineRun/TaskRun duration, image status, env identity, digest, GitOps commit, Argo revision and runtime provenance without requiring raw `kubectl`, `tkn` or Gitea UI inspection.
|
||||
- PaC Repository CR `spec.url` is the URL matcher for incoming Gitea webhook payloads, so `config/platform-infra/pipelines-as-code.yaml#repositories[].url` must use the public Gitea repository URL emitted by Gitea webhooks. Internal ClusterIP/service URLs belong in `cloneUrl` and `params.git_read_url`; putting an internal URL in `spec.url` makes PaC log `cannot find a repository match` and creates no PipelineRun even though the Gitea mirror is current.
|
||||
- PaC Repository CR params must use the node-specific Gitea snapshot prefix declared for that consumer, such as `unidesk-master-nc01` for NC01 sentinel. A generic or other-node prefix can make the repository look healthy while fresh pushes cannot close out against the target node source.
|
||||
- PaC history is the trigger/timing audit surface for Gitea/PaC-managed lanes. It must query Gitea Repository CR and Tekton PipelineRun/TaskRun live objects on the target node, aggregate there, return Beijing-time display by YAML timezone, expose a detail id for drill-down, and report read errors explicitly; a large namespace or unreadable target object must never be rendered as a successful empty table.
|
||||
- Formal delivery for a PaC-migrated consumer starts with merging the GitHub PR into that consumer's YAML-declared upstream branch. The GitHub webhook bridge then syncs GitHub to the controlled Gitea mirror and immutable snapshot refs; the Gitea repository push webhook triggers Pipelines-as-Code, which creates the Tekton PipelineRun. Operators must not replace this with `trigger-current`, `webhook-test`, a direct Gitea push, raw PipelineRun creation, or a local Git mirror edit. `webhook-test` is only a connectivity diagnostic.
|
||||
|
||||
@@ -139,7 +139,6 @@ NODE
|
||||
}
|
||||
|
||||
repository_manifest() {
|
||||
repository_url=$(resolve_service_url_to_cluster_ip "$UNIDESK_PAC_REPOSITORY_URL")
|
||||
cat <<EOF
|
||||
apiVersion: pipelinesascode.tekton.dev/v1alpha1
|
||||
kind: Repository
|
||||
@@ -151,7 +150,7 @@ metadata:
|
||||
app.kubernetes.io/part-of: $UNIDESK_PAC_PART_OF
|
||||
unidesk.ai/spec: $UNIDESK_PAC_SPEC
|
||||
spec:
|
||||
url: $repository_url
|
||||
url: $UNIDESK_PAC_REPOSITORY_URL
|
||||
git_provider:
|
||||
type: gitea
|
||||
url: $UNIDESK_PAC_GITEA_BASE_URL
|
||||
@@ -913,10 +912,15 @@ status_action() {
|
||||
argo=$(json_normalize "$argo")
|
||||
runtime=$(json_normalize "$(runtime_summary)")
|
||||
diagnostics=$(cicd_diagnostics "$pipelines" "$artifact" "$argo" "$runtime")
|
||||
printf '{"ok":%s,"crdPresent":%s,"controllerReady":"%s","repositoryCondition":"%s","webhooks":%s,"pipelineRuns":%s,"taskRuns":%s,"artifact":%s,"argo":%s,"runtime":%s,"diagnostics":%s,"valuesPrinted":false}\n' \
|
||||
printf '{"ok":%s,"crdPresent":%s,"controllerReady":"%s","repository":{"name":"%s","repo":"%s/%s","url":"%s","condition":"%s"},"repositoryCondition":"%s","webhooks":%s,"pipelineRuns":%s,"taskRuns":%s,"artifact":%s,"argo":%s,"runtime":%s,"diagnostics":%s,"valuesPrinted":false}\n' \
|
||||
"$( [ -n "$crd" ] && [ "$controller_ready" != "0/0" ] && echo true || echo false )" \
|
||||
"$( [ -n "$crd" ] && echo true || echo false )" \
|
||||
"$(json_string "$controller_ready")" \
|
||||
"$(json_string "$UNIDESK_PAC_REPOSITORY_NAME")" \
|
||||
"$(json_string "$UNIDESK_PAC_GITEA_OWNER")" \
|
||||
"$(json_string "$UNIDESK_PAC_GITEA_REPO")" \
|
||||
"$(json_string "$UNIDESK_PAC_REPOSITORY_URL")" \
|
||||
"$(json_string "$repository_condition")" \
|
||||
"$(json_string "$repository_condition")" \
|
||||
"$hooks" "$pipelines" "$tasks" "$artifact" "$argo" "$runtime" "$diagnostics"
|
||||
}
|
||||
|
||||
@@ -350,6 +350,7 @@ function validateConfig(config: PacConfig): void {
|
||||
if (ids.has(repository.id)) throw new Error(`${configLabel}.repositories id must be unique: ${repository.id}`);
|
||||
ids.add(repository.id);
|
||||
if (repository.providerType !== "gitea") throw new Error(`${configLabel}.repositories.${repository.id}.providerType must be gitea`);
|
||||
if (isInternalRepositoryMatchUrl(repository.url)) throw new Error(`${configLabel}.repositories.${repository.id}.url must be the public Gitea URL used in webhook payloads; keep internal service URLs in cloneUrl/params.git_read_url`);
|
||||
if (new URL(repository.cloneUrl).origin !== new URL(config.gitea.internalBaseUrl).origin) throw new Error(`${configLabel}.repositories.${repository.id}.cloneUrl must use the configured internal Gitea base URL`);
|
||||
}
|
||||
const consumerIds = new Set<string>();
|
||||
@@ -775,6 +776,7 @@ function statusSummary(payload: Record<string, unknown>): Record<string, unknown
|
||||
const argo = record(payload.argo);
|
||||
const runtime = record(payload.runtime);
|
||||
const diagnostics = record(payload.diagnostics);
|
||||
const webhooks = arrayRecords(payload.webhooks);
|
||||
const artifact = {
|
||||
...record(payload.artifact),
|
||||
imageStatus: record(payload.artifact).imageStatus ?? (runtime.image === undefined ? undefined : "runtime"),
|
||||
@@ -787,7 +789,9 @@ function statusSummary(payload: Record<string, unknown>): Record<string, unknown
|
||||
crdPresent: payload.crdPresent === true,
|
||||
controllerReady: payload.controllerReady,
|
||||
repositoryCondition: payload.repositoryCondition,
|
||||
webhookCount: arrayRecords(payload.webhooks).length,
|
||||
repository: record(payload.repository),
|
||||
webhooks,
|
||||
webhookCount: webhooks.length,
|
||||
latestPipelineRun: latest,
|
||||
taskRuns,
|
||||
pipelineRunGate: pipelineGate,
|
||||
@@ -872,11 +876,22 @@ function policyChecks(repository: PacRepository): Array<Record<string, unknown>>
|
||||
return [
|
||||
{ name: "single-path", ok: true, detail: "Gitea webhook -> Pipelines-as-Code -> Tekton -> Argo/k8s runtime; no Gitea Actions/act_runner/branch-follower fallback." },
|
||||
{ name: "yaml-source-of-truth", ok: true, detail: `${configLabel} owns PaC release, Repository CR, Gitea webhook and consumer params.` },
|
||||
{ name: "public-repository-url", ok: !isInternalRepositoryMatchUrl(repository.url), detail: "Repository CR url matches the public Gitea webhook payload URL; internal service URLs remain clone/read URLs only." },
|
||||
{ name: "gitea-internal-source", ok: repository.cloneUrl.includes(".svc.cluster.local"), detail: "Tekton source clone uses the internal k3s Gitea service URL." },
|
||||
{ name: "runtime-zero-docker", ok: true, detail: "Runtime starts at k8s pulling already-built images; CI build may use Tekton/BuildKit." },
|
||||
];
|
||||
}
|
||||
|
||||
function isInternalRepositoryMatchUrl(value: string): boolean {
|
||||
const parsed = new URL(value);
|
||||
return parsed.hostname.endsWith(".svc.cluster.local")
|
||||
|| parsed.hostname === "localhost"
|
||||
|| parsed.hostname === "127.0.0.1"
|
||||
|| /^10\./u.test(parsed.hostname)
|
||||
|| /^192\.168\./u.test(parsed.hostname)
|
||||
|| /^172\.(1[6-9]|2\d|3[0-1])\./u.test(parsed.hostname);
|
||||
}
|
||||
|
||||
function targetSummary(target: PacTarget): Record<string, unknown> {
|
||||
return { id: target.id, route: target.route, namespace: target.namespace, role: target.role };
|
||||
}
|
||||
@@ -1015,6 +1030,8 @@ function renderStatus(result: Record<string, unknown>): RenderedCliResult {
|
||||
const artifact = record(summary.artifact);
|
||||
const argo = record(summary.argo);
|
||||
const diagnostics = record(summary.diagnostics);
|
||||
const repository = record(summary.repository);
|
||||
const webhooks = arrayRecords(summary.webhooks);
|
||||
const lines = [
|
||||
"PLATFORM-INFRA PIPELINES-AS-CODE STATUS",
|
||||
...(coverage.length === 0 ? [] : [
|
||||
@@ -1022,7 +1039,11 @@ function renderStatus(result: Record<string, unknown>): RenderedCliResult {
|
||||
...table(["CONSUMER", "SOURCE", "NAMESPACE", "PIPELINE", "ARGO_APP"], coverage.map((item) => [stringValue(item.consumer), stringValue(item.source), stringValue(item.namespace), stringValue(item.pipeline), stringValue(item.argoApplication)])),
|
||||
"",
|
||||
]),
|
||||
...table(["CONSUMER", "READY", "CRD", "CONTROLLER", "WEBHOOKS", "REPOSITORY"], [[stringValue(consumer.id), boolText(summary.ready), boolText(summary.crdPresent), stringValue(summary.controllerReady), stringValue(summary.webhookCount), compactLine(stringValue(summary.repositoryCondition))]]),
|
||||
...table(["CONSUMER", "READY", "CRD", "CONTROLLER", "WEBHOOKS", "REPO_URL"], [[stringValue(consumer.id), boolText(summary.ready), boolText(summary.crdPresent), stringValue(summary.controllerReady), stringValue(summary.webhookCount), short(stringValue(repository.url), 56)]]),
|
||||
` repository-condition: ${compactLine(stringValue(summary.repositoryCondition))}`,
|
||||
"",
|
||||
"GITEA HOOKS",
|
||||
...(webhooks.length === 0 ? ["-"] : table(["HOOK", "ACTIVE", "EVENTS", "URL"], webhooks.map((item) => [stringValue(item.id), boolText(item.active), Array.isArray(item.events) ? item.events.join(",") : stringValue(item.events), short(stringValue(item.url), 56)]))),
|
||||
"",
|
||||
"LATEST PIPELINERUN",
|
||||
...table(["NAME", "STATUS", "REASON", "DURATION_S", "SOURCE"], [[stringValue(latest.name), stringValue(latest.status), stringValue(latest.reason), stringValue(latest.durationSeconds), short(stringValue(latest.sourceCommit))]]),
|
||||
|
||||
Reference in New Issue
Block a user