Skip to content

Commit ea0fd15

Browse files
authored
Merge pull request #418 from DevKor-github/codexd/apply-release-branch-strategy
[codex] Apply release branch deployment strategy
2 parents e2245b2 + b302896 commit ea0fd15

11 files changed

Lines changed: 228 additions & 23 deletions

.github/workflows/android-play-internal.yml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
name: Android Play Internal Deploy
22

33
on:
4+
push:
5+
branches:
6+
- main
47
workflow_dispatch:
58
inputs:
69
release_notes:
@@ -15,7 +18,7 @@ jobs:
1518
deploy_internal:
1619
name: Build and upload internal testing draft
1720
runs-on: ubuntu-latest
18-
environment: release
21+
environment: staging
1922
env:
2023
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
2124
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
@@ -118,10 +121,11 @@ jobs:
118121
flutter build appbundle --release \
119122
--build-name="$ANDROID_BUILD_NAME" \
120123
--build-number="${{ github.run_number }}" \
124+
--dart-define=ENV=staging \
121125
--dart-define=REST_API_URL="$REST_API_URL"
122126
123127
- name: Prepare Play release notes
124-
if: ${{ inputs.release_notes != '' }}
128+
if: ${{ github.event_name == 'workflow_dispatch' && inputs.release_notes != '' }}
125129
env:
126130
RELEASE_NOTES: ${{ inputs.release_notes }}
127131
run: |
@@ -137,7 +141,7 @@ jobs:
137141
retention-days: 14
138142

139143
- name: Upload internal testing draft with release notes
140-
if: ${{ inputs.release_notes != '' }}
144+
if: ${{ github.event_name == 'workflow_dispatch' && inputs.release_notes != '' }}
141145
uses: r0adkll/upload-google-play@v1
142146
with:
143147
serviceAccountJsonPlainText: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON }}
@@ -148,7 +152,7 @@ jobs:
148152
whatsNewDirectory: distribution/whatsnew
149153

150154
- name: Upload internal testing draft
151-
if: ${{ inputs.release_notes == '' }}
155+
if: ${{ github.event_name != 'workflow_dispatch' || inputs.release_notes == '' }}
152156
uses: r0adkll/upload-google-play@v1
153157
with:
154158
serviceAccountJsonPlainText: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON }}

.github/workflows/android-release-verify.yml

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
name: Android Release Verification
22

33
on:
4+
push:
5+
branches:
6+
- "release/**"
7+
- "hotfix/**"
8+
tags:
9+
- "v*"
410
workflow_dispatch:
511

612
permissions:
@@ -11,7 +17,7 @@ jobs:
1117
runs-on: ubuntu-latest
1218
environment: release
1319
steps:
14-
- uses: actions/checkout@v3
20+
- uses: actions/checkout@v4
1521

1622
- uses: actions/setup-java@v4
1723
with:
@@ -22,6 +28,7 @@ jobs:
2228
with:
2329
flutter-version: "3.32.6"
2430
channel: "stable"
31+
cache: true
2532

2633
- name: Decode Android Firebase config
2734
env:
@@ -37,7 +44,13 @@ jobs:
3744
3845
- run: flutter pub get
3946

40-
- run: dart run build_runner build -d
47+
- run: dart run build_runner build --delete-conflicting-outputs
48+
49+
- name: Analyze
50+
run: flutter analyze
51+
52+
- name: Test
53+
run: flutter test
4154

4255
- name: Derive Android build name
4356
run: |
@@ -49,11 +62,20 @@ jobs:
4962
fi
5063
echo "ANDROID_BUILD_NAME=$build_name" >> "$GITHUB_ENV"
5164
65+
- name: Select app environment
66+
run: |
67+
app_env=staging
68+
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
69+
app_env=prod
70+
fi
71+
echo "APP_ENV=$app_env" >> "$GITHUB_ENV"
72+
5273
- name: Build Android app bundle
5374
env:
5475
REST_API_URL: ${{ vars.REST_API_URL }}
5576
run: |
5677
flutter build appbundle --release \
5778
--build-name="$ANDROID_BUILD_NAME" \
5879
--build-number="${{ github.run_number }}" \
80+
--dart-define=ENV="$APP_ENV" \
5981
--dart-define=REST_API_URL="$REST_API_URL"

