forked from homeassistant-ai/ha-mcp
-
Notifications
You must be signed in to change notification settings - Fork 0
174 lines (152 loc) · 6.34 KB
/
Copy pathhotfix-release.yml
File metadata and controls
174 lines (152 loc) · 6.34 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
name: Hotfix Release
# Releases hotfix branches when their PR is merged to master
# Hotfix branches must be based on a stable tag, not master HEAD
on:
pull_request:
types: [closed]
branches: [master, main]
env:
PYTHON_VERSION: "3.13"
jobs:
semantic-release:
name: Semantic Release
# Only run for merged hotfix PRs
if: |
github.event.pull_request.merged == true &&
startsWith(github.event.pull_request.head.ref, 'hotfix/')
runs-on: ubuntu-latest
outputs:
released: ${{ steps.semantic.outputs.released }}
version: ${{ steps.semantic.outputs.version }}
permissions:
contents: write
id-token: write
pull-requests: write
issues: write
steps:
- name: Checkout merged hotfix on master
uses: actions/checkout@v7
with:
# Check out the merge commit so the workspace matches master's history;
# then attach to a local master branch below. python-semantic-release
# matches the active branch against [tool.semantic_release].branch
# in pyproject.toml — a detached HEAD checkout (e.g., of head.sha)
# fails silently with "Detached HEAD state cannot match any release
# groups; no release will be made", which is what broke PR #1090.
ref: ${{ github.event.pull_request.merge_commit_sha }}
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Attach to master branch locally
run: git checkout -B master HEAD
- name: Validate hotfix is based on stable
run: |
# Get the stable tag (moving tag that points to latest stable)
if ! git rev-parse stable &>/dev/null; then
echo "::error::No 'stable' tag found. Cannot validate hotfix base."
exit 1
fi
STABLE_COMMIT=$(git rev-parse stable)
HOTFIX_BASE=$(git merge-base $STABLE_COMMIT HEAD)
# The hotfix should be based on or after the stable tag
if git merge-base --is-ancestor $STABLE_COMMIT HEAD; then
echo "✓ Hotfix is based on stable tag"
else
# Check if stable is ancestor of hotfix base
if git merge-base --is-ancestor $HOTFIX_BASE $STABLE_COMMIT; then
echo "✓ Hotfix is based on a commit at or before stable"
else
echo "::error::Hotfix contains commits from master that are not in stable release"
echo "Hotfix must be branched from the 'stable' tag"
exit 1
fi
fi
- name: Run semantic-release
id: semantic
uses: python-semantic-release/python-semantic-release@v10.5.3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
verbosity: "2"
# Don't create GitHub release here - we'll create a draft below
vcs_release: "false"
- name: Create draft GitHub release
if: steps.semantic.outputs.released == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION="${{ steps.semantic.outputs.version }}"
TAG="v${VERSION}"
# Extract changelog for this version (content between version headers)
awk -v ver="## v${VERSION}" '$0 ~ "^"ver {found=1; next} found && /^## v[0-9]/ {exit} found' CHANGELOG.md > release_notes.md
if [ ! -s release_notes.md ]; then
echo "Hotfix Release v${VERSION}" > release_notes.md
echo "" >> release_notes.md
echo "Critical bug fix - see PR #${{ github.event.pull_request.number }}" >> release_notes.md
fi
# Create draft release (build-binary.yml will add binaries and publish)
gh release create "$TAG" \
--title "🚨 Hotfix $TAG" \
--notes-file release_notes.md \
--draft
echo "✓ Created draft hotfix release $TAG (waiting for binaries)"
- name: Copy changelog to addon directory
if: steps.semantic.outputs.released == 'true'
run: |
set -e
cp CHANGELOG.md homeassistant-addon/CHANGELOG.md
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add homeassistant-addon/CHANGELOG.md
git diff --staged --quiet || git commit -m "chore(addon): sync changelog for Home Assistant add-on [skip ci]"
git push origin HEAD:master
- name: Update stable git tag
if: steps.semantic.outputs.released == 'true'
run: |
VERSION="${{ steps.semantic.outputs.version }}"
echo "Updating 'stable' tag to point to v$VERSION"
git tag -d stable 2>/dev/null || true
git push origin :refs/tags/stable 2>/dev/null || true
git tag stable "v$VERSION"
git push origin stable
echo "✓ 'stable' tag now points to v$VERSION"
- name: Summary
if: steps.semantic.outputs.released == 'true'
run: |
echo "## 🚨 Hotfix Release" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Version:** ${{ steps.semantic.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "**Branch:** ${{ github.event.pull_request.head.ref }}" >> $GITHUB_STEP_SUMMARY
echo "**PR:** #${{ github.event.pull_request.number }}" >> $GITHUB_STEP_SUMMARY
# Build binaries and attach to release
build-and-release:
needs: semantic-release
if: needs.semantic-release.outputs.released == 'true'
uses: ./.github/workflows/_build-and-release.yml
with:
release_tag: v${{ needs.semantic-release.outputs.version }}
is_prerelease: false
permissions:
contents: write
# Build and push addon Docker images
build-addon:
needs: semantic-release
if: needs.semantic-release.outputs.released == 'true'
uses: ./.github/workflows/addon-publish.yml
with:
version: ${{ needs.semantic-release.outputs.version }}
permissions:
contents: read
packages: write
# Update addon config.yaml after images are published
update-addon-config:
needs: [semantic-release, build-addon]
if: needs.semantic-release.outputs.released == 'true'
uses: ./.github/workflows/_update-addon-config.yml
with:
version: ${{ needs.semantic-release.outputs.version }}
commit_message_prefix: 'publish hotfix version'
secrets:
RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
permissions:
contents: write