diff --git a/config/agentrun.yaml b/config/agentrun.yaml index 1b577f5d..55936d16 100644 --- a/config/agentrun.yaml +++ b/config/agentrun.yaml @@ -617,7 +617,7 @@ controlPlane: path: deploy/gitops/node/jd01/runtime-v02 argoNamespace: argocd argoApplication: agentrun-jd01-v02 - repoURL: http://git-mirror-http.devops-infra.svc.cluster.local:8080/pikasTech/agentrun.git + repoURL: http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-agentrun.git deployment: format: unidesk-yaml-only gitopsRoot: deploy/gitops/node/jd01 @@ -643,7 +643,7 @@ controlPlane: unideskSshEndpointEnv: name: UNIDESK_MAIN_SERVER_IP value: 74.48.78.17 - bootRepoUrl: http://git-mirror-http.devops-infra.svc.cluster.local:8080/pikasTech/agentrun.git + bootRepoUrl: http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-agentrun.git imageBuild: context: . containerfile: deploy/container/Containerfile @@ -772,7 +772,7 @@ controlPlane: readDeployment: git-mirror-http writeService: git-mirror-write writeDeployment: git-mirror-write - readUrl: http://git-mirror-http.devops-infra.svc.cluster.local:8080/pikasTech/agentrun.git + readUrl: http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-agentrun.git writeUrl: http://git-mirror-write.devops-infra.svc.cluster.local:8080/pikasTech/agentrun.git cachePvc: hwlab-git-mirror-cache cacheHostPath: null diff --git a/config/platform-infra/gitea.yaml b/config/platform-infra/gitea.yaml index 0c5443f3..768d01ba 100644 --- a/config/platform-infra/gitea.yaml +++ b/config/platform-infra/gitea.yaml @@ -84,6 +84,7 @@ sourceAuthority: owner: mirrors name: pikasTech-agentrun mirrorMode: controlled-push + publicRead: true readUrl: http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-agentrun.git gitops: branch: jd01-v0.2-gitops @@ -104,6 +105,7 @@ sourceAuthority: owner: mirrors name: pikasTech-unidesk mirrorMode: controlled-push + publicRead: true readUrl: http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-unidesk.git gitops: branch: master diff --git a/config/platform-infra/pipelines-as-code.yaml b/config/platform-infra/pipelines-as-code.yaml index 8478c06d..80742d27 100644 --- a/config/platform-infra/pipelines-as-code.yaml +++ b/config/platform-infra/pipelines-as-code.yaml @@ -57,7 +57,7 @@ repository: concurrencyLimit: 1 params: git_read_url: http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-agentrun.git - git_write_url: http://git-mirror-write.devops-infra.svc.cluster.local:8080/pikasTech/agentrun.git + git_write_url: http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-agentrun.git source_branch: v0.2 gitops_branch: jd01-v0.2-gitops source_snapshot_prefix: refs/unidesk/snapshots/gitea-actions/agentrun-v0.2 diff --git a/scripts/src/agentrun-manifests.ts b/scripts/src/agentrun-manifests.ts index 36c215eb..f73b08dd 100644 --- a/scripts/src/agentrun-manifests.ts +++ b/scripts/src/agentrun-manifests.ts @@ -265,6 +265,14 @@ function agentRunBuildPublishTask(spec: AgentRunLaneSpec): Record \"$root/build-result.json\"", "fi", + "chmod a+rw \"$root/build-result.json\"", "cat \"$root/build-result.json\"", ].join("\n"); } @@ -428,8 +440,14 @@ function agentRunTektonGitopsPublishScript(spec: AgentRunLaneSpec): string { "build_result=\"$root/build-result.json\"", "test -s \"$build_result\"", `templates_b64=${JSON.stringify(templateB64)}`, + "git_write_url='$(params.git-write-url)'", + "git_auth_url=\"$git_write_url\"", + "if printf '%s' \"$git_write_url\" | grep -q '^http://gitea-http\\.'; then", + " test -n \"${GITEA_TOKEN:-}\"", + " git_auth_url=$(printf '%s' \"$git_write_url\" | sed \"s#^http://#http://x-access-token:${GITEA_TOKEN}@#\")", + "fi", "rm -rf \"$root/gitops\"", - "git clone \"$(params.git-write-url)\" \"$root/gitops\"", + "git clone \"$git_auth_url\" \"$root/gitops\"", "cd \"$root/gitops\"", "git fetch origin \"$(params.gitops-branch)\" || true", "if git rev-parse --verify \"refs/remotes/origin/$(params.gitops-branch)^{commit}\" >/dev/null 2>&1; then git checkout -B \"$(params.gitops-branch)\" \"refs/remotes/origin/$(params.gitops-branch)\"; else git checkout --orphan \"$(params.gitops-branch)\"; git rm -rf . >/dev/null 2>&1 || true; fi", @@ -455,6 +473,7 @@ function agentRunTektonGitopsPublishScript(spec: AgentRunLaneSpec): string { "NODE", "git add source.json \"$(params.artifact-catalog)\" \"$(params.gitops-root)\"", "if git diff --quiet --cached; then changed=false; else changed=true; git -c user.email=agentrun@unidesk.local -c user.name='UniDesk AgentRun PaC' commit -m \"deploy: render AgentRun $(params.gitops-branch) from PaC\"; fi", + "git remote set-url origin \"$git_auth_url\"", "git push -u origin \"$(params.gitops-branch)\"", "gitops_commit=$(git rev-parse HEAD)", "BUILD_RESULT=\"$build_result\" CHANGED=\"$changed\" GITOPS_COMMIT=\"$gitops_commit\" node <<'NODE'", diff --git a/scripts/src/platform-infra-gitea-remote.sh b/scripts/src/platform-infra-gitea-remote.sh index 4689e552..bd13cee4 100644 --- a/scripts/src/platform-infra-gitea-remote.sh +++ b/scripts/src/platform-infra-gitea-remote.sh @@ -349,15 +349,19 @@ try: for repo in repos: owner = repo["gitea"]["owner"] if owner not in orgs: - orgs[owner] = request("POST", "/api/v1/orgs", {"username": owner, "full_name": "UniDesk internal mirrors", "visibility": "private"}, expected=(201,), tolerate=(409, 422)) + orgs[owner] = { + "create": request("POST", "/api/v1/orgs", {"username": owner, "full_name": "UniDesk internal mirrors", "visibility": "public"}, expected=(201,), tolerate=(409, 422)), + "patch": request("PATCH", f"/api/v1/orgs/{owner}", {"full_name": "UniDesk internal mirrors", "visibility": "public"}, expected=(200,), tolerate=()), + } repositories.append({ "key": repo["key"], "owner": owner, "name": repo["gitea"]["name"], - "create": request("POST", f"/api/v1/orgs/{owner}/repos", {"name": repo["gitea"]["name"], "private": False, "auto_init": False, "description": f"UniDesk controlled mirror for {repo['upstream']['repository']}"}, expected=(201,), tolerate=(409, 422)), + "create": request("POST", f"/api/v1/orgs/{owner}/repos", {"name": repo["gitea"]["name"], "private": not bool(repo["gitea"].get("publicRead")), "auto_init": False, "description": f"UniDesk controlled mirror for {repo['upstream']['repository']}"}, expected=(201,), tolerate=(409, 422)), + "patch": request("PATCH", f"/api/v1/repos/{owner}/{repo['gitea']['name']}", {"private": not bool(repo["gitea"].get("publicRead")), "description": f"UniDesk controlled mirror for {repo['upstream']['repository']}"}, expected=(200,), tolerate=()), }) payload = {"auth": auth, "orgs": orgs, "repositories": repositories} - ok = auth.get("ok") and all(v.get("ok") for v in orgs.values()) and all(item["create"].get("ok") for item in repositories) + ok = auth.get("ok") and all(v["create"].get("ok") and v["patch"].get("ok") for v in orgs.values()) and all(item["create"].get("ok") and item["patch"].get("ok") for item in repositories) except Exception as exc: payload = { "auth": {"ok": False}, diff --git a/scripts/src/platform-infra-gitea.ts b/scripts/src/platform-infra-gitea.ts index b2236866..a2c57435 100644 --- a/scripts/src/platform-infra-gitea.ts +++ b/scripts/src/platform-infra-gitea.ts @@ -164,12 +164,13 @@ interface GiteaMirrorRepository { cloneUrl: string; branch: string; }; - gitea: { - owner: string; - name: string; - mirrorMode: "controlled-push"; - readUrl: string; - }; + gitea: { + owner: string; + name: string; + mirrorMode: "controlled-push"; + publicRead: boolean; + readUrl: string; + }; gitops: { branch: string; flushDisposition: string; @@ -484,6 +485,7 @@ function parseMirrorRepository(record: Record, index: number): owner: y.stringField(gitea, "owner", `${path}.gitea`), name: giteaRepoNameField(gitea, "name", `${path}.gitea`), mirrorMode: y.enumField(gitea, "mirrorMode", `${path}.gitea`, ["controlled-push"] as const), + publicRead: y.booleanField(gitea, "publicRead", `${path}.gitea`), readUrl: urlField(gitea, "readUrl", `${path}.gitea`), }, gitops: { diff --git a/scripts/src/platform-infra-pipelines-as-code-remote.sh b/scripts/src/platform-infra-pipelines-as-code-remote.sh index a586c795..aa7a9705 100644 --- a/scripts/src/platform-infra-pipelines-as-code-remote.sh +++ b/scripts/src/platform-infra-pipelines-as-code-remote.sh @@ -79,10 +79,20 @@ ensure_token() { ensure_webhook() { hooks=$(gitea_api GET "repos/$UNIDESK_PAC_GITEA_OWNER/$UNIDESK_PAC_GITEA_REPO/hooks") - hook_id=$(printf '%s' "$hooks" | tr '{' '\n' | awk -v url="$UNIDESK_PAC_WEBHOOK_URL" 'index($0, url)>0 { if (match($0, /"id"[[:space:]]*:[[:space:]]*[0-9]+/)) { print substr($0, RSTART); exit } }' | sed -n 's/[^0-9]*\([0-9][0-9]*\).*/\1/p') + hook_ids=$(HOOKS_JSON="$hooks" node <<'NODE' +const data = JSON.parse(process.env.HOOKS_JSON || '[]'); +const url = process.env.UNIDESK_PAC_WEBHOOK_URL; +for (const item of data) if (item?.config?.url === url && item?.id) console.log(item.id); +NODE +) + hook_id=$(printf '%s\n' "$hook_ids" | sed -n '1p') body=$(printf '{"type":"gitea","config":{"url":"%s","content_type":"json","secret":"%s"},"events":["push"],"active":true}' "$UNIDESK_PAC_WEBHOOK_URL" "$UNIDESK_PAC_WEBHOOK_SECRET") if [ -n "$hook_id" ]; then gitea_api PATCH "repos/$UNIDESK_PAC_GITEA_OWNER/$UNIDESK_PAC_GITEA_REPO/hooks/$hook_id" "$body" >/dev/null + printf '%s\n' "$hook_ids" | sed -n '2,$p' | while IFS= read -r duplicate_id; do + [ -n "$duplicate_id" ] || continue + gitea_api DELETE "repos/$UNIDESK_PAC_GITEA_OWNER/$UNIDESK_PAC_GITEA_REPO/hooks/$duplicate_id" >/dev/null || true + done else created=$(gitea_api POST "repos/$UNIDESK_PAC_GITEA_OWNER/$UNIDESK_PAC_GITEA_REPO/hooks" "$body") hook_id=$(printf '%s' "$created" | sed -n 's/.*"id"[[:space:]]*:[[:space:]]*\([0-9][0-9]*\).*/\1/p') @@ -164,9 +174,11 @@ condition_status() { } pipeline_rows() { - payload=$(kubectl -n "$UNIDESK_PAC_TARGET_NAMESPACE" get pipelinerun -o json 2>/dev/null || echo '{"items":[]}') - PIPELINE_JSON="$payload" node <<'NODE' -const input = process.env.PIPELINE_JSON || '{"items":[]}'; + payload_file=$(mktemp) + kubectl -n "$UNIDESK_PAC_TARGET_NAMESPACE" get pipelinerun -o json >"$payload_file" 2>/dev/null || printf '{"items":[]}' >"$payload_file" + node - "$payload_file" <<'NODE' +const fs = require('node:fs'); +const input = fs.readFileSync(process.argv[2], 'utf8') || '{"items":[]}'; const data = input ? JSON.parse(input) : { items: [] }; function cond(item) { const c = (item.status?.conditions || []).find((x) => x.type === 'Succeeded') || {}; @@ -198,12 +210,15 @@ const rows = (data.items || []) }); process.stdout.write(JSON.stringify(rows)); NODE + rm -f "$payload_file" } task_rows() { - payload=$(kubectl -n "$UNIDESK_PAC_TARGET_NAMESPACE" get taskrun -o json 2>/dev/null || echo '{"items":[]}') - TASK_JSON="$payload" node <<'NODE' -const input = process.env.TASK_JSON || '{"items":[]}'; + payload_file=$(mktemp) + kubectl -n "$UNIDESK_PAC_TARGET_NAMESPACE" get taskrun -o json >"$payload_file" 2>/dev/null || printf '{"items":[]}' >"$payload_file" + node - "$payload_file" <<'NODE' +const fs = require('node:fs'); +const input = fs.readFileSync(process.argv[2], 'utf8') || '{"items":[]}'; const data = input ? JSON.parse(input) : { items: [] }; const pr = process.env.UNIDESK_PAC_TARGET_PIPELINERUN || ''; function cond(item) { @@ -226,6 +241,37 @@ const rows = (data.items || []) }); process.stdout.write(JSON.stringify(rows)); NODE + rm -f "$payload_file" +} + +artifact_summary() { + if [ -z "${UNIDESK_PAC_TARGET_PIPELINERUN:-}" ]; then + printf '{}' + return + fi + log_file=$(mktemp) + kubectl -n "$UNIDESK_PAC_TARGET_NAMESPACE" logs -l "tekton.dev/pipelineRun=$UNIDESK_PAC_TARGET_PIPELINERUN" --all-containers --tail=240 >"$log_file" 2>/dev/null || true + node - "$log_file" <<'NODE' +const fs = require('node:fs'); +const lines = fs.readFileSync(process.argv[2], 'utf8').split(/\r?\n/); +const records = []; +for (const line of lines) { + const trimmed = line.trim(); + if (!trimmed.startsWith('{') || !trimmed.endsWith('}')) continue; + try { records.push(JSON.parse(trimmed)); } catch {} +} +const publish = [...records].reverse().find((item) => item.phase === 'gitops-publish' || item.gitopsCommit); +const image = publish || [...records].reverse().find((item) => item.imageStatus || item.status === 'reused' || item.status === 'built'); +process.stdout.write(JSON.stringify(image ? { + imageStatus: image.imageStatus || image.status || null, + envIdentity: image.envIdentity || null, + digest: image.digest || null, + gitopsCommit: image.gitopsCommit || null, + sourceCommit: image.sourceCommit || null, + valuesPrinted: false, +} : { valuesPrinted: false })); +NODE + rm -f "$log_file" } hook_summary() { @@ -246,14 +292,15 @@ status_action() { latest=$(printf '%s' "$pipelines" | node -e 'const fs=require("fs"); const a=JSON.parse(fs.readFileSync(0,"utf8")||"[]"); process.stdout.write(a[0]?.name||"")') export UNIDESK_PAC_TARGET_PIPELINERUN="$latest" tasks=$(task_rows) + artifact=$(artifact_summary) hooks=$(hook_summary) argo=$(kubectl -n "$UNIDESK_PAC_ARGO_NAMESPACE" get application "$UNIDESK_PAC_ARGO_APPLICATION" -o json 2>/dev/null | node -e 'const fs=require("fs"); const s=fs.readFileSync(0,"utf8").trim(); if(!s){process.stdout.write("{}"); process.exit(0)} const a=JSON.parse(s); process.stdout.write(JSON.stringify({sync:a.status?.sync?.status||null, health:a.status?.health?.status||null, revision:a.status?.sync?.revision||null}))' || echo '{}') - printf '{"ok":%s,"crdPresent":%s,"controllerReady":"%s","repositoryCondition":"%s","webhooks":%s,"pipelineRuns":%s,"taskRuns":%s,"argo":%s,"valuesPrinted":false}\n' \ + printf '{"ok":%s,"crdPresent":%s,"controllerReady":"%s","repositoryCondition":"%s","webhooks":%s,"pipelineRuns":%s,"taskRuns":%s,"artifact":%s,"argo":%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 "$repository_condition")" \ - "$hooks" "$pipelines" "$tasks" "$argo" + "$hooks" "$pipelines" "$tasks" "$artifact" "$argo" } webhook_test_action() { diff --git a/scripts/src/platform-infra-pipelines-as-code.ts b/scripts/src/platform-infra-pipelines-as-code.ts index 9a497f8f..14536f28 100644 --- a/scripts/src/platform-infra-pipelines-as-code.ts +++ b/scripts/src/platform-infra-pipelines-as-code.ts @@ -316,7 +316,7 @@ async function status(config: UniDeskConfig, options: CommonOptions): Promise): Record): RenderedCliResult { const summary = record(result.summary); const latest = record(summary.latestPipelineRun); const taskRuns = arrayRecords(summary.taskRuns); + const artifact = record(summary.artifact); const argo = record(summary.argo); const lines = [ "PLATFORM-INFRA PIPELINES-AS-CODE STATUS", @@ -592,6 +594,9 @@ function renderStatus(result: Record): RenderedCliResult { "TASKRUN DURATIONS", ...(taskRuns.length === 0 ? ["-"] : table(["TASKRUN", "STATUS", "REASON", "DURATION_S"], taskRuns.map((item) => [short(stringValue(item.name), 56), stringValue(item.status), stringValue(item.reason), stringValue(item.durationSeconds)]))), "", + "IMAGE / GITOPS", + ...table(["IMAGE_STATUS", "ENV_ID", "DIGEST", "GITOPS"], [[stringValue(artifact.imageStatus), stringValue(artifact.envIdentity), short(stringValue(artifact.digest), 18), short(stringValue(artifact.gitopsCommit))]]), + "", "ARGO", ...table(["SYNC", "HEALTH", "REVISION"], [[stringValue(argo.sync), stringValue(argo.health), short(stringValue(argo.revision))]]), "",