-
Notifications
You must be signed in to change notification settings - Fork 0
150 lines (137 loc) · 5.95 KB
/
Copy pathrelease.yml
File metadata and controls
150 lines (137 loc) · 5.95 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
name: Release
# Two ways in, because pushing a tag is not always available:
# - push a version tag, and this publishes the release for it;
# - or run this workflow from the Actions tab with a version, and it
# creates the tag first. The second path is what to use when your
# client cannot push tag refs.
on:
push:
tags:
- "[0-9]+.[0-9]+.[0-9]+"
- "[0-9]+.[0-9]+.[0-9]+[a-z]"
workflow_dispatch:
inputs:
version:
description: 'Version to release, e.g. "0.0.17". Must match manifest.json.'
required: true
type: string
permissions:
contents: write
concurrency:
group: release-${{ inputs.version || github.ref_name }}
cancel-in-progress: false
jobs:
release:
name: Publish ${{ inputs.version || github.ref_name }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
# Full history and tags: --generate-notes needs the previous tag,
# and the step below may need to check an existing one out.
fetch-depth: 0
# Inputs reach the shell through the environment, never through
# ${{ }} interpolation into the script body.
- name: Resolve the version
id: version
env:
EVENT: ${{ github.event_name }}
INPUT_VERSION: ${{ inputs.version }}
REF_NAME: ${{ github.ref_name }}
run: |
set -euo pipefail
if [ "$EVENT" = "workflow_dispatch" ]; then
version="$INPUT_VERSION"
else
version="$REF_NAME"
fi
# Anchored, and matching the two tag patterns above exactly. A shell
# glob will not do this: every * in [0-9]*.[0-9]*.[0-9]* is
# unrestricted, so it accepts 0.0.17rc1 and 0.0.17/evil alike.
if ! printf '%s' "$version" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+[a-z]?$'; then
echo "::error::'$version' is not a version like 0.0.17 or 0.0.17b"
exit 1
fi
echo "version=$version" >> "$GITHUB_OUTPUT"
# A dispatch can land on a tag that already exists: a retried run, or a
# tag someone pushed by hand. `gh release create <tag>` publishes that
# existing tag, so everything below has to be validated against the tag
# rather than against the branch. Otherwise a branch that moved on since
# the tag would have its manifest, tests and notes checked here while
# the release archive carried different code.
- name: Select the commit to release
id: target
if: github.event_name == 'workflow_dispatch'
env:
VERSION: ${{ steps.version.outputs.version }}
run: |
set -euo pipefail
if git ls-remote --exit-code --tags origin "refs/tags/$VERSION" >/dev/null 2>&1; then
echo "tag_exists=true" >> "$GITHUB_OUTPUT"
git fetch --force origin "refs/tags/$VERSION:refs/tags/$VERSION"
git checkout --force --detach "refs/tags/$VERSION"
echo "Tag $VERSION already exists; validating and releasing that tag."
else
echo "tag_exists=false" >> "$GITHUB_OUTPUT"
echo "Tag $VERSION does not exist yet; releasing $GITHUB_REF_NAME at $(git rev-parse --short HEAD)."
fi
# A tag that disagrees with the manifest is what HACS shows users, so
# catch it here rather than after the release exists.
- name: Check the version matches the manifest
env:
VERSION: ${{ steps.version.outputs.version }}
run: |
set -euo pipefail
manifest=$(python3 -c "import json; print(json.load(open('custom_components/cellar_tracker/manifest.json'))['version'])")
if [ "$manifest" != "$VERSION" ]; then
echo "::error::manifest.json says $manifest, but this release is $VERSION. Bump the manifest first."
exit 1
fi
echo "manifest.json and the release agree on $VERSION"
- uses: actions/setup-node@v4
with:
node-version: "22"
- uses: actions/setup-python@v5
with:
python-version: "3.13"
cache: pip
- run: pip install -r requirements_test.txt ruff==0.15.8
# Never tag or publish a commit that does not pass its own checks.
- run: python -m pytest -q
- run: ruff check .
# Only when the tag is not already there; if it was, it is what we just
# validated and it is already what gh will publish.
# Pushing with GITHUB_TOKEN does not start another workflow run, so this
# tag push cannot re-enter the push trigger above.
- name: Create the tag
if: github.event_name == 'workflow_dispatch' && steps.target.outputs.tag_exists != 'true'
env:
VERSION: ${{ steps.version.outputs.version }}
run: |
set -euo pipefail
git -c user.name="github-actions[bot]" \
-c user.email="41898282+github-actions[bot]@users.noreply.github.com" \
tag -a "$VERSION" -m "$VERSION"
git push origin "refs/tags/$VERSION"
# release_notes/<version>.md if it exists, otherwise GitHub's generated
# notes. Hand-written notes matter when a version changes how the
# integration is installed or configured.
- name: Publish the release
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ steps.version.outputs.version }}
run: |
set -euo pipefail
if gh release view "$VERSION" >/dev/null 2>&1; then
echo "::error::Release $VERSION already exists. Delete it first, or pick a new version."
exit 1
fi
notes="release_notes/$VERSION.md"
if [ -f "$notes" ]; then
echo "Using $notes"
gh release create "$VERSION" --title "$VERSION" --notes-file "$notes"
else
echo "No $notes; generating notes from the commit history"
gh release create "$VERSION" --title "$VERSION" --generate-notes
fi
echo "::notice::Published $VERSION"