-
Notifications
You must be signed in to change notification settings - Fork 0
220 lines (202 loc) · 9.21 KB
/
Copy pathrelease.yml
File metadata and controls
220 lines (202 loc) · 9.21 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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
name: Build and Release Android APK
# Triggers:
# - push of any tag starting with `v` (e.g. `v2.1.0`) → publishes a release
# - manual dispatch via the Actions tab → publishes with the
# version already in pubspec.yaml (handy for hotfix re-runs)
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
release_notes:
description: "Optional release notes (Markdown). Leave empty to auto-generate from commit history."
required: false
default: ""
permissions:
contents: write
jobs:
build:
name: Build signed release APK
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # changelog needs full history
# ── Toolchain ──────────────────────────────────────────────
- name: Set up Java 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "17"
- name: Set up Flutter (stable)
uses: subosito/flutter-action@v2
with:
channel: stable
cache: true
- name: Verify Flutter install
run: |
flutter --version
flutter doctor -v
# ── Dependencies ──────────────────────────────────────────
- name: Cache Gradle
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('android/**/*.gradle*', 'android/**/gradle-wrapper.properties') }}
restore-keys: gradle-${{ runner.os }}-
- name: Cache pub
uses: actions/cache@v4
with:
path: |
~/.pub-cache
key: pub-${{ runner.os }}-${{ hashFiles('pubspec.lock') }}
restore-keys: pub-${{ runner.os }}-
- name: Install Flutter packages
run: flutter pub get
# ── Versioning ────────────────────────────────────────────
# Tag-driven release: derive version from the pushed tag.
# Manual dispatch: just read whatever is already in pubspec.yaml.
- name: Derive release version
id: version
run: |
if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
VERSION="${GITHUB_REF#refs/tags/v}"
else
VERSION=$(grep '^version:' pubspec.yaml | awk '{print $2}' | cut -d'+' -f1)
fi
if [[ -z "$VERSION" ]]; then
echo "::error::Could not determine version"
exit 1
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "Version: $VERSION"
# ── Signing ───────────────────────────────────────────────
# Detect whether the keystore secret is present. GitHub doesn't
# let us reference `secrets.X` directly inside an `if:` so we
# bounce the boolean through env.
- name: Detect keystore secret
run: |
if [[ -n "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" ]]; then
echo "HAVE_KEYSTORE=true" >> "$GITHUB_ENV"
else
echo "HAVE_KEYSTORE=false" >> "$GITHUB_ENV"
echo "::warning::ANDROID_KEYSTORE_BASE64 secret not set — APK will be signed with the debug key. Installs are NOT upgrade-compatible with previous releases."
fi
# Decode the base64-encoded keystore secret and write key.properties
# so `signingConfigs.release` in android/app/build.gradle.kts picks
# it up automatically. If the keystore secret is missing the build
# falls back to the debug keystore (so forks without secrets still
# produce a runnable APK \u2014 just not an upgrade-compatible one).
- name: Decode signing keystore
if: ${{ env.HAVE_KEYSTORE == 'true' }}
env:
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
run: |
echo "$ANDROID_KEYSTORE_BASE64" | base64 -d > android/app/wolwo-release.keystore
cat > android/key.properties <<EOF
storeFile=app/wolwo-release.keystore
storePassword=$ANDROID_KEYSTORE_PASSWORD
keyAlias=$ANDROID_KEY_ALIAS
keyPassword=$ANDROID_KEY_PASSWORD
EOF
# ── Build ────────────────────────────────────────────────
# Per-architecture split APKs keep download size small for end
# users. We also build a universal APK as a safety net for
# sideloaders who don't know their CPU.
- name: Build signed split APKs
env:
# Key material for sources that need them at compile time
# (Pixabay key is required to call the API). Set these as
# repo / org secrets — leave empty to ship without baked
# keys (users can still paste their own in Settings).
WALLHAVEN_KEY: ${{ secrets.WALLHAVEN_KEY }}
PIXABAY_KEY: ${{ secrets.PIXABAY_KEY }}
NASA_KEY: ${{ secrets.NASA_KEY || 'DEMO_KEY' }}
REDDIT_USER_AGENT: ${{ secrets.REDDIT_USER_AGENT || format('wolwo:v{0} (by /u/anonymous)', steps.version.outputs.version) }}
run: |
flutter build apk --release --split-per-abi \
--dart-define=WALLHAVEN_KEY="$WALLHAVEN_KEY" \
--dart-define=PIXABAY_KEY="$PIXABAY_KEY" \
--dart-define=NASA_KEY="$NASA_KEY" \
--dart-define=REDDIT_USER_AGENT="$REDDIT_USER_AGENT"
flutter build apk --release \
--dart-define=WALLHAVEN_KEY="$WALLHAVEN_KEY" \
--dart-define=PIXABAY_KEY="$PIXABAY_KEY" \
--dart-define=NASA_KEY="$NASA_KEY" \
--dart-define=REDDIT_USER_AGENT="$REDDIT_USER_AGENT"
# ── Rename APKs with the version + ABI ─────────────────
- name: Rename APKs
run: |
OUT=build/app/outputs/flutter-apk
V=${{ steps.version.outputs.version }}
mkdir -p release-apks
for abi in arm64-v8a armeabi-v7a x86_64; do
if [[ -f "$OUT/app-$abi-release.apk" ]]; then
cp "$OUT/app-$abi-release.apk" "release-apks/wolwo-v${V}-${abi}.apk"
fi
done
if [[ -f "$OUT/app-release.apk" ]]; then
cp "$OUT/app-release.apk" "release-apks/wolwo-v${V}-universal.apk"
fi
ls -la release-apks/
# ── Release notes ────────────────────────────────────────
- name: Generate release notes
id: notes
run: |
if [[ -n "${{ github.event.inputs.release_notes }}" ]]; then
echo "${{ github.event.inputs.release_notes }}" > release-notes.md
else
LAST_TAG=$(git describe --tags --abbrev=0 "HEAD^" 2>/dev/null || echo "")
{
echo "## wolwo v${{ steps.version.outputs.version }}"
echo ""
if [[ -n "$LAST_TAG" ]]; then
echo "### Recent changes (last 5 commits since \`$LAST_TAG\`)"
echo ""
git log "${LAST_TAG}..HEAD" --pretty=format:"- %s (%h)" --no-merges -5
else
echo "### Recent commits"
echo ""
git log --pretty=format:"- %s (%h)" --no-merges -5
fi
echo ""
echo ""
echo "### Installation"
echo ""
echo "Pick the APK matching your device's CPU:"
echo "- **arm64-v8a** — almost every modern phone (recommended)"
echo "- **armeabi-v7a** — older 32-bit ARM devices"
echo "- **x86_64** — emulators / Chromebooks"
echo "- **universal** — works everywhere, larger download"
} > release-notes.md
fi
cat release-notes.md
# ── Publish ──────────────────────────────────────────────
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: wolwo-v${{ steps.version.outputs.version }}-apks
path: release-apks/*.apk
if-no-files-found: error
- name: Create / update GitHub Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
V: ${{ steps.version.outputs.version }}
run: |
if gh release view "v$V" >/dev/null 2>&1; then
gh release upload "v$V" release-apks/*.apk --clobber
gh release edit "v$V" --notes-file release-notes.md
else
gh release create "v$V" release-apks/*.apk \
--title "wolwo v$V" \
--notes-file release-notes.md \
--latest
fi