|
|
|
@@ -72,12 +72,6 @@ jobs:
|
|
|
|
|
lighthouse:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
|
needs: [test]
|
|
|
|
|
# CAR-1218: continue-on-error until the Gitea Actions act runner can
|
|
|
|
|
# reliably capture lhci's stdout (currently suppressed — lhci exits
|
|
|
|
|
# ~40ms after start with no log output). The job still runs and
|
|
|
|
|
# reports; failures are surfaced on the PR but no longer block it.
|
|
|
|
|
# Quality-gate assertions in lighthouserc.json are unchanged.
|
|
|
|
|
continue-on-error: true
|
|
|
|
|
steps:
|
|
|
|
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
|
|
|
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
|
|
|
|
@@ -91,28 +85,14 @@ jobs:
|
|
|
|
|
npm install -g playwright
|
|
|
|
|
npx playwright install --with-deps chromium
|
|
|
|
|
- name: Start preview server
|
|
|
|
|
# CAR-1218: bind to 127.0.0.1 (IPv4) not localhost. The act runner
|
|
|
|
|
# resolves 'localhost' to ::1 (IPv6) and the preview server does not
|
|
|
|
|
# get a reachable IPv4 socket, so wait-on times out.
|
|
|
|
|
run: |
|
|
|
|
|
npx vite preview --host 127.0.0.1 --port 4173 &
|
|
|
|
|
npx wait-on http://127.0.0.1:4173/ --timeout 30000
|
|
|
|
|
npm run preview &
|
|
|
|
|
npx wait-on http://localhost:4173/ --timeout 30000
|
|
|
|
|
- name: Run Lighthouse CI
|
|
|
|
|
# CAR-1218: act_runner does not honor continue-on-error at the job level
|
|
|
|
|
# (job still posts 'failure' status). Apply at the step level so the
|
|
|
|
|
# commit status reflects success and the PR is unblocked. lhci output
|
|
|
|
|
# is captured to a file (act_runner suppresses stdout from lhci).
|
|
|
|
|
continue-on-error: true
|
|
|
|
|
run: |
|
|
|
|
|
{
|
|
|
|
|
CHROME_PATH=$(find /home/runner/.cache/ms-playwright -name chrome -type f 2>/dev/null | head -1)
|
|
|
|
|
npm install -g @lhci/cli
|
|
|
|
|
CHROME_PATH="$CHROME_PATH" lhci autorun --chrome-flags="--headless=new --no-sandbox --disable-gpu --disable-dev-shm-usage"
|
|
|
|
|
} > /tmp/lhci.log 2>&1 || true
|
|
|
|
|
echo '=== lhci log (cat /tmp/lhci.log) ==='
|
|
|
|
|
cat /tmp/lhci.log || echo 'no lhci log produced'
|
|
|
|
|
echo '=== end lhci log ==='
|
|
|
|
|
exit 0
|
|
|
|
|
CHROME_PATH=$(find /home/runner/.cache/ms-playwright -name chrome -type f 2>/dev/null | head -1)
|
|
|
|
|
npm install -g @lhci/cli
|
|
|
|
|
CHROME_PATH="$CHROME_PATH" lhci autorun --chrome-flags="--headless=new --no-sandbox --disable-gpu --disable-dev-shm-usage"
|
|
|
|
|
|
|
|
|
|
build-and-push:
|
|
|
|
|
runs-on: ubuntu-latest
|
|
|
|
@@ -508,14 +488,14 @@ jobs:
|
|
|
|
|
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
|
|
|
|
echo "tag=${{ needs.build-and-push.outputs.calver_tag }}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
else
|
|
|
|
|
echo "tag=sha-${GITHUB_SHA}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
echo "tag=${{ needs.build-and-push.outputs.sha_tag }}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
- name: Update frontend image tag
|
|
|
|
|
if: needs.build-and-push.result == 'success'
|
|
|
|
|
run: |
|
|
|
|
|
cd infra/apps/overlays/dev
|
|
|
|
|
kustomize edit set image ghcr.io/cartsnitch/app=git.farh.net/cartsnitch/cartsnitch:${{ steps.frontend_tag.outputs.tag }}
|
|
|
|
|
kustomize edit set image ghcr.io/cartsnitch/cartsnitch=git.farh.net/cartsnitch/cartsnitch:${{ steps.frontend_tag.outputs.tag }}
|
|
|
|
|
|
|
|
|
|
- name: Determine image tag for receiptwitness
|
|
|
|
|
id: receiptwitness_tag
|
|
|
|
@@ -523,7 +503,7 @@ jobs:
|
|
|
|
|
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
|
|
|
|
echo "tag=${{ needs.build-and-push-receiptwitness.outputs.calver_tag }}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
else
|
|
|
|
|
echo "tag=sha-${GITHUB_SHA}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
echo "tag=${{ needs.build-and-push-receiptwitness.outputs.sha_tag }}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
- name: Update receiptwitness image tag
|
|
|
|
@@ -538,7 +518,7 @@ jobs:
|
|
|
|
|
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
|
|
|
|
echo "tag=${{ needs.build-and-push-api.outputs.calver_tag }}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
else
|
|
|
|
|
echo "tag=sha-${GITHUB_SHA}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
echo "tag=${{ needs.build-and-push-api.outputs.sha_tag }}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
- name: Update api image tag
|
|
|
|
@@ -553,7 +533,7 @@ jobs:
|
|
|
|
|
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
|
|
|
|
echo "tag=${{ needs.build-and-push-auth.outputs.calver_tag }}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
else
|
|
|
|
|
echo "tag=sha-${GITHUB_SHA}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
echo "tag=${{ needs.build-and-push-auth.outputs.sha_tag }}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
- name: Update auth image tag
|
|
|
|
@@ -579,7 +559,7 @@ jobs:
|
|
|
|
|
PR_JSON=$(curl -sS -X POST \
|
|
|
|
|
-H "Authorization: token ${CI_GITEA_TOKEN}" \
|
|
|
|
|
-H "Content-Type: application/json" \
|
|
|
|
|
-d "$(jq -n --arg head "cartsnitch:${BRANCH}" --arg base dev --arg title "ci(dev): update overlay image tags (${GITHUB_SHA::12})" --arg body "$PR_BODY" '{head:$head,base:$base,title:$title,body:$body}')" \
|
|
|
|
|
-d "$(jq -n --arg head "cartsnitch:${BRANCH}" --arg base main --arg title "ci(dev): update overlay image tags (${GITHUB_SHA::12})" --arg body "$PR_BODY" '{head:$head,base:$base,title:$title,body:$body}')" \
|
|
|
|
|
"https://git.farh.net/api/v1/repos/cartsnitch/infra/pulls")
|
|
|
|
|
PR_NUM=$(echo "$PR_JSON" | jq -r '.number // empty')
|
|
|
|
|
if [ -z "$PR_NUM" ]; then
|
|
|
|
@@ -597,16 +577,6 @@ jobs:
|
|
|
|
|
if [ "${REVIEW_HTTP}" -lt 200 ] || [ "${REVIEW_HTTP}" -ge 300 ]; then
|
|
|
|
|
echo "::notice::Failed to request reviewers for cartsnitch/infra PR #${PR_NUM} (HTTP ${REVIEW_HTTP}); continuing"
|
|
|
|
|
fi
|
|
|
|
|
# CAR-1216: the in-job merge attempt is a best-effort fast-path only.
|
|
|
|
|
# `cartsnitch/infra` main requires a human approving review (immutable
|
|
|
|
|
# branch protection); the CI bot (`CI_GITEA_TOKEN`) can never self-
|
|
|
|
|
# approve, so this merge call structurally cannot succeed in the
|
|
|
|
|
# general case. Any non-merged outcome (approvals pending, checks
|
|
|
|
|
# pending, any other Gitea message) is the GitOps approval gate, not
|
|
|
|
|
# a CI failure — the PR is already opened and `cs_savannah` is
|
|
|
|
|
# requested as reviewer above. Surface the response as a notice and
|
|
|
|
|
# exit success. The only hard-fail (`exit 1`) in this step remains
|
|
|
|
|
# the empty-`PR_NUM` check (PR could not be created at all).
|
|
|
|
|
MERGE_RESP=$(curl -sS -X POST \
|
|
|
|
|
-H "Authorization: token ${CI_GITEA_TOKEN}" \
|
|
|
|
|
-H "Content-Type: application/json" \
|
|
|
|
@@ -615,9 +585,17 @@ jobs:
|
|
|
|
|
MERGED=$(echo "$MERGE_RESP" | jq -r '.merged // false')
|
|
|
|
|
if [ "$MERGED" = "true" ]; then
|
|
|
|
|
echo "PR #${PR_NUM} merged into cartsnitch/infra main"
|
|
|
|
|
else
|
|
|
|
|
echo "::notice::infra PR #${PR_NUM} opened and awaiting CTO (cs_savannah) approve+merge — GitOps approval gate, not a failure: $MERGE_RESP"
|
|
|
|
|
elif echo "$MERGE_RESP" | grep -qi 'does not have enough approvals'; then
|
|
|
|
|
# GitOps approval gate: the PR is correctly opened and surfaces in
|
|
|
|
|
# the CTO queue via the reviewers request above. Treat as success
|
|
|
|
|
# (exit 0) so the deploy job does not hard-fail on the approvals
|
|
|
|
|
# requirement that only a human maintainer can satisfy.
|
|
|
|
|
echo "::notice::infra PR #${PR_NUM} opened and awaiting CTO (cs_savannah) approve+merge — GitOps approval gate, not a failure"
|
|
|
|
|
exit 0
|
|
|
|
|
else
|
|
|
|
|
echo "::error::Auto-merge of cartsnitch/infra PR #${PR_NUM} failed: $MERGE_RESP"
|
|
|
|
|
echo "::error::Reassign to cs_savannah (authorized merger for cartsnitch/infra main) for backstop merge."
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
deploy-uat:
|
|
|
|
@@ -654,14 +632,14 @@ jobs:
|
|
|
|
|
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
|
|
|
|
echo "tag=${{ needs.build-and-push.outputs.calver_tag }}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
else
|
|
|
|
|
echo "tag=sha-${GITHUB_SHA}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
echo "tag=${{ needs.build-and-push.outputs.sha_tag }}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
- name: Update frontend image tag
|
|
|
|
|
if: needs.build-and-push.result == 'success'
|
|
|
|
|
run: |
|
|
|
|
|
cd infra/apps/overlays/uat
|
|
|
|
|
kustomize edit set image ghcr.io/cartsnitch/app=git.farh.net/cartsnitch/cartsnitch:${{ steps.frontend_tag.outputs.tag }}
|
|
|
|
|
kustomize edit set image ghcr.io/cartsnitch/cartsnitch=git.farh.net/cartsnitch/cartsnitch:${{ steps.frontend_tag.outputs.tag }}
|
|
|
|
|
|
|
|
|
|
- name: Determine image tag for receiptwitness
|
|
|
|
|
id: receiptwitness_tag
|
|
|
|
@@ -669,7 +647,7 @@ jobs:
|
|
|
|
|
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
|
|
|
|
echo "tag=${{ needs.build-and-push-receiptwitness.outputs.calver_tag }}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
else
|
|
|
|
|
echo "tag=sha-${GITHUB_SHA}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
echo "tag=${{ needs.build-and-push-receiptwitness.outputs.sha_tag }}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
- name: Update receiptwitness image tag
|
|
|
|
@@ -684,7 +662,7 @@ jobs:
|
|
|
|
|
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
|
|
|
|
echo "tag=${{ needs.build-and-push-api.outputs.calver_tag }}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
else
|
|
|
|
|
echo "tag=sha-${GITHUB_SHA}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
echo "tag=${{ needs.build-and-push-api.outputs.sha_tag }}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
- name: Update api image tag
|
|
|
|
@@ -699,7 +677,7 @@ jobs:
|
|
|
|
|
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
|
|
|
|
echo "tag=${{ needs.build-and-push-auth.outputs.calver_tag }}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
else
|
|
|
|
|
echo "tag=sha-${GITHUB_SHA}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
echo "tag=${{ needs.build-and-push-auth.outputs.sha_tag }}" >> "$GITHUB_OUTPUT"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
- name: Update auth image tag
|
|
|
|
@@ -725,7 +703,7 @@ jobs:
|
|
|
|
|
PR_JSON=$(curl -sS -X POST \
|
|
|
|
|
-H "Authorization: token ${CI_GITEA_TOKEN}" \
|
|
|
|
|
-H "Content-Type: application/json" \
|
|
|
|
|
-d "$(jq -n --arg head "cartsnitch:${BRANCH}" --arg base uat --arg title "ci(uat): update overlay image tags (${GITHUB_SHA::12})" --arg body "$PR_BODY" '{head:$head,base:$base,title:$title,body:$body}')" \
|
|
|
|
|
-d "$(jq -n --arg head "cartsnitch:${BRANCH}" --arg base main --arg title "ci(uat): update overlay image tags (${GITHUB_SHA::12})" --arg body "$PR_BODY" '{head:$head,base:$base,title:$title,body:$body}')" \
|
|
|
|
|
"https://git.farh.net/api/v1/repos/cartsnitch/infra/pulls")
|
|
|
|
|
PR_NUM=$(echo "$PR_JSON" | jq -r '.number // empty')
|
|
|
|
|
if [ -z "$PR_NUM" ]; then
|
|
|
|
@@ -743,16 +721,6 @@ jobs:
|
|
|
|
|
if [ "${REVIEW_HTTP}" -lt 200 ] || [ "${REVIEW_HTTP}" -ge 300 ]; then
|
|
|
|
|
echo "::notice::Failed to request reviewers for cartsnitch/infra PR #${PR_NUM} (HTTP ${REVIEW_HTTP}); continuing"
|
|
|
|
|
fi
|
|
|
|
|
# CAR-1216: the in-job merge attempt is a best-effort fast-path only.
|
|
|
|
|
# `cartsnitch/infra` main requires a human approving review (immutable
|
|
|
|
|
# branch protection); the CI bot (`CI_GITEA_TOKEN`) can never self-
|
|
|
|
|
# approve, so this merge call structurally cannot succeed in the
|
|
|
|
|
# general case. Any non-merged outcome (approvals pending, checks
|
|
|
|
|
# pending, any other Gitea message) is the GitOps approval gate, not
|
|
|
|
|
# a CI failure — the PR is already opened and `cs_savannah` is
|
|
|
|
|
# requested as reviewer above. Surface the response as a notice and
|
|
|
|
|
# exit success. The only hard-fail (`exit 1`) in this step remains
|
|
|
|
|
# the empty-`PR_NUM` check (PR could not be created at all).
|
|
|
|
|
MERGE_RESP=$(curl -sS -X POST \
|
|
|
|
|
-H "Authorization: token ${CI_GITEA_TOKEN}" \
|
|
|
|
|
-H "Content-Type: application/json" \
|
|
|
|
@@ -761,7 +729,15 @@ jobs:
|
|
|
|
|
MERGED=$(echo "$MERGE_RESP" | jq -r '.merged // false')
|
|
|
|
|
if [ "$MERGED" = "true" ]; then
|
|
|
|
|
echo "PR #${PR_NUM} merged into cartsnitch/infra main"
|
|
|
|
|
else
|
|
|
|
|
echo "::notice::infra PR #${PR_NUM} opened and awaiting CTO (cs_savannah) approve+merge — GitOps approval gate, not a failure: $MERGE_RESP"
|
|
|
|
|
elif echo "$MERGE_RESP" | grep -qi 'does not have enough approvals'; then
|
|
|
|
|
# GitOps approval gate: the PR is correctly opened and surfaces in
|
|
|
|
|
# the CTO queue via the reviewers request above. Treat as success
|
|
|
|
|
# (exit 0) so the deploy job does not hard-fail on the approvals
|
|
|
|
|
# requirement that only a human maintainer can satisfy.
|
|
|
|
|
echo "::notice::infra PR #${PR_NUM} opened and awaiting CTO (cs_savannah) approve+merge — GitOps approval gate, not a failure"
|
|
|
|
|
exit 0
|
|
|
|
|
else
|
|
|
|
|
echo "::error::Auto-merge of cartsnitch/infra PR #${PR_NUM} failed: $MERGE_RESP"
|
|
|
|
|
echo "::error::Reassign to cs_savannah (authorized merger for cartsnitch/infra main) for backstop merge."
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|