Prepare Release #9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Prepare Release | |
on: | |
workflow_dispatch: | |
inputs: | |
bump: | |
type: choice | |
description: "Version bump type" | |
required: true | |
options: | |
- patch | |
- minor | |
- major | |
preid: | |
description: "(Optional) prerelease identifier (e.g. alpha, beta, rc)" | |
required: false | |
dry_run: | |
type: boolean | |
description: "Dry run (do not push/PR)" | |
default: false | |
required: true | |
force_update_existing: | |
type: boolean | |
description: "If release branch already exists, force update it" | |
default: false | |
required: false | |
permissions: | |
contents: write | |
pull-requests: write | |
jobs: | |
prepare: | |
runs-on: ubuntu-latest | |
steps: | |
- name: Checkout dev | |
uses: actions/checkout@v4 | |
with: | |
ref: dev | |
fetch-depth: 0 | |
- name: Set up Git user | |
run: | | |
git config user.name "github-actions[bot]" | |
git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
- name: Read current version | |
id: current | |
run: | | |
CURR=$(grep '^version:' pubspec.yaml | head -1 | awk '{print $2}') | |
echo "current=$CURR" >> $GITHUB_OUTPUT | |
- name: Compute next version | |
id: next | |
run: | | |
set -e | |
bump='${{ github.event.inputs.bump }}' | |
curr='${{ steps.current.outputs.current }}' | |
pre='${{ github.event.inputs.preid }}' | |
base=${curr%%-*} # strip prerelease if any | |
IFS='.' read -r MA MI PA <<< "$base" | |
case "$bump" in | |
patch) PA=$((PA+1));; | |
minor) MI=$((MI+1)); PA=0;; | |
major) MA=$((MA+1)); MI=0; PA=0;; | |
esac | |
next="$MA.$MI.$PA" | |
if [ -n "$pre" ]; then | |
# If current already has same pre id, increment numeric suffix | |
if [[ $curr == *"$pre"* ]]; then | |
# Extract trailing digits | |
suffix=$(echo "$curr" | sed -n "s/.*$pre\.\([0-9]\+\)$/\1/p") | |
if [ -n "$suffix" ]; then | |
next="$MA.$MI.$PA-$pre.$((suffix+1))" | |
else | |
next="$MA.$MI.$PA-$pre.1" | |
fi | |
else | |
next="$MA.$MI.$PA-$pre.1" | |
fi | |
fi | |
echo "value=$next" >> $GITHUB_OUTPUT | |
echo "Next version: $next" | |
- name: Update pubspec.yaml version | |
run: | | |
next='${{ steps.next.outputs.value }}' | |
sed -i "s/^version: .*/version: $next/" pubspec.yaml | |
echo "Updated pubspec.yaml to $next" | |
- name: Update CHANGELOG.md (prepend Unreleased section) | |
run: | | |
next='${{ steps.next.outputs.value }}' | |
date=$(date +%Y-%m-%d) | |
if [ ! -f CHANGELOG.md ]; then | |
echo "# Changelog" > CHANGELOG.md | |
echo >> CHANGELOG.md | |
fi | |
# Ensure Changelog header exists | |
if ! grep -q '^# Changelog' CHANGELOG.md; then | |
{ echo '# Changelog'; echo; cat CHANGELOG.md; } > /tmp/_ch && mv /tmp/_ch CHANGELOG.md | |
fi | |
# Ensure Unreleased section exists | |
if ! grep -q '^## \[Unreleased\]' CHANGELOG.md; then | |
{ echo '## [Unreleased]'; echo; cat CHANGELOG.md; } > /tmp/_unrel && mv /tmp/_unrel CHANGELOG.md | |
fi | |
# Update or add the release section | |
if ! grep -q "^## \[$next\]" CHANGELOG.md; then | |
awk -v ver="$next" -v d="$date" 'BEGIN{added=0} { | |
if(!added && /^## \[Unreleased\]/){ | |
print $0; print ""; print "## [" ver "] - " d; print ""; print "- (placeholder) Describe changes here"; print ""; added=1; next | |
} | |
} END{ if(!added){ print "## [" ver "] - " d; print ""; print "- (placeholder) Describe changes here"; print "" } }' CHANGELOG.md > /tmp/_new && mv /tmp/_new CHANGELOG.md | |
fi | |
echo "Updated CHANGELOG.md" | |
- name: Show diff | |
run: git --no-pager diff --name-only && git --no-pager diff | head -200 | |
- name: Commit changes | |
if: ${{ github.event.inputs.dry_run == 'false' }} | |
run: | | |
next='${{ steps.next.outputs.value }}' | |
git add pubspec.yaml CHANGELOG.md | |
if git diff --cached --quiet; then | |
echo "No changes to commit (version already set?)" | |
else | |
git commit -m "chore(release): v$next\n\nPrepare release from dev" | |
fi | |
- name: Push dev (ensure version bump recorded) | |
if: ${{ github.event.inputs.dry_run == 'false' }} | |
run: | | |
# Push dev so that origin/dev always reflects latest version bump | |
git push origin dev | |
- name: Push release branch (safe) | |
if: ${{ github.event.inputs.dry_run == 'false' }} | |
id: push | |
run: | | |
set -e | |
next='${{ steps.next.outputs.value }}' | |
BRANCH="release/v$next" | |
FORCE='${{ github.event.inputs.force_update_existing }}' | |
git fetch origin "$BRANCH" || true | |
if git rev-parse -q --verify "origin/$BRANCH" >/dev/null; then | |
echo "Remote branch exists: $BRANCH" | |
if [ "$FORCE" = "true" ]; then | |
echo "Force updating remote branch $BRANCH" | |
git push origin HEAD:$BRANCH --force | |
else | |
# Check divergence | |
LOCAL=$(git rev-parse HEAD) | |
REMOTE=$(git rev-parse "origin/$BRANCH") | |
if [ "$LOCAL" = "$REMOTE" ]; then | |
echo "Remote branch already up-to-date." | |
else | |
echo "Branch diverged. (Set force_update_existing=true to overwrite)" | |
echo "branch=$BRANCH" >> $GITHUB_OUTPUT | |
exit 0 | |
fi | |
fi | |
else | |
echo "Creating new remote branch $BRANCH" | |
git push origin HEAD:$BRANCH | |
fi | |
echo "branch=$BRANCH" >> $GITHUB_OUTPUT | |
- name: Determine target branch | |
id: target | |
run: | | |
pre='${{ github.event.inputs.preid }}' | |
if [ -n "$pre" ]; then | |
echo "base=dev" >> $GITHUB_OUTPUT | |
echo "pr_body=自動生成された **プレリリース (Beta)** 準備 PR です。" >> $GITHUB_OUTPUT | |
else | |
echo "base=main" >> $GITHUB_OUTPUT | |
echo "pr_body=自動生成された **正式リリース** 準備 PR です。" >> $GITHUB_OUTPUT | |
fi | |
- name: Create PR | |
if: ${{ github.event.inputs.dry_run == 'false' && steps.push.outputs.branch != '' }} | |
uses: peter-evans/create-pull-request@v6 | |
with: | |
token: ${{ secrets.GITHUB_TOKEN }} | |
branch: ${{ steps.push.outputs.branch }} | |
base: ${{ steps.target.outputs.base }} | |
title: "chore(release): v${{ steps.next.outputs.value }}" | |
body: | | |
${{ steps.target.outputs.pr_body }} | |
- 元ブランチ: dev | |
- 次バージョン: v${{ steps.next.outputs.value }} | |
- CHANGELOG は placeholder を含む場合があります。必要に応じて編集してください。 | |
**【重要】** | |
- **正式リリース (main向け)**: マージ後、`publish-release` ワークフローがタグと GitHub Release を作成します。 | |
- **プレリリース (dev向け)**: マージ後、タグやリリースは作成されません。バージョン番号のみ取り込みます。 | |
labels: release | |
draft: false | |
- name: Dry run note | |
if: ${{ github.event.inputs.dry_run == 'true' }} | |
run: echo "Dry run finished. No push/PR performed." |