forked from aztec-labs-eng/aztec-node
-
Notifications
You must be signed in to change notification settings - Fork 0
135 lines (130 loc) · 6.6 KB
/
Copy pathrelease-tag.yml
File metadata and controls
135 lines (130 loc) · 6.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# Creates release tags via the release GitHub App — the only identity the
# release-tags ruleset permits to create v* tags.
#
# nightly: cron (or dispatch with kind=nightly) -> v<ver>-nightly.<date>
# per branch in the nightly matrix below; unattended via the
# `tagger` environment.
# rc: dispatch with kind=rc -> v<ver>-rc.<n>
# from any branch (input); n is derived from origin's existing
# rc tags for that version (max + 1, starting at 1). Gated by
# `release-approval` like a real release; artifacts publish to
# the 'rc' channel and never take 'latest'.
# release: dispatch with kind=release -> v<ver>
# from any branch (input), gated by the `release-approval`
# environment: required reviewers with self-review prevented, so
# cutting a release takes two distinct humans.
#
# rc numbers are dotted (-rc.N, not -rcN): semver compares the dotted N
# numerically (rc.2 < rc.10) but an undotted rcN lexically (rc10 < rc2), and
# ci3/dist_tag takes the first dot-separated prerelease identifier as the
# release channel — 'rc' — where rcN would mint a fresh channel per candidate.
#
# Multi-branch model: scheduled/dispatched runs always execute THIS file from
# the default branch, so the token-minting code is always the reviewed code on
# main — and the environments' deployment policy stays main-only for the same
# reason. The branch being tagged is just data: each branch's version comes
# from its own .release-please-manifest.json, so a v5 line tags v5.x.y and
# main tags v6.x.y with no collision. To start nightlies for a new release
# line, add it to the matrix list below (a one-line reviewed PR).
name: Release Tag
on:
schedule:
# Every night at 4:00 AM UTC.
- cron: "0 4 * * *"
workflow_dispatch:
inputs:
kind:
description: "nightly re-tag, a release candidate (requires approval), or a real release (requires approval)"
type: choice
options: [nightly, rc, release]
default: nightly
branch:
description: "branch to tag (its manifest supplies the version)"
type: string
default: main
jobs:
tag:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# TO ADD A NEW RELEASE LINE to the nightly schedule: extend the LAST
# list in this expression, e.g. fromJSON('["main", "v5"]'). Nothing else
# changes — no environment, ruleset, or App-installation edits (see the
# multi-branch model in the header). The first arm of the expression is
# not a branch list: it collapses dispatch runs to the one requested branch.
branch: ${{ github.event_name == 'workflow_dispatch' && fromJSON(format('["{0}"]', inputs.branch)) || fromJSON('["main"]') }}
concurrency:
group: ${{ github.workflow }}-${{ github.repository }}-${{ matrix.branch }}
environment: ${{ (github.event_name == 'workflow_dispatch' && (inputs.kind == 'release' || inputs.kind == 'rc')) && 'release-approval' || 'tagger' }}
steps:
- name: Mint App token
uses: actions/create-github-app-token@v2
id: app
with:
app-id: ${{ vars.RELEASE_APP_ID || secrets.RELEASE_APP_ID }}
private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
# Do NOT bump to checkout v6 (see the pinning rationale in ci3.yml).
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1
with:
ref: ${{ matrix.branch }}
token: ${{ steps.app.outputs.token }}
- name: Create and push tag
run: |
set -euo pipefail
git config --global user.email "tech@aztecprotocol.com"
git config --global user.name "AztecBot"
version=$(jq -r '."."' .release-please-manifest.json)
kind=${{ github.event_name == 'workflow_dispatch' && inputs.kind || 'nightly' }}
case "$kind" in
release)
tag="v${version}"
;;
rc)
# Next candidate number comes from origin, not the clone: list the
# existing v<ver>-rc.* tags and take max+1 (1 when none). The trailing
# anchor also drops ls-remote's peeled ^{} duplicates.
last=$(git ls-remote --tags origin "refs/tags/v${version}-rc.*" \
| sed -n "s|.*refs/tags/v${version}-rc\.\([0-9][0-9]*\)$|\1|p" \
| sort -n | tail -1)
tag="v${version}-rc.$(( ${last:-0} + 1 ))"
;;
*)
tag="v${version}-nightly.$(date -u +%Y%m%d)"
;;
esac
echo "Tagging ${{ matrix.branch }} @ $(git rev-parse --short HEAD): $tag"
# Refuse to move an existing tag: re-dispatching a release without a
# version-bump PR must fail loudly, not re-tag.
if git ls-remote --exit-code --tags origin "refs/tags/$tag" >/dev/null; then
echo "::error::Tag $tag already exists. Bump .release-please-manifest.json on ${{ matrix.branch }} first."
exit 1
fi
git tag -a "$tag" -m "$tag"
git push origin "$tag"
# Nightly tagging is unattended, so a failure here is otherwise invisible: no tag is
# pushed and the release run that would report it never starts. Posted inline rather
# than via ci3/slack_notify because two of the three steps above can fail before the
# repo is checked out.
- name: Notify Slack on tagging failure
if: failure()
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
KIND: ${{ github.event_name == 'workflow_dispatch' && inputs.kind || 'nightly' }}
BRANCH: ${{ matrix.branch }}
ACTOR: ${{ github.actor }}
RUN_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
if [ -z "${SLACK_BOT_TOKEN:-}" ]; then
echo "No SLACK_BOT_TOKEN, skipping notification"
exit 0
fi
TEXT="Release tagging FAILED (${KIND}, branch *${BRANCH}*, ${ACTOR}): <${RUN_URL}|View Run>"
response=$(curl -sS -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" \
-H "Content-type: application/json" \
--data "$(jq -n --arg c '#team-alpha-ci' --arg t "$TEXT" '{channel:$c, text:$t}')")
# Slack returns 200 on errors, so surface a bad channel/token instead of dropping it.
if [ "$(jq -r '.ok // false' <<<"$response")" != "true" ]; then
echo "Failed to post to Slack: $(jq -r '.error // empty' <<<"$response")" >&2
fi