diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index b6f072cc09e..4fbb8269e3c 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -14,17 +14,77 @@ on: permissions: read-all env: - AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: + flutter-prep: + name: ${{ matrix.os }} Flutter Prep + outputs: + latest_flutter_candidate: ${{ steps.flutter-candidate.outputs.FLUTTER_CANDIDATE }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - name: git clone devtools + uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + + - name: Get Latest Flutter Candidate + id: flutter-candidate + run: | + LATEST_FLUTTER_CANDIDATE=$(./tool/latest_flutter_candidate.sh) + echo "FLUTTER_CANDIDATE=$LATEST_FLUTTER_CANDIDATE" >> $GITHUB_OUTPUT + + - name: Load Cached Flutter SDK + id: cache-flutter + uses: actions/cache@v3 + with: + path: | + ./flutter-sdk + key: flutter-sdk-${{ runner.os }}-${{ steps.flutter-candidate.outputs.FLUTTER_CANDIDATE }} + + - if: ${{ steps.cache-flutter.outputs.cache-hit != 'true' }} + name: Clone Flutter SDK if none cached + run: | + git clone https://github.com/flutter/flutter.git ./flutter-sdk + cd flutter-sdk + git checkout $LATEST_FLUTTER_CANDIDATE + env: + LATEST_FLUTTER_CANDIDATE: ${{ steps.flutter-candidate.outputs.FLUTTER_CANDIDATE }} + + - name: Assert that the Latest Flutter Candidate is checked out + run: | + cd flutter-sdk + HEAD_SHA=$(git rev-parse HEAD) + LATEST_FLUTTER_CANDIDATE_SHA=$(git rev-parse "origin/$LATEST_FLUTTER_CANDIDATE") + if [ "$HEAD_SHA" != "$LATEST_FLUTTER_CANDIDATE_SHA" ]; then + echo "::error ,title=Error checking out Latest Flutter Candidate::{expected HEAD to be at $LATEST_FLUTTER_CANDIDATE_SHA but got $HEAD_SHA}" + exit 1 + fi + env: + LATEST_FLUTTER_CANDIDATE: ${{ steps.flutter-candidate.outputs.FLUTTER_CANDIDATE }} + + - name: Setup Flutter SDK + run: | + ./flutter-sdk/bin/flutter config --no-analytics + ./flutter-sdk/bin/flutter doctor + ./flutter-sdk/bin/cache/dart-sdk/bin/dart --disable-analytics + main: name: main + needs: flutter-prep runs-on: ubuntu-latest strategy: fail-fast: false steps: - name: git clone uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + - name: Load Cached Flutter SDK + uses: actions/cache@v3 + with: + path: | + ./flutter-sdk + key: flutter-sdk-${{ runner.os }}-${{ needs.flutter-prep.outputs.latest_flutter_candidate }} + - name: tool/bots.sh env: BOT: main @@ -32,6 +92,7 @@ jobs: test: name: ${{ matrix.bot }} + needs: flutter-prep runs-on: ubuntu-latest strategy: fail-fast: false @@ -44,7 +105,12 @@ jobs: steps: - name: git clone uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 - + - name: Load Cached Flutter SDK + uses: actions/cache@v3 + with: + path: | + ./flutter-sdk + key: flutter-sdk-${{ runner.os }}-${{ needs.flutter-prep.outputs.latest_flutter_candidate }} - name: tool/bots.sh env: BOT: ${{ matrix.bot }} @@ -52,6 +118,7 @@ jobs: run: ./tool/bots.sh macos-test: + needs: flutter-prep name: macos ${{ matrix.bot }} runs-on: macos-latest strategy: @@ -62,7 +129,12 @@ jobs: steps: - name: git clone uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 - + - name: Load Cached Flutter SDK + uses: actions/cache@v3 + with: + path: | + ./flutter-sdk + key: flutter-sdk-${{ runner.os }}-${{ needs.flutter-prep.outputs.latest_flutter_candidate }} - name: tool/bots.sh env: BOT: ${{ matrix.bot }} diff --git a/tool/bots.sh b/tool/bots.sh index d07e5c17478..44da0ac5b5e 100755 --- a/tool/bots.sh +++ b/tool/bots.sh @@ -26,9 +26,11 @@ function flutter { fi } -# Get Flutter. -echo "Cloning the Flutter master branch" -git clone https://github.com/flutter/flutter.git ./flutter-sdk +# Make sure Flutter sdk has been provided +if [ ! -d "./flutter-sdk" ]; then + echo "Expected ./flutter-sdk to exist" + exit 1; +fi # Look in the dart bin dir first, then the flutter one, then the one for the # devtools repo. We don't use the dart script from flutter/bin as that script @@ -39,14 +41,6 @@ export PATH=`pwd`/flutter-sdk/bin/cache/dart-sdk/bin:`pwd`/flutter-sdk/bin:`pwd` # Look up the latest flutter candidate (this is the latest flutter version in g3) # TODO(https://github.com/flutter/devtools/issues/4591): re-write this script as a # shell script so we won't have to incurr the cost of building flutter tool twice. -echo "Looking up the latest Flutter candidate branch" -pushd packages/devtools_app -LATEST_FLUTTER_CANDIDATE=`repo_tool latest-flutter-candidate --githubToken=$AUTH_TOKEN | tail -n 1` -popd - -pushd flutter-sdk -git checkout $LATEST_FLUTTER_CANDIDATE -popd flutter config --no-analytics flutter doctor diff --git a/tool/latest_flutter_candidate.sh b/tool/latest_flutter_candidate.sh new file mode 100755 index 00000000000..e2eb3b9c0ad --- /dev/null +++ b/tool/latest_flutter_candidate.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# Copyright 2022 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. + +RESPONSE=$(gh api --paginate /repos/flutter/flutter/branches) + +CANDIDATES=$(echo "$RESPONSE" | jq '.[].name' | grep candidate) + +VERSIONS=$(echo "$CANDIDATES" | sed -E 's/.*([0-9]+\.[0-9]+-candidate\.[0-9]+).*/\1/' ) + +LATEST_VERSION=$(echo "$VERSIONS" | sort --version-sort | tail -n 1 ) + +if [ -z ${LATEST_VERSION+x} ]; then + echo "Unable to get Latest flutter candidate version" + exit 1 +fi + +LATEST_FLUTTER_CANDIDATE="flutter-$LATEST_VERSION" + +echo $LATEST_FLUTTER_CANDIDATE \ No newline at end of file diff --git a/tool/lib/commands/latest_flutter_candidate.dart b/tool/lib/commands/latest_flutter_candidate.dart deleted file mode 100644 index b878c56b111..00000000000 --- a/tool/lib/commands/latest_flutter_candidate.dart +++ /dev/null @@ -1,121 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:args/command_runner.dart'; -import 'package:devtools_shared/devtools_shared.dart'; -import 'package:http/http.dart' as http; - -const githubToken = 'githubToken'; - -/// Outputs the latest flutter candidate branch name. -/// -/// The latest candidate branch will be the branch that matches the Flutter SDK -/// inside g3. -/// -/// Sample usage: -/// ```shell -/// $dart tool/bin/repo_tool.dart latest-flutter-candidate -/// ``` -class LatestFlutterCandidateCommand extends Command { - LatestFlutterCandidateCommand() { - argParser.addOption( - githubToken, - help: 'Specify the github auth token to be used for API requests.' - ' If unspecified, this may lead to rate limit errors from the' - ' GitHub API.', - defaultsTo: '', - ); - } - - @override - String get name => 'latest-flutter-candidate'; - - @override - String get description => - 'Outputs the most recent flutter release candidate banch'; - - @override - Future run() async { - final authToken = (argResults?[githubToken] ?? '') as String; - - SemanticVersion latest = SemanticVersion(); - String? latestBranchName; - - final allBranchNames = []; - - // TODO(kenz): consider traversing pages properly instead of using a while - // loop. - // See https://docs.github.com/en/rest/guides/traversing-with-pagination - const maxPerPage = 100; - var requestPage = 0; - bool lastPageReceived = false; - while (!lastPageReceived) { - final uri = Uri.https( - 'api.github.com', - '/repos/flutter/flutter/branches', - { - 'per_page': '$maxPerPage', - 'page': '$requestPage', - }, - ); - - final response = await http.get( - uri, - headers: - authToken.isEmpty ? null : {'authorization': 'Bearer $authToken'}, - ); - - if (response.statusCode != HttpStatus.ok) { - print('HttpStatus ${response.statusCode}: ${response.reasonPhrase}'); - return; - } - - final List> branches = - (jsonDecode(response.body) as List).cast>(); - - final branchNames = - branches.map((branch) => branch['name']).cast(); - allBranchNames.addAll(branchNames); - - final candidateBranchesNames = - branchNames.where((name) => name.contains('candidate')); - - for (final branchName in candidateBranchesNames) { - final semVer = semVerFromCandidateBranch(branchName); - if (semVer != null && semVer > latest) { - latest = semVer; - latestBranchName = branchName; - } - } - - requestPage++; - if (branches.length < maxPerPage) { - lastPageReceived = true; - } - } - - if (latestBranchName == null) { - throw Exception( - 'Something went wrong. Could not find the latest candidate branch:' - '${allBranchNames.join('\n')}'); - } else { - print(latestBranchName); - } - } -} - -SemanticVersion? semVerFromCandidateBranch(String branch) { - final candidateBranchPattern = - RegExp(r'^flutter-([0-9]+).([0-9]+)-candidate.([0-9]+)$'); - - final match = candidateBranchPattern.firstMatch(branch); - if (match == null) { - return null; - } - - final x = int.parse(match.group(1)!); - final y = int.parse(match.group(2)!); - final z = int.parse(match.group(3)!); - - return SemanticVersion(major: x, minor: y, patch: z); -} diff --git a/tool/lib/repo_tool.dart b/tool/lib/repo_tool.dart index 7c7150bcbe1..407f733be9b 100644 --- a/tool/lib/repo_tool.dart +++ b/tool/lib/repo_tool.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'package:args/command_runner.dart'; -import 'package:devtools_repo/commands/latest_flutter_candidate.dart'; import 'commands/analyze.dart'; import 'commands/generate_changelog.dart'; @@ -21,6 +20,5 @@ class DevToolsCommandRunner extends CommandRunner { addCommand(PackagesGetCommand()); addCommand(GenerateChangelogCommand()); addCommand(RollbackCommand()); - addCommand(LatestFlutterCandidateCommand()); } } diff --git a/tool/update_flutter_sdk.sh b/tool/update_flutter_sdk.sh index 9df3b2c87b8..7e392112ce0 100755 --- a/tool/update_flutter_sdk.sh +++ b/tool/update_flutter_sdk.sh @@ -17,7 +17,7 @@ TOOL_DIR=`dirname "${RELATIVE_PATH_TO_SCRIPT}"` pushd "$TOOL_DIR" dart pub get -REQUIRED_FLUTTER_BRANCH=`dart bin/repo_tool.dart latest-flutter-candidate | tail -n 1` +REQUIRED_FLUTTER_BRANCH=`./latest_flutter_candidate.sh` echo "REQUIRED_FLUTTER_BRANCH: $REQUIRED_FLUTTER_BRANCH"