90bfcaa388
Every commit on dev that's part of an open PR fires each workflow TWICE: once for the push event and once for the pull_request event (observable in run #43 + #44 for the same SHA in android.yml, same shape across test-web.yml and test-go.yml). The two runs check the exact same SHA — pure waste. Drop the pull_request trigger from test-web.yml, test-go.yml, and android.yml. The dev push already exercises every check that a PR would re-run. This repo has no fork PRs to cover, which is the only case pull_request would catch that push doesn't. Add a concurrency group keyed on workflow + ref with cancel-in-progress: true to every workflow including release.yml. Rapid re-pushes (or force-moving the per-day tag) now cancel the older in-flight run instead of stacking.
121 lines
4.6 KiB
YAML
121 lines
4.6 KiB
YAML
name: release
|
|
|
|
# Builds and pushes the minstrel container image to the Gitea registry.
|
|
#
|
|
# push to main → :main and :latest
|
|
# push tag vYYYY.MM.DD → :vYYYY.MM.DD and :latest
|
|
# workflow_dispatch → manual trigger (same rules based on the ref)
|
|
#
|
|
# Release model: per-day CalVer tags (no trailing patch digit). The day's
|
|
# tag is intentionally mutable — if a second release happens the same day,
|
|
# move the tag with `git push -f origin vYYYY.MM.DD` and the image tag of
|
|
# the same name gets overwritten. :latest is updated by every main push
|
|
# AND every tag push, so it always reflects the newest blessed image.
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
tags: ['v*']
|
|
# Tag pushes still build (tag releases are intentional, server + Flutter
|
|
# share the version). Branch pushes skip when the diff is Flutter-only —
|
|
# rebuilding the Go image for a Flutter-only merge wastes CI and churns
|
|
# the registry.
|
|
paths-ignore:
|
|
- 'flutter_client/**'
|
|
- 'docs/**'
|
|
- '**/*.md'
|
|
workflow_dispatch:
|
|
|
|
# Force-moving the per-day tag (or rapidly re-pushing to main) should
|
|
# supersede the in-flight build — the operator explicitly wants the
|
|
# later commit to win.
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
release:
|
|
runs-on: go-ci
|
|
container:
|
|
image: git.fabledsword.com/bvandeusen/ci-go:1.26
|
|
|
|
env:
|
|
IMAGE: git.fabledsword.com/bvandeusen/minstrel
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Detect buildable project
|
|
id: guard
|
|
shell: bash
|
|
run: |
|
|
if [ -f Dockerfile ] && [ -f go.mod ]; then
|
|
echo "ready=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "ready=false" >> "$GITHUB_OUTPUT"
|
|
echo "::notice::No Dockerfile + go.mod yet — release build skipped"
|
|
fi
|
|
|
|
- name: Compute image tags
|
|
id: tags
|
|
if: steps.guard.outputs.ready == 'true'
|
|
shell: bash
|
|
run: |
|
|
if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
|
|
VERSION="${GITHUB_REF#refs/tags/}"
|
|
echo "args=-t ${IMAGE}:${VERSION} -t ${IMAGE}:latest" >> "$GITHUB_OUTPUT"
|
|
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
|
echo "::notice::Release build: ${VERSION} + latest"
|
|
else
|
|
# Main is the protected, post-PR-merge branch. Treat it as the
|
|
# rolling stable channel — every main push moves :latest.
|
|
# Pinned consumers can target :vYYYY.MM.DD; everyone else
|
|
# gets the newest main.
|
|
echo "args=-t ${IMAGE}:main -t ${IMAGE}:latest" >> "$GITHUB_OUTPUT"
|
|
echo "version=main" >> "$GITHUB_OUTPUT"
|
|
echo "::notice::Main-branch build: :main + :latest"
|
|
fi
|
|
|
|
- name: Registry login
|
|
if: steps.guard.outputs.ready == 'true'
|
|
shell: bash
|
|
run: |
|
|
echo "${{ secrets.CI_TOKEN }}" \
|
|
| docker login git.fabledsword.com -u "${{ github.actor }}" --password-stdin
|
|
|
|
# In-app update flow (#397): on tag pushes only, fetch the APK
|
|
# that flutter.yml is attaching to this same release. flutter.yml
|
|
# runs in parallel; poll up to 15 min for the asset to appear.
|
|
# On main pushes (or if the APK never lands), client/ stays empty
|
|
# and the endpoints return 404 — graceful degradation.
|
|
- name: Fetch APK for bundled in-app update channel
|
|
if: steps.guard.outputs.ready == 'true' && startsWith(github.ref, 'refs/tags/v')
|
|
shell: bash
|
|
env:
|
|
CI_TOKEN: ${{ secrets.CI_TOKEN }}
|
|
run: |
|
|
TAG="${GITHUB_REF#refs/tags/}"
|
|
REPO="${GITHUB_REPOSITORY}"
|
|
APK_URL="https://git.fabledsword.com/${REPO}/releases/download/${TAG}/minstrel-${TAG}.apk"
|
|
echo "Polling ${APK_URL} (up to 15 min for flutter.yml to attach)..."
|
|
for i in $(seq 1 30); do
|
|
if curl -fsSL -H "Authorization: token ${CI_TOKEN}" \
|
|
-o client/minstrel.apk "$APK_URL"; then
|
|
echo "Got APK on attempt $i"
|
|
echo "${TAG}" > client/minstrel.apk.version
|
|
ls -lh client/
|
|
exit 0
|
|
fi
|
|
echo "APK not ready yet (attempt $i/30), sleeping 30s..."
|
|
sleep 30
|
|
done
|
|
echo "::warning::APK never appeared at ${APK_URL} after 15 min — image will ship without bundled update channel"
|
|
|
|
- name: Build and push
|
|
if: steps.guard.outputs.ready == 'true'
|
|
run: |
|
|
docker buildx build \
|
|
--build-arg MINSTREL_VERSION="${{ steps.tags.outputs.version }}" \
|
|
--push ${{ steps.tags.outputs.args }} .
|