Skip to content

Commit 3773087

Browse files
committed
chore(tool,windows): release from one script and package the installer icon
release.sh resolves the version the same way for pre and stable, bumping the patch when pubspec still names an already tagged one, prints the notes the tag would ship, and pushes only with --push. The two paths differ in more than the tag: a prerelease renders its notes in CI from build --unreleased and writes nothing back, while a stable release needs CHANGELOG.md and changelog.json regenerated and committed before the tag, because render release reads the committed file for a stable tag. The pubspec rewrite has to happen before the preview, since build --unreleased reads pubspec rather than the tag, so an EXIT trap restores it on any exit that is not a completed release. The tag is pushed by name instead of with --follow-tags, which carries annotated tags only while every release tag here is lightweight, so the branch used to land while the tag stayed local and the workflow never fired. The confirmation reads from /dev/tty and re-asks rather than treating an empty answer as No, since rendering the preview takes seconds and a Return pressed while waiting sits in the terminal buffer until the prompt consumes it. The bash that ships with macOS is 3.2, which has neither a fractional read timeout nor a way to flush stdin, so re-asking is the portable fix. The build number is refreshed on every release rather than only when the app version changes: it feeds Android's versionCode, and two builds carrying the same one cannot be told apart once installed. The app version still holds across a cycle, because build --unreleased keys its commit range off it. setup_icon_file loses its leading ..\, since the packager joins that value onto Directory.current before handing it to Inno Setup and the old path landed a level above the repository. The locale entries are copied into the generated .iss verbatim and stay relative to dist/, where that script is written. Changelog: skip
1 parent cb84bba commit 3773087

3 files changed

Lines changed: 232 additions & 3 deletions

File tree

