Skip to content

Flutter Auto Upgrade #16

Flutter Auto Upgrade

Flutter Auto Upgrade #16

name: Flutter Auto Upgrade
on:
schedule:
# Run every Sunday at 2 AM UTC
- cron: '0 2 * * 0'
workflow_dispatch: # Allow manual triggering
jobs:
check-and-upgrade-flutter:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
channel: 'stable'
- name: Get current Flutter version
id: current-version
run: |
# Check if we have a tracked version file
if [ -f ".flutter-version-tracked" ]; then
TRACKED_VERSION=$(cat .flutter-version-tracked)
echo "tracked=$TRACKED_VERSION" >> $GITHUB_OUTPUT
echo "Previously tracked Flutter version: $TRACKED_VERSION"
else
# Get current installed version as fallback
CURRENT_VERSION=$(flutter --version | head -n 1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
echo "tracked=$CURRENT_VERSION" >> $GITHUB_OUTPUT
echo "No tracked version found, using current Flutter version: $CURRENT_VERSION"
fi
# Also get the actual installed version for reference
INSTALLED_VERSION=$(flutter --version | head -n 1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
echo "installed=$INSTALLED_VERSION" >> $GITHUB_OUTPUT
echo "Currently installed Flutter version: $INSTALLED_VERSION"
- name: Check for Flutter upgrades
id: check-upgrade
run: |
# Get the latest stable Flutter version (filter out pre-releases)
LATEST_VERSION=$(curl -s https://api.github.com/repos/flutter/flutter/releases | grep '"tag_name"' | grep -v 'pre' | head -1 | cut -d '"' -f 4)
# Fallback to current installed version if API call fails
if [ -z "$LATEST_VERSION" ]; then
LATEST_VERSION=${{ steps.current-version.outputs.installed }}
echo "Warning: Could not fetch latest version from GitHub, using installed version"
fi
echo "latest=$LATEST_VERSION" >> $GITHUB_OUTPUT
echo "Latest Flutter version: $LATEST_VERSION"
# Compare with tracked version (not current installed version)
TRACKED_VERSION="${{ steps.current-version.outputs.tracked }}"
if [ "$TRACKED_VERSION" != "$LATEST_VERSION" ]; then
echo "upgrade_available=true" >> $GITHUB_OUTPUT
echo "Upgrade available: $TRACKED_VERSION -> $LATEST_VERSION"
else
echo "upgrade_available=false" >> $GITHUB_OUTPUT
echo "Flutter is already up to date (tracked: $TRACKED_VERSION)"
fi
- name: Check for dependency updates
id: check-deps
run: |
echo "Checking for dependency updates..."
# Check dio version
DIO_CURRENT=$(grep "dio:" pubspec.yaml | sed 's/.*: \^//')
echo "Current dio version: $DIO_CURRENT"
DIO_LATEST=$(curl -s https://pub.dev/api/packages/dio | jq -r '.latest.version')
echo "Latest dio version: $DIO_LATEST"
# Check http version
HTTP_CURRENT=$(grep "http:" pubspec.yaml | sed 's/.*: \^//')
echo "Current http version: $HTTP_CURRENT"
HTTP_LATEST=$(curl -s https://pub.dev/api/packages/http | jq -r '.latest.version')
echo "Latest http version: $HTTP_LATEST"
# Set outputs
echo "dio_current=$DIO_CURRENT" >> $GITHUB_OUTPUT
echo "dio_latest=$DIO_LATEST" >> $GITHUB_OUTPUT
echo "http_current=$HTTP_CURRENT" >> $GITHUB_OUTPUT
echo "http_latest=$HTTP_LATEST" >> $GITHUB_OUTPUT
# Check if dependency updates are available
DEPS_AVAILABLE=false
if [ "$DIO_CURRENT" != "$DIO_LATEST" ]; then
echo "Dio update available: $DIO_CURRENT -> $DIO_LATEST"
DEPS_AVAILABLE=true
fi
if [ "$HTTP_CURRENT" != "$HTTP_LATEST" ]; then
echo "HTTP update available: $HTTP_CURRENT -> $HTTP_LATEST"
DEPS_AVAILABLE=true
fi
echo "deps_available=$DEPS_AVAILABLE" >> $GITHUB_OUTPUT
if [ "$DEPS_AVAILABLE" = "true" ]; then
echo "Dependency updates are available"
else
echo "All dependencies are up to date"
fi
- name: Create upgrade branch
if: steps.check-upgrade.outputs.upgrade_available == 'true' || steps.check-deps.outputs.deps_available == 'true'
run: |
git config --local user.email "[email protected]"
git config --local user.name "GitHub Action"
# Create unique branch name with timestamp to avoid conflicts
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
if [ "${{ steps.check-upgrade.outputs.upgrade_available }}" == "true" ]; then
BRANCH_NAME="flutter/auto-upgrade-${{ steps.check-upgrade.outputs.latest }}-$TIMESTAMP"
else
BRANCH_NAME="deps/auto-update-$TIMESTAMP"
fi
# Delete remote branch if it exists (cleanup from previous runs)
git push origin --delete "$BRANCH_NAME" 2>/dev/null || echo "Remote branch doesn't exist, continuing..."
# Create and checkout new branch
git checkout -b "$BRANCH_NAME"
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
- name: Upgrade Flutter
if: steps.check-upgrade.outputs.upgrade_available == 'true'
run: |
echo "Upgrading Flutter to ${{ steps.check-upgrade.outputs.latest }}"
# Try normal upgrade first
if ! flutter upgrade; then
echo "Normal upgrade failed, attempting force upgrade..."
flutter upgrade --force
fi
# Update Flutter version in pubspec.yaml if it exists with version constraints
if [ -f "pubspec.yaml" ] && grep -q "flutter:" "pubspec.yaml"; then
echo "Checking pubspec.yaml for Flutter version constraints..."
# Note: This is a basic approach - you might need more sophisticated version handling
fi
- name: Update dependencies
if: steps.check-deps.outputs.deps_available == 'true'
run: |
echo "Updating dependencies..."
# Update dio if newer version available
if [ "${{ steps.check-deps.outputs.dio_current }}" != "${{ steps.check-deps.outputs.dio_latest }}" ]; then
echo "Updating dio from ${{ steps.check-deps.outputs.dio_current }} to ${{ steps.check-deps.outputs.dio_latest }}"
sed -i.bak "s/dio: \^${{ steps.check-deps.outputs.dio_current }}/dio: ^${{ steps.check-deps.outputs.dio_latest }}/" pubspec.yaml
fi
# Update http if newer version available
if [ "${{ steps.check-deps.outputs.http_current }}" != "${{ steps.check-deps.outputs.http_latest }}" ]; then
echo "Updating http from ${{ steps.check-deps.outputs.http_current }} to ${{ steps.check-deps.outputs.http_latest }}"
sed -i.bak "s/http: \^${{ steps.check-deps.outputs.http_current }}/http: ^${{ steps.check-deps.outputs.http_latest }}/" pubspec.yaml
fi
# Clean up backup files
rm -f pubspec.yaml.bak
- name: Apply automatic fixes
if: steps.check-upgrade.outputs.upgrade_available == 'true' || steps.check-deps.outputs.deps_available == 'true'
run: |
echo "Applying automatic Dart fixes for deprecations and lint issues..."
# First check what fixes are available (dry run)
echo "Checking available fixes:"
dart fix --dry-run || echo "No automatic fixes available or dry-run failed"
# Apply the fixes
echo "Applying fixes:"
dart fix --apply || echo "No fixes applied or apply failed"
- name: Update tracked Flutter version
if: steps.check-upgrade.outputs.upgrade_available == 'true'
run: |
echo "Updating tracked Flutter version to ${{ steps.check-upgrade.outputs.latest }}"
echo "${{ steps.check-upgrade.outputs.latest }}" > .flutter-version-tracked
echo "Tracked version file updated"
- name: Install dependencies and test
if: steps.check-upgrade.outputs.upgrade_available == 'true' || steps.check-deps.outputs.deps_available == 'true'
run: |
flutter pub get
# Run basic checks to ensure upgrade didn't break anything
echo "Running Flutter doctor..."
flutter doctor
echo "Analyzing project..."
flutter analyze
echo "Running tests..."
flutter test || echo "Tests failed - upgrade may need manual review"
- name: Check for changes
if: steps.check-upgrade.outputs.upgrade_available == 'true' || steps.check-deps.outputs.deps_available == 'true'
id: check-changes
run: |
git add .
if git diff --staged --quiet; then
echo "has_changes=false" >> $GITHUB_OUTPUT
echo "No changes detected after Flutter upgrade"
else
echo "has_changes=true" >> $GITHUB_OUTPUT
echo "Changes detected after Flutter upgrade"
fi
- name: Commit changes
if: steps.check-changes.outputs.has_changes == 'true'
run: |
# Create appropriate commit message based on what was updated
if [ "${{ steps.check-upgrade.outputs.upgrade_available }}" == "true" ] && [ "${{ steps.check-deps.outputs.deps_available }}" == "true" ]; then
COMMIT_MSG="chore: upgrade Flutter to ${{ steps.check-upgrade.outputs.latest }} and update dependencies
- Automated Flutter upgrade from ${{ steps.current-version.outputs.tracked }} to ${{ steps.check-upgrade.outputs.latest }}
- Updated dependencies (dio, http)
- Applied automatic fixes with dart fix
- Updated tracked Flutter version
- Verified with flutter analyze and flutter test"
elif [ "${{ steps.check-upgrade.outputs.upgrade_available }}" == "true" ]; then
COMMIT_MSG="chore: upgrade Flutter to ${{ steps.check-upgrade.outputs.latest }}
- Automated Flutter upgrade from ${{ steps.current-version.outputs.tracked }} to ${{ steps.check-upgrade.outputs.latest }}
- Applied automatic fixes with dart fix
- Updated tracked Flutter version
- Verified with flutter analyze and flutter test"
else
COMMIT_MSG="chore: update dependencies
- Updated dependencies (dio: ${{ steps.check-deps.outputs.dio_latest }}, http: ${{ steps.check-deps.outputs.http_latest }})
- Applied automatic fixes with dart fix
- Verified with flutter analyze and flutter test"
fi
git commit -m "$COMMIT_MSG"
- name: Push changes
if: steps.check-changes.outputs.has_changes == 'true'
run: |
# Try normal push first, then force push if it fails
if ! git push origin "$BRANCH_NAME"; then
echo "Normal push failed, attempting force push..."
git push --force origin "$BRANCH_NAME"
fi
- name: Create Pull Request
if: steps.check-changes.outputs.has_changes == 'true'
uses: actions/github-script@v7
with:
script: |
const latestVersion = '${{ steps.check-upgrade.outputs.latest }}';
const trackedVersion = '${{ steps.current-version.outputs.tracked }}';
const { data: pullRequest } = await github.rest.pulls.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `chore: upgrade Flutter to ${latestVersion} and dependencies`,
head: process.env.BRANCH_NAME,
base: 'master', // Change to 'main' if that's your default branch
body: `## Flutter Auto Upgrade
This PR was automatically created to upgrade Flutter from **${trackedVersion}** to **${latestVersion}** and update dependencies.
### Changes Made:
- Upgraded Flutter to the latest stable version
- Updated dependencies with \`flutter pub get\`
- Applied automatic fixes for deprecations with \`dart fix --apply\`
- Used force upgrade fallback if normal upgrade failed
- Verified with \`flutter analyze\`
- Ran \`flutter test\` (check CI results)
### Review Checklist:
- [ ] Verify all tests pass in CI
- [ ] Check for any breaking changes in Flutter release notes
- [ ] Test the app manually if needed
- [ ] Review any dependency conflicts
### Flutter Release Notes:
Check the [Flutter releases page](https://github.com/flutter/flutter/releases/tag/${latestVersion}) for detailed information about this version.
---
*This PR was created automatically by the Flutter Auto Upgrade workflow.*`
});
console.log('Created PR #' + pullRequest.number);
- name: Add labels to PR
if: steps.check-changes.outputs.has_changes == 'true'
continue-on-error: true
uses: actions/github-script@v7
with:
script: |
try {
// Get the PR number from the previous step
const prs = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
head: context.repo.owner + ':' + process.env.BRANCH_NAME,
state: 'open'
});
if (prs.data.length > 0) {
const prNumber = prs.data[0].number;
console.log(`Attempting to add labels to PR #${prNumber}`);
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
labels: ['dependencies', 'flutter', 'automated', 'upgrade']
});
console.log('Successfully added labels to PR');
} else {
console.log('No PR found to add labels to');
}
} catch (error) {
console.log('Failed to add labels to PR (this is non-critical):', error.message);
console.log('The PR was created successfully, labels can be added manually if needed');
}
- name: Summary
run: |
if [ "${{ steps.check-upgrade.outputs.upgrade_available }}" == "true" ]; then
if [ "${{ steps.check-changes.outputs.has_changes }}" == "true" ]; then
echo "Flutter upgrade available, changes detected, and PR created!"
echo "Upgraded from ${{ steps.current-version.outputs.tracked }} to ${{ steps.check-upgrade.outputs.latest }}"
echo "Branch created: $BRANCH_NAME"
else
echo "Flutter upgrade available, but no changes detected"
fi
elif [ "${{ steps.check-deps.outputs.deps_available }}" == "true" ]; then
if [ "${{ steps.check-changes.outputs.has_changes }}" == "true" ]; then
echo "Dependency updates available, changes detected, and PR created!"
echo "Branch created: $BRANCH_NAME"
else
echo "Dependency updates available, but no changes detected"
fi
else
echo "Flutter is already up to date (tracked: ${{ steps.current-version.outputs.tracked }})"
fi