-
Notifications
You must be signed in to change notification settings - Fork 0
108 lines (97 loc) · 3.88 KB
/
Copy pathrelease.yml
File metadata and controls
108 lines (97 loc) · 3.88 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
name: Release
on:
workflow_run:
workflows: [CI]
types: [completed]
workflow_dispatch:
inputs:
ref:
description: Commit SHA to evaluate and tag if warranted
required: true
type: string
permissions:
contents: write
jobs:
tag-and-release:
# The workflow_run branch is belt-and-suspenders for a natural push to
# main; in practice merges here are performed by auto-merge.yml using
# GITHUB_TOKEN, and GitHub deliberately does not let GITHUB_TOKEN pushes
# trigger further push-triggered workflow runs (it would recurse), so CI
# never reports a push event for a merge commit. auto-merge.yml dispatches
# this workflow explicitly for the same reason it dispatches cd.yml.
if: >-
github.event_name == 'workflow_dispatch' ||
(github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.head_branch == 'main' &&
github.event.workflow_run.event == 'push')
runs-on: ubuntu-latest
env:
RELEASE_SHA: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.event.workflow_run.head_sha }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v7
with:
ref: ${{ env.RELEASE_SHA }}
fetch-depth: 0
- name: Determine the next version from conventional commits
id: version
run: |
set -euo pipefail
last_tag="$(git tag --list 'v*.*.*' --sort=-v:refname | head -n1)"
if [[ -n "$last_tag" ]]; then
range="${last_tag}..${RELEASE_SHA}"
base="${last_tag#v}"
else
range="${RELEASE_SHA}"
base="0.0.0"
fi
if [[ -z "$(git log "$range" --oneline 2>/dev/null)" ]]; then
echo "No commits since ${last_tag:-the start of history}; nothing to release."
echo "bump=none" >> "$GITHUB_OUTPUT"
exit 0
fi
subjects="$(git log "$range" --pretty=%s)"
bodies="$(git log "$range" --pretty=%b)"
# Conventional Commits: a feature earns a minor release, a fix a
# patch, and a declared breaking change (either `type!:` or a
# BREAKING CHANGE footer) always wins regardless of what else is in
# the range. Anything else (docs/ci/build/test/chore) is
# deliberately not release-worthy on its own.
bump=none
if grep -qE '^[a-z]+(\([^)]*\))?!:' <<<"$subjects" || grep -q 'BREAKING CHANGE' <<<"$bodies"; then
bump=major
elif grep -qE '^feat(\([^)]*\))?:' <<<"$subjects"; then
bump=minor
elif grep -qE '^fix(\([^)]*\))?:' <<<"$subjects"; then
bump=patch
fi
if [[ "$bump" == none ]]; then
echo "No feat/fix/breaking change since ${last_tag:-the start of history}; skipping the release."
echo "bump=none" >> "$GITHUB_OUTPUT"
exit 0
fi
IFS=. read -r major minor patch <<<"$base"
case "$bump" in
major) major=$((major + 1)); minor=0; patch=0 ;;
minor) minor=$((minor + 1)); patch=0 ;;
patch) patch=$((patch + 1)) ;;
esac
echo "bump=$bump" >> "$GITHUB_OUTPUT"
echo "version=v${major}.${minor}.${patch}" >> "$GITHUB_OUTPUT"
- name: Tag and publish the release
if: steps.version.outputs.bump != 'none'
env:
VERSION: ${{ steps.version.outputs.version }}
run: |
set -euo pipefail
if git rev-parse "$VERSION" >/dev/null 2>&1; then
echo "$VERSION already exists; skipping."
exit 0
fi
git tag "$VERSION" "$RELEASE_SHA"
git push origin "$VERSION"
gh release create "$VERSION" \
--repo "${{ github.repository }}" \
--title "$VERSION" \
--target "$RELEASE_SHA" \
--generate-notes