mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-09-11 12:05:40 +00:00
Successful release fast paths publish image tags but never dispatch the job that creates the GitHub release and decrypt binaries. Dispatch `deploy.yml` from both image routes. A default-off `images_published` input skips E2E and image rebuilding only for an already-published tag; missing or mismatched images keep the complete fallback without requiring new inputs on older workflow definitions. Go validation still gates the release binaries, checkout and version flags retain the tagged source, and the existing release action uploads both architectures before publication. Missing binary files now fail publication. Fixes #1956. Validation: - `node test-issue-1956-release-routing.js` executes the actual workflow shell steps with registry and dispatch commands stubbed. Covers matching, missing and mismatched images; failed retag and Go validation; branch/PR boundaries; and both tagged binary commands. - The original test commit fails because a matching image dispatches zero artifact workflows; the fix passes the same assertion. - Existing release workflow Go checks, decrypt/channel tests, YAML parsing and actionlint pass. - Both static Linux amd64 and arm64 binaries cross-build with verified architecture and version metadata. Actual registry publication and GitHub release creation were not exercised. Existing immutable releases and old tags that contain older workflow definitions are outside this fix. Following #1922, this is a focused release-routing PR. A separate repair for #1858 rewrites the shared frontend test runner; merging this first lets that repair retain this regression in its authoritative list. Please assess current Go and E2E job results separately from workflow-approval or staging-runner state.
137 lines
5.8 KiB
YAML
137 lines
5.8 KiB
YAML
name: Release Fast-Path
|
|
|
|
# Issue #1677: re-tag :edge as :vX.Y.Z when the tag SHA matches :edge's
|
|
# org.opencontainers.image.revision label. Skips Playwright + Docker rebuild
|
|
# because the application bytes are identical. Both paths dispatch deploy.yml
|
|
# for Go validation and release binaries; mismatched SHAs also run the full
|
|
# image pipeline so tags on older commits still go through full validation.
|
|
#
|
|
# This workflow is the SOLE consumer of push.tags. deploy.yml's tag
|
|
# trigger has been removed to prevent double-fire.
|
|
|
|
on:
|
|
push:
|
|
tags: ['v[0-9]+.[0-9]+.[0-9]+']
|
|
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
actions: write # issue #1702: required for the `gh workflow run deploy.yml` dispatch
|
|
|
|
concurrency:
|
|
group: release-fast-path-${{ github.ref }}
|
|
cancel-in-progress: false
|
|
|
|
jobs:
|
|
retag-or-fallback:
|
|
name: "🏷️ Re-tag :edge and dispatch release artifacts or full fallback"
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Log in to GHCR
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Install crane
|
|
uses: imjasonh/setup-crane@v0.4
|
|
|
|
- name: Parse semver from tag
|
|
id: semver
|
|
run: |
|
|
set -euo pipefail
|
|
TAG="${GITHUB_REF#refs/tags/}"
|
|
# Expect vMAJOR.MINOR.PATCH (workflow trigger already enforces this).
|
|
if [[ ! "$TAG" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
|
|
echo "Tag $TAG does not match vMAJOR.MINOR.PATCH" >&2
|
|
exit 1
|
|
fi
|
|
MAJOR="${BASH_REMATCH[1]}"
|
|
MINOR="${BASH_REMATCH[2]}"
|
|
{
|
|
echo "tag=$TAG"
|
|
echo "vMajor=v$MAJOR"
|
|
echo "vMajorMinor=v$MAJOR.$MINOR"
|
|
} >> "$GITHUB_OUTPUT"
|
|
echo "Parsed: $TAG → v$MAJOR / v$MAJOR.$MINOR / $TAG"
|
|
|
|
- name: Inspect :edge revision label
|
|
id: edge
|
|
run: |
|
|
set -euo pipefail
|
|
IMAGE="ghcr.io/kpa-clawbot/corescope"
|
|
EDGE_REF="${IMAGE}:edge"
|
|
# crane config returns the OCI image config JSON; the revision label
|
|
# is set by docker/metadata-action on the master-edge build.
|
|
# If :edge doesn't exist yet (first run on a fresh registry), fall
|
|
# through to the slow path.
|
|
if ! CONFIG="$(crane config "$EDGE_REF" 2>/dev/null)"; then
|
|
echo "edge_revision=" >> "$GITHUB_OUTPUT"
|
|
echo "no_edge=true" >> "$GITHUB_OUTPUT"
|
|
echo ":edge not found in registry — will use fallback path"
|
|
exit 0
|
|
fi
|
|
REV="$(echo "$CONFIG" | jq -r '.config.Labels["org.opencontainers.image.revision"] // ""')"
|
|
echo "edge_revision=$REV" >> "$GITHUB_OUTPUT"
|
|
echo "no_edge=false" >> "$GITHUB_OUTPUT"
|
|
echo ":edge org.opencontainers.image.revision = $REV"
|
|
echo "tag SHA (github.sha) = ${{ github.sha }}"
|
|
|
|
# ─────────── FAST PATH: SHAs match, metadata-only retag ───────────
|
|
# Issue #1807: a plain `crane tag` keeps the ldflags-baked
|
|
# Version="edge" inside the binary, so /api/stats reports "edge" on
|
|
# tagged releases. Instead of a full rebuild we append a single-file
|
|
# layer (/app/.image-version containing the tag) and set the OCI
|
|
# version label, then point the remaining tags at that mutated image.
|
|
# The server reads .image-version at startup (see resolveVersion()).
|
|
- name: Re-tag :edge → :vX.Y.Z + :vX.Y + :vX + :latest (fast path)
|
|
if: steps.edge.outputs.no_edge == 'false' && steps.edge.outputs.edge_revision == github.sha
|
|
run: |
|
|
set -euo pipefail
|
|
IMAGE="ghcr.io/kpa-clawbot/corescope"
|
|
SRC="${IMAGE}:edge"
|
|
TAG="${{ steps.semver.outputs.tag }}"
|
|
echo "SHA match — fast-path re-tag from $SRC"
|
|
|
|
# Build a one-file layer: /app/.image-version = vX.Y.Z
|
|
LAYER_DIR="$(mktemp -d)"
|
|
mkdir -p "${LAYER_DIR}/app"
|
|
printf '%s' "$TAG" > "${LAYER_DIR}/app/.image-version"
|
|
tar --owner=0 --group=0 --mtime='UTC 2020-01-01' \
|
|
-C "$LAYER_DIR" -cf /tmp/image-version-layer.tar app
|
|
echo " crane mutate $SRC (+.image-version layer, +version label) → ${IMAGE}:${TAG}"
|
|
crane mutate "$SRC" \
|
|
--append /tmp/image-version-layer.tar \
|
|
--label "org.opencontainers.image.version=${TAG}" \
|
|
--tag "${IMAGE}:${TAG}"
|
|
|
|
for NEW_TAG in \
|
|
"${{ steps.semver.outputs.vMajorMinor }}" \
|
|
"${{ steps.semver.outputs.vMajor }}" \
|
|
"latest"; do
|
|
echo " crane tag ${IMAGE}:${TAG} $NEW_TAG"
|
|
crane tag "${IMAGE}:${TAG}" "$NEW_TAG"
|
|
done
|
|
echo "Fast-path complete — release tags point at :edge plus a one-file version layer."
|
|
|
|
# Both image routes need the single release-artifacts writer in deploy.yml.
|
|
- name: Dispatch release artifacts or full deploy.yml pipeline
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
set -euo pipefail
|
|
DISPATCH_ARGS=()
|
|
if [[ "${{ steps.edge.outputs.no_edge == 'false' && steps.edge.outputs.edge_revision == github.sha }}" == 'true' ]]; then
|
|
echo "Images published — dispatching Go validation and release artifacts"
|
|
DISPATCH_ARGS+=(--field images_published=true)
|
|
else
|
|
# No new inputs: an older tag may have an older deploy.yml schema.
|
|
echo "SHA mismatch (or no :edge) — falling back to full pipeline"
|
|
fi
|
|
gh workflow run deploy.yml \
|
|
--repo "${{ github.repository }}" \
|
|
--ref "${{ github.ref }}" \
|
|
"${DISPATCH_ARGS[@]}"
|
|
echo "Dispatched deploy.yml against ${{ github.ref }}"
|