| name | flutter-release-pipeline |
| description | Automates the entire Flutter release process. Trigger when the user asks to "cut a release", "run release pipeline", or "bump version and release". |
| agents | ["claude","codex","antigravity"] |
Flutter Release Pipeline
When triggered, execute the following steps strictly in order. If any critical step fails, STOP immediately and report the error.
Safety Rules (CRITICAL)
- NO DELETIONS: Never use rm -rf or delete any file. Ask user first if cleanup is needed.
- CASE SENSITIVITY: Always refer to the docs folder as DOCs/ (capital D, capital C).
- DATA PERSISTENCE: Always APPEND to CSV files. Never overwrite existing data.
- PATH RETENTION: Write all confirmed paths to flutter_release_config.json in the project root. Read from it in every subsequent step. Never ask for the same path twice.
- GITIGNORE PROTECTION: Always ensure flutter_release_config.json is in .gitignore.
- CROSS-PLATFORM: Always detect OS first (Step 0.0) and use correct commands throughout.
- NO EARLY GIT CHECKS: Never run any git write operation before Step 8. git status is only used in Step 8.1 as informational display.
Pipeline Overview
Step 0 - Environment Setup (OS + Flutter check + Config + gitignore + Releases dir)
Step 1 - Run Tests (GATE)
Step 2 - Bump Version
Step 3 - Log Test Results to CSV
Step 4 - Extract Changes and Generate Release Notes
Step 5 - Log Release to CSV
Step 6 - Review and Confirm Release Notes (GATE)
Step 7 - Build
7.1 iOS Archive Preparation (GATE)
7.2 Android Build (AAB / APK / Skip) AFTER
Step 8 - Git Operations (status -> stage -> commit -> tag -> push)
Finish - Completion Summary
Step 0: Environment and Path Verification
0.0 OS Detection (CRITICAL - Run First)
- Detect the operating system.
- Set OS context for all subsequent steps:
- macOS/Linux: use Unix commands (mkdir -p, echo >>, ls, basename $PWD, /tmp/)
- Windows: use PowerShell commands (New-Item -Force, Add-Content, dir, Split-Path -Leaf, $env:TEMP)
- Confirm: "OS Detected: [macOS / Linux / Windows]."
Cross-Platform Command Reference:
| Operation | macOS/Linux | Windows PowerShell |
|---|
| Create directory | mkdir -p | New-Item -ItemType Directory -Force -Path "" |
| Append to file | echo "text" >> file | Add-Content -Path "file" -Value "text" |
| Create new file | echo "text" > file | Set-Content -Path "file" -Value "text" |
| List directory | ls | dir "" |
| Check file exists | test -f | Test-Path "" |
| Check dir exists | test -d | Test-Path -PathType Container "" |
| Get project name | basename $PWD | Split-Path -Leaf (Get-Location) |
| Temp file | /tmp/flutter_test_output.json | $env:TEMP\flutter_test_output.json |
| Home directory | ~/ | $env:USERPROFILE\ |
| Read file | cat | Get-Content "" |
| Path separator | / | \ |
0.1 Flutter Project Check
- Confirm pubspec.yaml exists in the current directory.
- IF MISSING: STOP - "This does not appear to be a Flutter project root. Please navigate to your Flutter project root directory and try again."
0.2 Load or Create Config (flutter_release_config.json)
- Check if flutter_release_config.json exists in the project root.
- IF EXISTS:
- Read and display saved paths.
- Ask: "Found saved config for <project_name>:
docs_root :
releases_dir :
test_results :
releases_csv :
- Use this config
- Re-configure"
- If 1: load paths and skip to Step 0.3.
- If 2: proceed to re-configure below.
- IF MISSING or re-configuring:
a. Check if DOCs/ exists in the project root.
- IF EXISTS: Ask:
"DOCs/ folder found.
- Use existing DOCs/ folder
- Enter a different folder path"
- IF MISSING: Ask:
"DOCs/ folder not found. Please choose:
- Create DOCs/ now (recommended)
- Enter a custom folder path"
- If 1:
macOS/Linux: mkdir -p DOCs/releases
Windows: New-Item -ItemType Directory -Force -Path "DOCs\releases"
Use DOCs/ as docs_root.
- If 2: ask user for path, validate:
macOS/Linux: ls
Windows: dir ""
- Valid: use it.
- Invalid: ask "1. Create it now 2. Enter a different path"
Loop until resolved.
b. Write flutter_release_config.json to project root:
{
"project_name": "<project_name>",
"os": "<macos|linux|windows>",
"docs_root": "ed_path>",
"releases_dir": "ed_path>/releases",
"test_results_csv": "ed_path>/test_results.csv",
"releases_csv": "ed_path>/releases.csv"
}
Note: On Windows use backslash in all paths inside the JSON.
c. Confirm: "Config saved to flutter_release_config.json"
0.3 .gitignore Protection
- Check if .gitignore exists.
- If yes: check if flutter_release_config.json is already listed.
- If not listed:
macOS/Linux: echo "flutter_release_config.json" >> .gitignore
Windows: Add-Content -Path ".gitignore" -Value "flutter_release_config.json"
- If missing:
macOS/Linux: echo "flutter_release_config.json" > .gitignore
Windows: Set-Content -Path ".gitignore" -Value "flutter_release_config.json"
- Confirm: "flutter_release_config.json is protected in .gitignore"
0.4 Releases Sub-directory Check
- Read releases_dir from flutter_release_config.json.
- If the directory does not exist:
macOS/Linux: mkdir -p <releases_dir>
Windows: New-Item -ItemType Directory -Force -Path "<releases_dir>"
- Confirm: "Releases directory verified."
Step 1: Run Tests
- Run:
macOS/Linux: flutter test --reporter json 2>&1 | tee /tmp/flutter_test_output.json
Windows: flutter test --reporter json 2>&1 | Tee-Object -FilePath "$env:TEMP\flutter_test_output.json"
- Parse JSON output to extract:
- All individual test case names
- Total tests run
- Passed count
- Failed count
- Show a clean summary to the user.
GATE - Tests FAILED:
- Do NOT proceed to Step 2.
- Read test_results_csv from config. If missing, create with headers:
Date,Version,Test_cases,Total Tests,Passed,Failed,Status
- Append (current version - not yet bumped):
[Date],[Current Version],[test names separated by ;],[Total],[Passed],[Failed],Failed
- Present recovery options:
"Tests failed. Results logged to test_results.csv.
How would you like to proceed?
- Retry tests
- Analyze errors and suggest fixes
- Analyze errors and fix automatically
- Cancel release (already logged as Failed)"
- Act on user choice. Do NOT continue pipeline unless a retry fully passes.
GATE - Tests PASSED:
- Confirm: "All tests passed. Proceeding to version bump."
- Do NOT log to CSV yet - bumped version needed first (see Step 3).
Step 2: Bump Version
- Read the version: line from pubspec.yaml (e.g., version: 1.0.4+5).
- Increment patch version and build number (e.g., 1.0.4+5 to 1.0.5+6).
- Write the updated version back to pubspec.yaml.
- Store OLD_VERSION for potential revert use in Steps 6 and 7.
- Confirm: "Version bumped: 1.0.4+5 to 1.0.5+6"
Step 3: Log Test Results to CSV
New version is now available - safe to log now.
- Read test_results_csv from config. If missing, create with headers:
Date,Version,Test_cases,Total Tests,Passed,Failed,Status
- Append:
[Date],[New Version],[test names separated by ;],[Total],[Passed],[Failed],Passed
- Confirm: "Test results logged to test_results.csv"
Step 4: Extract Changes and Generate Release Notes
-
Run:
macOS/Linux: git log $(git describe --tags --abbrev=0 2>/dev/null || git rev-list --max-parents=0 HEAD)..HEAD --pretty=format:"- %s"
Windows: git log --pretty=format:"- %s" $(git describe --tags --abbrev=0)
-
Read releases_dir from config.
-
Create file: <releases_dir>/release_notes_<version_with_underscores>.md
Example: DOCs/releases/release_notes_1_0_5.md
-
Write the following content:
Release Notes - v[NEW_VERSION]
Date: [Current Date]
Build: [Build Number]
Platform: [OS]
Changes
[formatted commit list]
-
Confirm: "Release notes draft created: "
Step 5: Log Release to CSV
- Read releases_csv from config. If missing, create with headers:
Date,Version,Release Notes File Path,Changes
- Append:
[Date],[New Version],<releases_dir>/release_notes_X_X_X.md,"[changes as single line; semicolon separated]"
- Confirm: "Release logged to releases.csv"
Step 6: Review and Confirm Release Notes (CRITICAL GATE)
This step MUST happen before any build or git operation.
-
Read and display the full contents of the generated release notes file to the user.
-
Show:
"Release Notes for v[NEW_VERSION]:
[Full contents of release_notes_X_X_X.md]
How would you like to proceed?
- Looks good - proceed to build
- Edit release notes - I will provide new content
- Regenerate from git log - re-extract commits
- Cancel release"
-
If user chooses 1: proceed to Step 7.
-
If user chooses 2:
- Ask: "Please provide the updated release notes content."
- Overwrite the release notes file with user input.
- Update the Changes column in releases.csv with new content.
- Show updated notes and ask: "1. Confirm 2. Edit again"
- Loop until user confirms.
-
If user chooses 3:
- Re-run the git log command from Step 4.
- Overwrite release notes file with freshly extracted commits.
- Show new notes and return to top of Step 6.
-
If user chooses 4:
- STOP the entire pipeline.
- Revert pubspec.yaml version back to OLD_VERSION.
- Inform: "Release cancelled. pubspec.yaml reverted to [OLD_VERSION]. CSV logs retained for audit."
- Do NOT delete any CSV logs already written.
Step 7: Build
7.1 iOS Archive Preparation (GATE)
IMPORTANT: This step runs before Android because flutter clean wipes the entire
build/ folder. Running iOS prep first ensures the Android build output is never deleted.
-
Check Requirements:
- Is the OS detected in Step 0.0 macOS?
- Does the ios/ directory exist in the project root?
-
IF NOT macOS OR IF ios/ IS MISSING:
- Log: "Skipping iOS prep: OS is not macOS or ios/ folder not found."
- Skip immediately to Step 7.2.
-
IF macOS AND ios/ EXISTS:
Ask the user:
"iOS Archive Preparation
This will prepare your project for Xcode archiving:
- flutter clean (clears build folder)
- flutter pub get (picks up version bump)
- pod deintegrate (removes old pod linkages)
- pod install (re-syncs pods with Xcode)
How would you like to proceed?
- Run iOS prep - then continue to Android build
- Run iOS prep - open Xcode for archiving - then continue to Android build
- Skip iOS prep - go straight to Android build"
-
If user chooses 1 or 2:
a. Run: flutter clean
Confirm: "flutter clean complete - build/ folder cleared."
b. Run: flutter pub get
Confirm: "flutter pub get complete - version bump picked up."
c. Run: cd ios && pod deintegrate
Confirm: "pod deintegrate complete."
d. Run: pod install
Confirm: "pod install complete - pods synced with Xcode."
e. Run: cd ..
Confirm: "Returned to project root."
f. If user chose 2:
- Run: open ios/Runner.xcworkspace
- Show:
"Xcode is opening with version [NEW_VERSION].
Complete the archive in Xcode:
- Select Any iOS Device as target
- Product -> Archive
- Organizer -> Distribute App
- Upload to App Store Connect or export IPA
Type 'done' when Xcode archiving is complete."
- Wait for user to confirm 'done' before proceeding.
g. Confirm: "iOS prep complete. Proceeding to Android build."
-
If user chooses 3:
- Confirm: "iOS prep skipped. Proceeding to Android build."
- Note: flutter clean was NOT run. Android builds into existing build/ folder.
-
If iOS prep FAILS at any sub-step: STOP. Show full error. Ask:
"iOS prep failed at: [sub-step]. Error: [error output]
- Retry this sub-step
- Skip iOS prep and continue to Android
- Cancel release - revert pubspec.yaml to [OLD_VERSION]"
7.2 Android Build (Runs AFTER iOS prep)
-
Ask:
"Android Build. Choose an option:
- Build App Bundle (AAB) - recommended for Play Store
-> flutter build appbundle --release
- Build APK - for direct distribution
-> flutter build apk --release
- Skip Android build - proceed to git operations"
-
If 1: run flutter build appbundle --release
Output path:
macOS/Linux: build/app/outputs/bundle/release/app-release.aab
Windows: build\app\outputs\bundle\release\app-release.aab
Confirm: "AAB built successfully: <output_path>"
-
If 2: run flutter build apk --release
Output path:
macOS/Linux: build/app/outputs/flutter-apk/app-release.apk
Windows: build\app\outputs\flutter-apk\app-release.apk
Confirm: "APK built successfully: <output_path>"
-
If 3: skip and proceed to Step 8.
-
If build FAILS: STOP. Show full error output. Ask:
"Android build failed.
- Retry build
- Cancel release - revert pubspec.yaml to [OLD_VERSION]"
Step 8: Git Operations
This is the ONLY step where any git write operation happens.
No git commits, tags, or pushes occur before this step.
8.1 Show Git Status (Informational Only)
- Run: git status --short
- Display all changed files to the user:
"The following files will be committed:
[list of all changed files]"
- This is informational only. Proceed immediately to 8.2.
8.2 Stage Files
- Read docs_root from config.
- Stage all release-related files:
git add pubspec.yaml <docs_root>/ .gitignore flutter_release_config.json
- Confirm: "Files staged successfully."
8.3 Commit, Tag and Push
Ask:
"Ready to commit v[NEW_VERSION]. What would you like to do?
- Commit + Tag only (local)
-> git commit -m 'chore(release): bump version to [NEW_VERSION]'
-> git tag v[NEW_VERSION]
- Commit + Tag + Push (remote)
-> git commit -m 'chore(release): bump version to [NEW_VERSION]'
-> git tag v[NEW_VERSION]
-> git push
-> git push --tags
- Skip - do not commit"
Execute based on user choice.
Confirm: "Git operations complete." or "Git operations skipped."
Completion Summary
Output a formatted summary:
╔══════════════════════════════════════════════════════════════╗
║ 🎉 Flutter Release Pipeline Complete ║
╠══════════════════════════════════════════════════════════════╣
║ Project : <project_name> ║
║ OS : <macOS / Linux / Windows> ║
║ New Version : <new_version> ║
║ iOS Prep : <Completed / Xcode Opened / Skipped> ║
║ Android Build : <AAB path / APK path / Skipped> ║
║ Release Notes : <releases_dir>/release_notes_X_X_X.md ║
║ Releases CSV : <releases_csv path> ║
║ Test Results : <test_results_csv path> ║
║ Git Tag : v<new_version> (pushed / local / skipped) ║
╚══════════════════════════════════════════════════════════════╝