Repository navigation
193 lines (176 loc) · 8.66 KB
/
Copy pathplugin-dev-release.yml
File metadata and controls
193 lines (176 loc) · 8.66 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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# Releases plugin.json's version from the N.x-dev branch the caller runs on, when it has no tag yet.
#
# Its CHANGELOG.md entry is merged undated or Unreleased (Plugins CI's release date check fails one
# dated by hand). This dates it on automated/release-date-<version>, tags and publishes that commit,
# then opens a pull request bringing the date into the branch and sets it to merge once the branch
# protection's required checks pass, if it lets this token or the approver token do so. Otherwise
# the pull request is left open for a person, with a warning; the release never waits on that merge.
#
# The caller owns the triggers: a weekly schedule, workflow_dispatch, and plugin-branch-sweep.yml to
# dispatch it on the other maintained branch, since a schedule only runs on the default branch.
name: Plugin development release
on:
workflow_call:
inputs:
workflows-ref:
description: "Ref of this repository for the release scripts. This is this repository, so the workflow SHA is the right value when pinning."
required: false
type: string
default: 'main'
reviewer-team:
description: "Slug of the team in the repository's organisation that a release date pull request left waiting on a person requests review from, or mentions without approver-token. Empty picks plugin-reviewers in matomo-org and premium-plugins-reviewers in innocraft."
required: false
type: string
default: ''
skip-ci-check:
description: "Release even when a push CI run on the branch's head failed or is still running. For a run by hand when that failure is not the release's concern; leave it false on the schedule."
required: false
type: boolean
default: false
ci-wait-minutes:
description: "How long to wait, from 0 to 45 minutes, for push CI still running on the branch's head before failing without a release."
required: false
type: number
default: 45
require-approver-token:
description: "Fail before releasing when approver-token is empty, so a secret that was renamed, removed or not passed under secrets: is noticed rather than the release date pull request being left for a person."
required: false
type: boolean
default: false
secrets:
approver-token:
description: "Optional token for a user other than github-actions, which approves and merges the release date pull request where the branch protection needs a review or restricts who can push, and requests the team review on one left waiting on a person. A GitHub App needs organisation Members read access for that."
required: false
permissions: {}
# Queued rather than cancelled, so a dispatch during the scheduled run cannot interrupt a release
# halfway. Named without ${{ github.workflow }}, which resolves to the caller's workflow name here.
concurrency:
group: plugin-dev-release-${{ github.ref_name }}
cancel-in-progress: false
jobs:
release:
name: Release
runs-on: ubuntu-24.04
permissions:
actions: write # approve the held checks on the release date pull request
contents: write # push the release date branch and the tag, publish the release
pull-requests: write # open and merge the release date pull request
# ci-wait-minutes, at most 45, plus the release and any earlier versions it finishes.
timeout-minutes: 90
env:
GITHUB_TOKEN: ${{ github.token }}
GH_TOKEN: ${{ github.token }}
# Unique so it cannot collide with a directory the caller tracks.
WORKFLOWS_DIR: .plugin-ci-workflows-${{ github.run_id }}-${{ github.run_attempt }}
steps:
- name: Check the approver token
if: inputs.require-approver-token
env:
# Whether it is set, never the token, which only the merge step is given.
HAS_APPROVER_TOKEN: ${{ secrets.approver-token != '' }}
shell: bash
run: |
if [[ "$HAS_APPROVER_TOKEN" != true ]]; then
echo "::error::require-approver-token is set but approver-token is empty, so nothing was released. Check that the caller passes it under secrets: and that the secret exists."
exit 1
fi
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Check out plugin-ci-workflows repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: matomo-org/plugin-ci-workflows
ref: ${{ inputs.workflows-ref }}
path: ${{ env.WORKFLOWS_DIR }}
persist-credentials: false
# The guard fails closed without PyYAML; see plugin-ci.yml for why the install is conditional.
- name: Install the YAML parser the guard needs
shell: bash
run: python3 -P -c 'import yaml' || { sudo apt-get update && sudo apt-get install -y --no-install-recommends python3-yaml; }
- name: Check caller concurrency
env:
WORKFLOW_REF: ${{ github.workflow_ref }}
shell: bash
run: |
bash "$WORKFLOWS_DIR/scripts/bash/check_caller_concurrency.sh" "$WORKFLOW_REF" "$GITHUB_WORKSPACE" \
"plugin-ci-workflows/.github/workflows/plugin-dev-release.yml"
- name: Stage release scripts
shell: bash
run: |
set -euo pipefail
mkdir -p "$RUNNER_TEMP/release-scripts"
cp -r "$WORKFLOWS_DIR/scripts/bash" "$WORKFLOWS_DIR/scripts/python" "$RUNNER_TEMP/release-scripts/"
echo "RELEASE_SCRIPTS=$RUNNER_TEMP/release-scripts" >> "$GITHUB_ENV"
# Keep the shared checkout out of the plugin repository before git records the release.
rm -rf "$WORKFLOWS_DIR"
- name: Configure git credentials
shell: bash
run: |
# git asks the helper, which reads the runner-masked token itself, so no value derived from
# the token reaches the environment and needs masking.
{
echo "GIT_CONFIG_COUNT=1"
echo "GIT_CONFIG_KEY_0=credential.https://github.com.helper"
echo "GIT_CONFIG_VALUE_0=!f() { echo username=x-access-token; echo \"password=\$GITHUB_TOKEN\"; }; f"
} >> "$GITHUB_ENV"
- name: Prepare release
id: prepare
env:
RELEASE_SKIP_CI_CHECK: ${{ inputs.skip-ci-check }}
RELEASE_CI_WAIT_MINUTES: ${{ inputs.ci-wait-minutes }}
shell: bash
run: bash "$RELEASE_SCRIPTS/bash/prepare_plugin_dev_release.sh" "$GITHUB_REF"
- name: Date the release
if: steps.prepare.outputs.release_needed == 'true'
env:
TODAY: ${{ steps.prepare.outputs.today }}
shell: bash
run: bash "$RELEASE_SCRIPTS/bash/push_plugin_release_date.sh" "$GITHUB_REF_NAME" "$TODAY"
- name: Create release tag
if: steps.prepare.outputs.release_needed == 'true'
env:
TODAY: ${{ steps.prepare.outputs.today }}
VERSION: ${{ steps.prepare.outputs.version }}
shell: bash
run: bash "$RELEASE_SCRIPTS/bash/tag_plugin_dev_release.sh" "$VERSION" "$TODAY"
- name: Create GitHub release
if: steps.prepare.outputs.publish_needed == 'true'
env:
GITHUB_REPOSITORY: ${{ github.repository }}
FINISH: ${{ steps.prepare.outputs.finish }}
PLUGIN_NAME: ${{ steps.prepare.outputs.plugin_name }}
shell: bash
run: |
set -uo pipefail
# One version failing must not hold back the versions after it.
status=0
for release in $FINISH; do
bash "$RELEASE_SCRIPTS/bash/publish_plugin_release.sh" "$PLUGIN_NAME" "${release%%:*}" "${release#*:}" || status=1
done
exit "$status"
- name: Merge the release date
if: steps.prepare.outputs.publish_needed == 'true'
env:
FINISH: ${{ steps.prepare.outputs.finish }}
RELEASE_APPROVER_TOKEN: ${{ secrets.approver-token }}
RELEASE_REVIEWER_TEAM: ${{ inputs.reviewer-team }}
shell: bash
run: |
set -uo pipefail
# One version failing must not hold back the versions after it.
status=0
for release in $FINISH; do
bash "$RELEASE_SCRIPTS/bash/merge_plugin_release_date_pr.sh" "$GITHUB_REF_NAME" "${release%%:*}" || status=1
done
exit "$status"
# Last, so the versions being finished are not held back with the new one.
- name: Fail when CI held the release back
if: always() && steps.prepare.outputs.ci_held != ''
env:
CI_HELD: ${{ steps.prepare.outputs.ci_held }}
shell: bash
run: |
echo "::error::$CI_HELD"
exit 1