Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions .github/workflows/update_flutter.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Copyright 2026 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

name: Update Flutter SDK Pin

on:
schedule:
- cron: '0 0 * * 1' # Run every Monday at midnight UTC
workflow_dispatch: # Allow manual execution from the Actions tab

permissions:
contents: write
pull-requests: write

jobs:
check-and-update:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4

- name: Check for New Flutter stable version
id: check-version
run: |
# 1. Retrieve the current pinned version from the shared script
CURRENT_VERSION=$(grep -E 'FLUTTER_VERSION="[0-9.]+"' tool/provision_flutter.sh | head -n 1 | cut -d'"' -f2)
echo "Current pinned version: $CURRENT_VERSION"

# 2. Retrieve the latest stable version from Flutter's official releases manifest
LATEST_VERSION=$(curl -s https://storage.googleapis.com/flutter_infra_release/releases/releases_linux.json | jq -r '.releases | map(select(.channel == "stable"))[0].version')
echo "Latest stable version: $LATEST_VERSION"

# 3. Compare and update if a newer version is available
if [ "$CURRENT_VERSION" != "$LATEST_VERSION" ]; then
echo "New Flutter stable version detected: $LATEST_VERSION"
sed -i -e "s/FLUTTER_VERSION=\"$CURRENT_VERSION\"/FLUTTER_VERSION=\"$LATEST_VERSION\"/g" tool/provision_flutter.sh
echo "updated=true" >> $GITHUB_OUTPUT
echo "latest_version=$LATEST_VERSION" >> $GITHUB_OUTPUT
else
echo "Flutter SDK is already up to date."
echo "updated=false" >> $GITHUB_OUTPUT
fi

- name: Create Pull Request for Version Bump
if: steps.check-version.outputs.updated == 'true'
uses: peter-evans/create-pull-request@v6
with:
commit-message: "ci: bump pinned Flutter SDK to version ${{ steps.check-version.outputs.latest_version }}"
title: "ci: bump pinned Flutter SDK to version ${{ steps.check-version.outputs.latest_version }}"
body: |
An automated check has detected a new stable release of the Flutter SDK.

* **New Pinned Version**: `${{ steps.check-version.outputs.latest_version }}`

This Pull Request updates our shared provisioning script (`tool/provision_flutter.sh`) to target this version. All presubmit tests will be run against this version to verify compatibility.
branch: "auto-update-flutter-sdk"
delete-branch: true
labels: |
dependencies
ci
81 changes: 81 additions & 0 deletions testSrc/unit/io/flutter/CIIntegrityTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright 2026 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
package io.flutter;

import org.junit.Test;
import java.io.File;
import java.nio.file.Files;
import java.util.regex.Pattern;
import static org.junit.Assert.assertTrue;

/**
* Integrity tests for the CI/CD automation pipeline.
* <p>
* <b>Why this exists:</b>
* Our CI/CD scripts rely on a shared bash script to provision the Flutter SDK, and a
* scheduled GitHub Actions workflow to automatically check for new Flutter stable releases
* and submit version-bumping Pull Requests.
* <p>
* If a developer modifies the provisioning script (e.g., renaming the constant FLUTTER_VERSION)
* or alters the regex search format without updating the GitHub Actions workflow, the automation
* will fail silently in production.
* <p>
* This class acts as a "meta-test" or "integrity-check" that runs during standard project
* compilations (`./gradlew test`) to give developers an immediate early warning of synchronization
* failures before code is merged.
*/
public class CIIntegrityTest {

/**
* Verifies that the Flutter SDK provisioning script exists at the expected path
* and defines the `FLUTTER_VERSION` constant in the exact semver format required.
* <p>
* If this test fails, it means `tool/provision_flutter.sh` was moved, deleted, or
* the `FLUTTER_VERSION` constant definition was formatted incorrectly (or renamed).
*/
@Test
public void testFlutterProvisioningScriptIntegrity() throws Exception {
// The JVM's Current Working Directory (CWD) during unit tests is the repository root.
File scriptFile = new File("tool/provision_flutter.sh");
assertTrue("provision_flutter.sh must exist at the repository root 'tool/' directory", scriptFile.exists());

String content = Files.readString(scriptFile.toPath());

// Ensure the shell script declares the version constant in a predictable pattern:
// E.g. FLUTTER_VERSION="3.41.0"
Pattern versionPattern = Pattern.compile("FLUTTER_VERSION=\"[0-9.]+\"");
assertTrue(
"provision_flutter.sh must define a constant FLUTTER_VERSION matching the expected format (e.g., FLUTTER_VERSION=\"3.41.0\"). " +
"This constant is critical because the automated GitHub Actions updater searches for this exact pattern to bump the version.",
versionPattern.matcher(content).find()
);
}

/**
* Verifies that the automated GitHub Actions updater workflow is synchronized
* with the provisioning script.
* <p>
* Specifically, it ensures the workflow searches for the exact constant pattern
* `FLUTTER_VERSION="[0-9.]+"` to perform its automated string replacement. If a developer
* renames the constant in the script, they MUST also update the workflow, otherwise this test fails.
*/
@Test
public void testGitHubWorkflowRegexSync() throws Exception {
File workflowFile = new File(".github/workflows/update_flutter.yaml");
assertTrue("update_flutter.yaml workflow must exist in the '.github/workflows/' directory", workflowFile.exists());

String content = Files.readString(workflowFile.toPath());

// The workflow must use the constant name followed by a flexible regex query in single or double quotes.
// E.g., matches 'FLUTTER_VERSION="[0-9.]+"' or 'FLUTTER_VERSION="[0-9.]*"' or "FLUTTER_VERSION='[0-9.]+'"
Pattern regexPattern = Pattern.compile("FLUTTER_VERSION=['\"].+?['\"]");
assertTrue(
"update_flutter.yaml must reference the 'FLUTTER_VERSION' constant with a regex pattern (e.g. 'FLUTTER_VERSION=\"[0-9.]+\"') " +
"in its search-and-replace logic.",
regexPattern.matcher(content).find()
);
}
}
2 changes: 2 additions & 0 deletions tool/provision_flutter.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ set -e
# Provision the pinned Flutter SDK if not present
if [ ! -d "../flutter" ]; then
OS_NAME=$(uname -s | tr '[:upper:]' '[:lower:]')
# Pinned Flutter SDK version. This constant is automatically checked and updated weekly
# by the .github/workflows/update_flutter.yaml GitHub Actions workflow.
FLUTTER_VERSION="3.41.0"

echo "Provisioning Flutter SDK version ${FLUTTER_VERSION} for ${OS_NAME}..."
Expand Down
Loading