‎.agents/commands.md‎

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,21 @@ Releasing a stable version, in order:
167167
tool/bump_version.sh all
168168
dart run tool/changelog.dart release --version 0.8.96
169169
git commit -am "chore(release): v0.8.96"
170-
git tag v0.8.96 && git push --follow-tags
170+
git tag v0.8.96
171+
git push origin main && git push origin v0.8.96
172+
```
173+
174+
Push the tag by name. Every release tag here is lightweight, and `--follow-tags` carries annotated tags only: it skips a
175+
lightweight one silently, so the branch lands, the tag does not, and the release workflow never fires.
176+
177+
`tool/release.sh` drives both paths so the ordering below cannot be got wrong by hand. It resolves the version (bumping
178+
the patch when pubspec still names an already tagged one), prints the notes the tag would ship, and only pushes with
179+
`--push`:
180+
181+
```bash
182+
tool/release.sh pre --dry-run # plan and notes, changes nothing
183+
tool/release.sh pre --push # bump, tag vX.Y.Z-pre.N, push
184+
tool/release.sh stable --push # changelog, chore(release) commit, tag, push
171185
```
172186

173187
The release commit comes before the tag on purpose: the generated wording is reviewable in the diff before it ships, and
@@ -184,7 +198,9 @@ skipped and moves on instead of reporting drift that does not exist. Checking me
184198
branch fail on an unrelated release.
185199

186200
Prerelease tags (`v0.8.96-pre.N`) skip the release commit, and CI renders their notes with `build --unreleased` for the
187-
Telegram post. They publish no GitHub release, so the update dialog never sees them.
201+
Telegram post. They publish no GitHub release, so the update dialog never sees them. `build --unreleased` reads the
202+
version from `pubspec.yaml` rather than the tag, so the patch has to be bumped before the first `-pre.N` of a cycle:
203+
while `v<pubspec version>` is still tagged it refuses to collect anything and the release job fails.
188204

189205
## Verify
190206

‎tool/release.sh‎

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5+
root="$(cd "$script_dir/.." && pwd)"
6+
cd "$root"
7+
8+
mode=""
9+
want_version=""
10+
do_push=0
11+
assume_yes=0
12+
dry_run=0
13+
14+
usage() {
15+
cat <<'EOF'
16+
Usage: tool/release.sh <pre|stable> [options]
17+
18+
pre Tag the next vX.Y.Z-pre.N prerelease.
19+
stable Write the changelog, commit it, and tag vX.Y.Z.
20+
21+
Options:
22+
--version X.Y.Z Target app version. Defaults to the pubspec version,
23+
bumping the patch when that version is already tagged.
24+
--push Push the branch and the tag once the local steps pass.
25+
--yes Skip the confirmation prompt.
26+
--dry-run Report the plan and exit without changing anything.
27+
-h, --help Show this help.
28+
29+
Examples:
30+
tool/release.sh pre --push # v0.8.97-pre.1, notes rendered by CI
31+
tool/release.sh stable --push # v0.8.97 with a chore(release) commit
32+
EOF
33+
}
34+
35+
die() {
36+
echo "error: $*" >&2
37+
exit 1
38+
}
39+
40+
while (($#)); do
41+
case "$1" in
42+
pre | stable)
43+
[[ -z "$mode" ]] || die "mode given twice: $mode and $1"
44+
mode="$1"
45+
;;
46+
--version)
47+
shift || die "--version needs a value"
48+
want_version="$1"
49+
;;
50+
--version=*) want_version="${1#*=}" ;;
51+
--push) do_push=1 ;;
52+
--yes | -y) assume_yes=1 ;;
53+
--dry-run) dry_run=1 ;;
54+
-h | --help)
55+
usage
56+
exit 0
57+
;;
58+
*)
59+
usage >&2
60+
die "unknown argument: $1"
61+
;;
62+
esac
63+
shift
64+
done
65+
66+
[[ -n "$mode" ]] || {
67+
usage >&2
68+
exit 64
69+
}
70+
71+
if [[ -n "$want_version" && ! "$want_version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
72+
die "--version must look like 0.8.97, got: $want_version"
73+
fi
74+
75+
pubspec_version() {
76+
sed -n 's/^version: \([0-9]*\.[0-9]*\.[0-9]*\).*/\1/p' pubspec.yaml
77+
}
78+
79+
if ! git diff --quiet || ! git diff --cached --quiet; then
80+
die "working tree has uncommitted changes; commit or stash them first"
81+
fi
82+
83+
branch="$(git rev-parse --abbrev-ref HEAD)"
84+
[[ "$branch" != "HEAD" ]] || die "detached HEAD; check out a branch first"
85+
if [[ "$branch" != "main" ]]; then
86+
echo "note: releasing from '$branch', not main. CI triggers on the tag, so"
87+
echo " this publishes '$branch' while main stays behind."
88+
fi
89+
90+
current="$(pubspec_version)"
91+
[[ -n "$current" ]] || die "could not read the version from pubspec.yaml"
92+
93+
bumped=0
94+
if [[ -n "$want_version" ]]; then
95+
version="$want_version"
96+
elif git rev-parse -q --verify "refs/tags/v$current" >/dev/null; then
97+
IFS='.' read -r vmaj vmin vpat <<<"$current"
98+
version="$vmaj.$vmin.$((vpat + 1))"
99+
echo "pubspec is at $current, which is already tagged; targeting $version"
100+
else
101+
version="$current"
102+
fi
103+
104+
git rev-parse -q --verify "refs/tags/v$version" >/dev/null &&
105+
die "v$version is already tagged; pass --version with the next one"
106+
107+
if [[ "$version" != "$current" ]]; then
108+
bumped=1
109+
fi
110+
111+
if [[ "$mode" == "pre" ]]; then
112+
last="$(git tag --list "v$version-pre.*" |
113+
sed -n "s/^v$version-pre\.\([0-9]*\)$/\1/p" | sort -n | tail -1)"
114+
tag="v$version-pre.$(((${last:-0}) + 1))"
115+
else
116+
tag="v$version"
117+
fi
118+
119+
echo
120+
echo "mode : $mode"
121+
echo "branch : $branch"
122+
echo "version : $current -> $version$([[ $bumped == 1 ]] && echo ' (pubspec will be rewritten)')"
123+
echo "tag : $tag"
124+
if [[ "$mode" == "pre" ]]; then
125+
echo "changelog : rendered by CI from build --unreleased; nothing committed"
126+
echo "publishes : build artifacts + Telegram only, no GitHub release"
127+
else
128+
echo "changelog : CHANGELOG.md + changelog.json regenerated and committed"
129+
echo "publishes : GitHub release with artifacts, SHA256SUMS, Homebrew cask"
130+
fi
131+
echo "push : $([[ $do_push == 1 ]] && echo yes || echo 'no (printed at the end)')"
132+
echo
133+
134+
committed=0
135+
restore() {
136+
((committed)) && return 0
137+
git checkout -- pubspec.yaml changelog.json 2>/dev/null || true
138+
}
139+
trap restore EXIT
140+
141+
if ((bumped)); then
142+
sed -i.bak "s/^version: [0-9]*\.[0-9]*\.[0-9]*/version: $version/" pubspec.yaml
143+
rm -f pubspec.yaml.bak
144+
fi
145+
tool/bump_version.sh minor
146+
147+
echo "--- release notes for $tag ---"
148+
if dart run tool/changelog.dart build --unreleased >/dev/null 2>&1; then
149+
dart run tool/changelog.dart render release 2>/dev/null |
150+
sed -n '/changelog:begin/,/changelog:end/p' | sed '1d;$d'
151+
else
152+
echo "(preview unavailable: 'build --unreleased' found nothing to collect)"
153+
fi
154+
git checkout -- changelog.json 2>/dev/null || true
155+
echo "--- end of notes ---"
156+
echo
157+
158+
if ((dry_run)); then
159+
echo "dry run: nothing was changed."
160+
exit 0
161+
fi
162+
163+
if ((assume_yes == 0)); then
164+
if [[ ! -r /dev/tty ]]; then
165+
die "no terminal to confirm on; pass --yes to run unattended"
166+
fi
167+
while true; do
168+
read -r -p "Proceed with $tag? [y/n] " reply </dev/tty ||
169+
die "no answer read; pass --yes to run unattended"
170+
case "$reply" in
171+
[yY] | [yY][eE][sS]) break ;;
172+
[nN] | [nN][oO])
173+
echo "Cancelled. Nothing was changed."
174+
exit 0
175+
;;
176+
*) echo "Please answer y or n." ;;
177+
esac
178+
done
179+
fi
180+
181+
if [[ "$mode" == "stable" ]]; then
182+
dart run tool/changelog.dart release --version "$version"
183+
echo
184+
git --no-pager diff --stat -- CHANGELOG.md changelog.json pubspec.yaml
185+
echo
186+
git add CHANGELOG.md changelog.json pubspec.yaml
187+
git commit -m "chore(release): v$version"
188+
committed=1
189+
dart run tool/changelog.dart verify
190+
elif ! git diff --quiet -- pubspec.yaml; then
191+
git add pubspec.yaml
192+
git commit -m "chore: bump version to $(sed -n 's/^version: //p' pubspec.yaml)"
193+
committed=1
194+
else
195+
committed=1
196+
fi
197+
198+
git tag "$tag"
199+
echo "tagged $tag at $(git rev-parse --short HEAD)"
200+
201+
if ((do_push)); then
202+
git push origin "$branch"
203+
git push origin "$tag"
204+
echo "pushed $branch and $tag"
205+
else
206+
echo
207+
echo "Nothing was pushed. To publish:"
208+
echo " git push origin $branch && git push origin $tag"
209+
fi

‎windows/packaging/exe/make_config.yaml‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ publisher_url: https://github.com/chen08209/FlClash
66
display_name: FlClash
77
executable_name: FlClash.exe
88
output_base_file_name: FlClash.exe
9-
setup_icon_file: ..\windows\runner\resources\app_icon.ico
9+
# Resolved against the project root: flutter_distributor turns this into an
10+
# absolute path via Directory.current.
11+
setup_icon_file: windows\runner\resources\app_icon.ico
1012
locales:
13+
# Written into the .iss verbatim, so this one stays relative to the generated
14+
# script in dist/.
1115
- lang: zh
1216
file: ..\windows\packaging\exe\ChineseSimplified.isl
1317
- lang: en

0 commit comments

Comments
 (0)