From cc9c13e0090ea13f3e13cb7fc522b043f95ed3f2 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Wed, 22 Jan 2025 12:22:30 -0800 Subject: [PATCH] Experiment with a `files-changed.json` per PR (#161788) This is an experiment to determine what the wall time of a (minimal) "upload a JSON file describing files changed". We are looking for this to take (low) single digit minutes, because if we use this file (and expand it to become a build plan), it will block almost _all_ other actions, and will likely get longer as we add more complex logic and checks. Here's hoping! --- .github/workflows/files-changed.yml | 37 +++++++++++++++++ bin/internal/update_engine_version.sh | 32 ++++++++++----- dev/tools/bin/GITHUB_ACTIONS.md | 1 + dev/tools/bin/get_files_changed.dart | 57 +++++++++++++++++++++++++++ 4 files changed, 118 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/files-changed.yml create mode 100644 dev/tools/bin/GITHUB_ACTIONS.md create mode 100644 dev/tools/bin/get_files_changed.dart diff --git a/.github/workflows/files-changed.yml b/.github/workflows/files-changed.yml new file mode 100644 index 00000000000..73e68ebb59d --- /dev/null +++ b/.github/workflows/files-changed.yml @@ -0,0 +1,37 @@ +name: Generate Changed Files JSON + +on: + pull_request: + types: + - opened + - synchronize + +jobs: + generate-json: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Fetch base commit and origin/master + # Fetch what to compare the commit against + run: | + git fetch --no-tags --prune --depth=1 origin ${{ github.event.pull_request.base.sha }} + git fetch --no-tags --prune --depth=1 origin master + echo "FLUTTER_ENGINE_VERSION=${{ github.event.pull_request.base.sha }}" >> "$GITHUB_ENV" + + - name: Initialize Dart SDK + # This downloads the version of the Dart SDK for the current platform. + run: | + ./bin/dart --version + cd dev/tools && ../../bin/dart pub get + + - name: Write changed files to a JSON file + run: | + ./bin/dart run dev/tools/bin/get_files_changed.dart --since="${{ github.event.pull_request.base.sha }}" > changed_files.json + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: changed-files + path: changed_files.json diff --git a/bin/internal/update_engine_version.sh b/bin/internal/update_engine_version.sh index db05771c287..67f748000be 100755 --- a/bin/internal/update_engine_version.sh +++ b/bin/internal/update_engine_version.sh @@ -14,10 +14,24 @@ set -e +# Allow overriding the intended engine version via FLUTTER_ENGINE_VERSION. +# +# This is for systems, such as Github Actions, where we know ahead of time the +# base-ref we want to use (to download the engine binaries and avoid trying +# to compute one below). +# +# This environment variable is EXPERIMENTAL. If you are not on the Flutter infra +# team, this code path might be removed at anytime and cease functioning. Please +# file an issue if you have workflow needs. +if [ -n "${FLUTTER_ENGINE_VERSION}" ]; then + ENGINE_VERSION="${FLUTTER_ENGINE_VERSION}" + echo "[Unstable] Override: Setting engine SHA to $ENGINE_VERSION" 1>&2 +fi + FLUTTER_ROOT="$(dirname "$(dirname "$(dirname "${BASH_SOURCE[0]}")")")" -# Test for fusion repository -if [ -f "$FLUTTER_ROOT/DEPS" ] && [ -f "$FLUTTER_ROOT/engine/src/.gn" ]; then +# Test for fusion repository and no environment variable override. +if [ -z "$ENGINE_VERSION" ] && [ -f "$FLUTTER_ROOT/DEPS" ] && [ -f "$FLUTTER_ROOT/engine/src/.gn" ]; then BRANCH=$(git -C "$FLUTTER_ROOT" rev-parse --abbrev-ref HEAD) # In a fusion repository; the engine.version comes from the git hashes. if [ -z "${LUCI_CONTEXT}" ]; then @@ -35,14 +49,14 @@ if [ -f "$FLUTTER_ROOT/DEPS" ] && [ -f "$FLUTTER_ROOT/engine/src/.gn" ]; then else ENGINE_VERSION=$(git -C "$FLUTTER_ROOT" rev-parse HEAD) fi +fi - if [[ "$BRANCH" != "stable" && "$BRANCH" != "beta" ]]; then - # Write the engine version out so downstream tools know what to look for. - echo $ENGINE_VERSION > "$FLUTTER_ROOT/bin/internal/engine.version" +if [[ "$BRANCH" != "stable" && "$BRANCH" != "beta" ]]; then + # Write the engine version out so downstream tools know what to look for. + echo $ENGINE_VERSION > "$FLUTTER_ROOT/bin/internal/engine.version" - # The realm on CI is passed in. - if [ -n "${FLUTTER_REALM}" ]; then - echo $FLUTTER_REALM > "$FLUTTER_ROOT/bin/internal/engine.realm" - fi + # The realm on CI is passed in. + if [ -n "${FLUTTER_REALM}" ]; then + echo $FLUTTER_REALM > "$FLUTTER_ROOT/bin/internal/engine.realm" fi fi diff --git a/dev/tools/bin/GITHUB_ACTIONS.md b/dev/tools/bin/GITHUB_ACTIONS.md new file mode 100644 index 00000000000..d20346f9858 --- /dev/null +++ b/dev/tools/bin/GITHUB_ACTIONS.md @@ -0,0 +1 @@ +This is a stub-file that can be deleted. diff --git a/dev/tools/bin/get_files_changed.dart b/dev/tools/bin/get_files_changed.dart new file mode 100644 index 00000000000..1a3095f5556 --- /dev/null +++ b/dev/tools/bin/get_files_changed.dart @@ -0,0 +1,57 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:convert'; +import 'dart:io' as io; + +import 'package:args/args.dart'; + +final ArgParser _argParser = + ArgParser() + ..addOption( + 'since', + help: 'What previous SHA to compare the current git state to.', + defaultsTo: 'HEAD^', + ) + ..addOption( + 'output', + help: 'What format to output in.', + defaultsTo: io.stdout.hasTerminal ? 'text' : 'json', + allowed: ['text', 'json'], + ); + +void main(List args) async { + final ArgResults argResults = _argParser.parse(args); + + // Get a list of files changed between this commit and the base SHA. + final List filesChanged; + { + final List args = [ + 'diff', + '--name-only', + '--full-index', + argResults.option('since')!, + ]; + final io.ProcessResult git = await io.Process.run('git', args); + if (git.exitCode != 0) { + io.stderr.writeln('$args failed (exit code: ${git.exitCode}):'); + io.stderr.writeln(git.stdout); + io.stderr.writeln(git.stderr); + io.exitCode = 1; + return; + } + + final String stdout = git.stdout as String; + filesChanged = const LineSplitter().convert(stdout); + } + + // Output to stdout. + final _Output output = _Output.values.byName(argResults.option('output')!); + io.stdout.writeln(switch (output) { + _Output.text => filesChanged.join('\n'), + _Output.json => jsonEncode(filesChanged), + }); +} + +enum _Output { text, json }