.github/workflows/firebase-hosting-merge.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ permissions:
1313
jobs:
1414
build_and_deploy:
1515
runs-on: ubuntu-latest
16-
environment: release
16+
environment: staging
1717
steps:
1818
- uses: actions/checkout@v3
1919
- uses: actions/setup-java@v1
@@ -35,7 +35,10 @@ jobs:
3535
- name: Build Web
3636
env:
3737
REST_API_URL: ${{ vars.REST_API_URL }}
38-
run: flutter build web --release --dart-define=REST_API_URL=$REST_API_URL
38+
run: |
39+
flutter build web --release \
40+
--dart-define=ENV=staging \
41+
--dart-define=REST_API_URL=$REST_API_URL
3942
4043
- uses: FirebaseExtended/action-hosting-deploy@v0
4144
with:

.github/workflows/firebase-hosting-pull-request.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ jobs:
3636
- name: Build Web
3737
env:
3838
REST_API_URL: ${{ vars.REST_API_URL }}
39-
run: flutter build web --release --dart-define=REST_API_URL=$REST_API_URL
39+
run: |
40+
flutter build web --release \
41+
--dart-define=ENV=dev \
42+
--dart-define=REST_API_URL=$REST_API_URL
4043
4144
- uses: FirebaseExtended/action-hosting-deploy@v0
4245
with:

.github/workflows/flutter_test.yml

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,34 @@ name: Flutter Testing
22
on:
33
workflow_dispatch:
44
pull_request:
5-
branches: [main]
5+
branches:
6+
- main
7+
- "release/**"
8+
- "hotfix/**"
9+
push:
10+
branches:
11+
- main
12+
- "release/**"
13+
- "hotfix/**"
614
jobs:
715
test:
816
runs-on: ubuntu-latest
917
steps:
10-
- uses: actions/checkout@v3
18+
- uses: actions/checkout@v4
1119
- uses: subosito/flutter-action@v2
1220
with:
13-
channel: 'stable'
21+
flutter-version: "3.32.6"
22+
channel: stable
23+
cache: true
1424
- name: install sql
1525
run: sudo apt-get install sqlite3 libsqlite3-dev
1626
- name: Install packages
1727
run: flutter pub get
1828
- name: Check Flutter version
1929
run: flutter --version
2030
- name: Run generator
21-
run: flutter pub run build_runner build
31+
run: dart run build_runner build --delete-conflicting-outputs
32+
- name: Analyze
33+
run: flutter analyze
2234
- name: Run test
23-
run: flutter test test
35+
run: flutter test

README.md

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ The app reads compile-time values from Dart defines in `lib/core/constants/envir
8181

8282
| Define | Required | Used for |
8383
| --- | --- | --- |
84+
| `ENV` | Optional | App environment label. Use `dev`, `staging`, or `prod`; defaults to `dev`. |
8485
| `REST_API_URL` | Yes | Base URL for Dio API calls. |
8586
| `REST_AUTH_TOKEN` | Optional | Static auth token override for development/test scenarios. |
8687
| `GOOGLE_RESERVED_CLIENT_ID_IOS` | iOS release/archive only | Reversed iOS Google client ID used as the iOS URL scheme for Google Sign-In. |
@@ -89,16 +90,19 @@ Pass defines directly on Flutter commands:
8990

9091
```sh
9192
flutter run -d chrome \
93+
--dart-define=ENV=dev \
9294
--dart-define=REST_API_URL=<api-base-url>
9395

