ci: release v1 automatically on a green merge to main #28
+38
-10
@@ -115,10 +115,7 @@ jobs:
|
|||||||
timeout-minutes: 2
|
timeout-minutes: 2
|
||||||
# The workflow-level group above is keyed per-commit (github.sha) so
|
# The workflow-level group above is keyed per-commit (github.sha) so
|
||||||
# unrelated commits' CI never blocks each other -- which also means two
|
# unrelated commits' CI never blocks each other -- which also means two
|
||||||
# merges landing close together run two concurrent release-tag jobs, each
|
# merges landing close together can run two concurrent release-tag jobs.
|
||||||
# force-pushing its OWN commit to v1. If the older one finishes last, v1
|
|
||||||
# regresses to a stale-but-green commit until the next merge corrects it.
|
|
||||||
#
|
|
||||||
# A job-level `concurrency:` is a second, independent group scoped to
|
# A job-level `concurrency:` is a second, independent group scoped to
|
||||||
# this job alone -- it does not replace the workflow-level one, it adds
|
# this job alone -- it does not replace the workflow-level one, it adds
|
||||||
# to it (confirmed by reading gitea's source at the v1.27.2 tag this
|
# to it (confirmed by reading gitea's source at the v1.27.2 tag this
|
||||||
@@ -126,12 +123,13 @@ jobs:
|
|||||||
# fields, evaluated and enforced by separate functions --
|
# fields, evaluated and enforced by separate functions --
|
||||||
# CancelPreviousJobsByRunConcurrency vs CancelPreviousJobsByJobConcurrency
|
# CancelPreviousJobsByRunConcurrency vs CancelPreviousJobsByJobConcurrency
|
||||||
# in models/actions/{run,run_job}.go -- not one overriding the other).
|
# in models/actions/{run,run_job}.go -- not one overriding the other).
|
||||||
# A fixed, non-sha group name is what serialises across commits:
|
# This serialises jobs that are actually running or queued AT THE SAME
|
||||||
# `cancel-in-progress: false` keeps a running push from being interrupted
|
# TIME -- it has no notion of commit order between jobs that never
|
||||||
# by a newer one, and Gitea's default "single pending slot" behaviour
|
# overlap. Two release-tag runs on a 2-slot, 4-repo runner with a
|
||||||
# (same as GitHub's) already supersedes any older QUEUED attempt with the
|
# multi-minute selftest ahead of each can easily not overlap at all,
|
||||||
# newest one once the running job clears -- so this can delay v1 landing
|
# finishing in either order regardless of push order. The step below is
|
||||||
# on the newest commit, never regress it to an older one.
|
# what makes the OUTCOME order-independent; this group only bounds how
|
||||||
|
# much work is wasted getting there.
|
||||||
concurrency:
|
concurrency:
|
||||||
group: release-tag-v1
|
group: release-tag-v1
|
||||||
cancel-in-progress: false
|
cancel-in-progress: false
|
||||||
@@ -142,14 +140,44 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
|
# fetch-depth: 0 fetches full history AND all tags (actions/checkout's
|
||||||
|
# own description: "0 indicates all history for all branches and
|
||||||
|
# tags") -- REQUIRED so refs/tags/v1 and the ancestry behind it are
|
||||||
|
# both present locally for the merge-base check below, regardless of
|
||||||
|
# which commit this run happens to be built from.
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
# The concurrency group above only excludes a SIMULTANEOUS competing
|
||||||
|
# push; it does nothing for two release-tag jobs that never overlap
|
||||||
|
# and finish in the opposite order from the merges that triggered
|
||||||
|
# them -- which a shared 2-slot runner and a multi-minute selftest
|
||||||
|
# ahead of this job make routine, not rare. So the push itself has to
|
||||||
|
# be safe regardless of completion order: skip whenever v1 already
|
||||||
|
# points at this commit or a descendant of it, rather than trusting
|
||||||
|
# this run to be the last one to finish. `--is-ancestor` treats a
|
||||||
|
# commit as its own ancestor, so "already at" and "already ahead" are
|
||||||
|
# one case. A v1 that doesn't exist yet, or that shares no history
|
||||||
|
# with this commit, falls through to the push below -- the guard is
|
||||||
|
# only ever a reason to skip, never a reason to fail.
|
||||||
|
- name: Skip if v1 already at or ahead of this commit
|
||||||
|
id: check
|
||||||
|
run: |
|
||||||
|
if git rev-parse -q --verify refs/tags/v1 >/dev/null \
|
||||||
|
&& git merge-base --is-ancestor "${{ github.sha }}" refs/tags/v1; then
|
||||||
|
echo "v1 already at or ahead of ${{ github.sha }} -- nothing to do"
|
||||||
|
echo "skip=true" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "skip=false" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
# Lightweight tag, matching what v1 already is (`git cat-file -t v1`
|
# Lightweight tag, matching what v1 already is (`git cat-file -t v1`
|
||||||
# reports `commit`, not `tag`) -- no identity needed to move it, only
|
# reports `commit`, not `tag`) -- no identity needed to move it, only
|
||||||
# to push it.
|
# to push it.
|
||||||
- name: Force v1 to this commit
|
- name: Force v1 to this commit
|
||||||
|
if: steps.check.outputs.skip != 'true'
|
||||||
run: |
|
run: |
|
||||||
git tag -f v1 "${{ github.sha }}"
|
git tag -f v1 "${{ github.sha }}"
|
||||||
git push --force origin v1
|
git push --force origin v1
|
||||||
|
|||||||
Reference in New Issue
Block a user