9496
flutter build web --release \
97+
--dart-define=ENV=staging \
9598
--dart-define=REST_API_URL=<api-base-url>
9699
```
97100

98101
For iOS release and archive builds, include the Google URL scheme define:
99102

100103
```sh
101104
flutter build ios --release \
105+
--dart-define=ENV=prod \
102106
--dart-define=REST_API_URL=<api-base-url> \
103107
--dart-define=GOOGLE_RESERVED_CLIENT_ID_IOS=<reversed-ios-client-id>
104108
```
@@ -165,19 +169,41 @@ flutter test --coverage
165169
Run the web app locally:
166170

167171
```sh
168-
flutter run -d chrome --dart-define=REST_API_URL=<api-base-url>
172+
flutter run -d chrome \
173+
--dart-define=ENV=dev \
174+
--dart-define=REST_API_URL=<api-base-url>
169175
```
170176

171177
Do not use `npm test`; the root `package.json` script is a placeholder that intentionally fails.
172178

173179
## Build and Release
174180

181+
This repository uses trunk-based development with release branches:
182+
183+
```text
184+
main = always test-deployable
185+
release/* = store candidate
186+
v* tag = production release source of truth
187+
hotfix/* = emergency production repair
188+
```
189+
190+
Normal changes should land through short-lived `feature/*` or `fix/*` branches
191+
into `main`. Create `release/x.y.z` from `main` for final store QA, cut
192+
`vX.Y.Z` tags from approved release branches, then merge the release branch back
193+
to `main`. See [docs/Git.md](docs/Git.md) for the full branch and deployment
194+
flow.
195+
175196
### Web
176197

177-
Preview and production web deployments are handled by GitHub Actions and Firebase Hosting. CI uses the `REST_API_URL` GitHub environment variable and builds with:
198+
Preview and staging web deployments are handled by GitHub Actions and Firebase
199+
Hosting. Pull requests build with `ENV=dev`; merges to `main` build with
200+
`ENV=staging`. CI uses the `REST_API_URL` GitHub environment variable and builds
201+
with:
178202

179203
```sh
180-
flutter build web --release --dart-define=REST_API_URL=<api-base-url>
204+
flutter build web --release \
205+
--dart-define=ENV=staging \
206+
--dart-define=REST_API_URL=<api-base-url>
181207
```
182208

183209
Firebase Hosting deploys `build/web` to project `ontime-c63f1`.
@@ -188,13 +214,15 @@ Build a release APK:
188214

189215
```sh
190216
flutter build apk --release \
217+
--dart-define=ENV=staging \
191218
--dart-define=REST_API_URL=<api-base-url>
192219
```
193220

194221
Build an app bundle for Play Console upload:
195222

196223
```sh
197224
flutter build appbundle --release \
225+
--dart-define=ENV=prod \
198226
--dart-define=REST_API_URL=<api-base-url>
199227
```
200228

@@ -206,6 +234,7 @@ Build locally:
206234

207235
```sh
208236
flutter build ios --release \
237+
--dart-define=ENV=prod \
209238
--dart-define=REST_API_URL=<api-base-url> \
210239
--dart-define=GOOGLE_RESERVED_CLIENT_ID_IOS=<reversed-ios-client-id>
211240
```

docs/Android-Release-Configuration.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ The release verification workflow decodes this secret to `android/app/src/releas
1212

1313
Use the `Android Play Internal Deploy` GitHub Actions workflow to build a signed
1414
Android App Bundle and upload it to the Google Play Internal Testing track as a
15-
draft release. The workflow is manual-only and must be dispatched from `main`.
15+
draft release. The workflow runs automatically on pushes to `main` and can also
16+
be dispatched manually from `main`.
1617

17-
Configure a GitHub environment named `release` with required reviewers before
18-
using the workflow. Store these environment secrets there:
18+
Configure a GitHub environment named `staging` for internal test distribution.
19+
Store these environment secrets there:
1920

2021
- `ANDROID_GOOGLE_SERVICES_JSON_B64`: base64-encoded production Android
2122
Firebase config.
@@ -26,10 +27,9 @@ using the workflow. Store these environment secrets there:
2627
- `GOOGLE_PLAY_SERVICE_ACCOUNT_JSON`: raw service-account JSON for the Google
2728
Play Developer API.
2829

29-
Store this environment variable in `release`:
30+
Store this environment variable in `staging`:
3031

31-
- `REST_API_URL`: production API base URL passed to Flutter with
32-
`--dart-define`.
32+
- `REST_API_URL`: target API base URL passed to Flutter with `--dart-define`.
3333

3434
The deploy workflow runs package install, code generation, generated-file drift
3535
checking, analysis, tests, and then `flutter build appbundle --release`. It
@@ -40,6 +40,7 @@ derives Android `versionName` from the `pubspec.yaml` version name and supplies
4040
flutter build appbundle --release \
4141
--build-name=<version name from pubspec.yaml> \
4242
--build-number=${{ github.run_number }} \
43+
--dart-define=ENV=staging \
4344
--dart-define=REST_API_URL="$REST_API_URL"
4445
```
4546

@@ -64,6 +65,7 @@ base64 --decode android-google-services.json.b64 > android/app/src/release/googl
6465
flutter build appbundle --release \
6566
--build-name=<version name from pubspec.yaml> \
6667
--build-number=<monotonic Android versionCode> \
68+
--dart-define=ENV=prod \
6769
--dart-define=REST_API_URL=<api-url>
6870
```
6971

0 commit comments

Comments
 (0)