Add release publish recipe
In an effort to match SLSA requirements on release workflows, moving some release logic into a recipe will allow for the logic to be triggered by tool_proxy and run on dart-internal SLSA compliant builders.
Bug: b/265318414
Change-Id: I1b145d5a32a97e4c40eec62c2f849df75b27d937
Reviewed-on: https://flutter-review.googlesource.com/c/recipes/+/38134
Commit-Queue: Jesse Seales <jseales@google.com>
Reviewed-by: Casey Hillers <chillers@google.com>
diff --git a/recipes/release/release_publish.expected/flutter-1.2-candidate.31.2.3-4.5.prebeta.json b/recipes/release/release_publish.expected/flutter-1.2-candidate.31.2.3-4.5.prebeta.json
new file mode 100644
index 0000000..4be9ded
--- /dev/null
+++ b/recipes/release/release_publish.expected/flutter-1.2-candidate.31.2.3-4.5.prebeta.json
@@ -0,0 +1,166 @@
+[
+ {
+ "cmd": [],
+ "name": "checkout release branch"
+ },
+ {
+ "cmd": [],
+ "name": "checkout release branch.Checkout flutter/flutter",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "python3",
+ "-u",
+ "RECIPE_MODULE[depot_tools::git]/resources/git_setup.py",
+ "--path",
+ "[START_DIR]/flutter",
+ "--url",
+ "https://flutter.googlesource.com/mirrors/flutter"
+ ],
+ "name": "checkout release branch.Checkout flutter/flutter.git setup",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "fetch",
+ "origin",
+ "flutter-1.2-candidate.3",
+ "--recurse-submodules",
+ "--progress",
+ "--tags"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "env": {
+ "PATH": "RECIPE_REPO[depot_tools]:<PATH>"
+ },
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.git fetch",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "checkout",
+ "-f",
+ "FETCH_HEAD"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.git checkout",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "rev-parse",
+ "HEAD"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.read revision",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_TEXT@<br/>checked out 'deadbeef'<br/>@@@",
+ "@@@SET_BUILD_PROPERTY@got_revision@\"deadbeef\"@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "clean",
+ "-f",
+ "-d",
+ "-x"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.git clean",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "submodule",
+ "sync"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.submodule sync",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "submodule",
+ "update",
+ "--init",
+ "--recursive"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.submodule update",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "tag release"
+ },
+ {
+ "cmd": [
+ "git tag",
+ "1.2.3-4.5.pre",
+ "deadbeef"
+ ],
+ "name": "tag release.Add tag to release hash",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "push tags to upstream"
+ },
+ {
+ "cmd": [
+ "git push origin",
+ "1.2.3-4.5.pre"
+ ],
+ "name": "push tags to upstream.Push tag to origin",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "publish version"
+ },
+ {
+ "cmd": [
+ "git push origin",
+ "1.2.3-4.5.pre"
+ ],
+ "name": "publish version.Push release to refs/heads/beta",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "name": "$result"
+ }
+]
\ No newline at end of file
diff --git a/recipes/release/release_publish.expected/flutter-1.2-candidate.31.2.3-4.5.prestable.json b/recipes/release/release_publish.expected/flutter-1.2-candidate.31.2.3-4.5.prestable.json
new file mode 100644
index 0000000..e346e42
--- /dev/null
+++ b/recipes/release/release_publish.expected/flutter-1.2-candidate.31.2.3-4.5.prestable.json
@@ -0,0 +1,166 @@
+[
+ {
+ "cmd": [],
+ "name": "checkout release branch"
+ },
+ {
+ "cmd": [],
+ "name": "checkout release branch.Checkout flutter/flutter",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "python3",
+ "-u",
+ "RECIPE_MODULE[depot_tools::git]/resources/git_setup.py",
+ "--path",
+ "[START_DIR]/flutter",
+ "--url",
+ "https://flutter.googlesource.com/mirrors/flutter"
+ ],
+ "name": "checkout release branch.Checkout flutter/flutter.git setup",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "fetch",
+ "origin",
+ "flutter-1.2-candidate.3",
+ "--recurse-submodules",
+ "--progress",
+ "--tags"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "env": {
+ "PATH": "RECIPE_REPO[depot_tools]:<PATH>"
+ },
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.git fetch",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "checkout",
+ "-f",
+ "FETCH_HEAD"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.git checkout",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "rev-parse",
+ "HEAD"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.read revision",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_TEXT@<br/>checked out 'deadbeef'<br/>@@@",
+ "@@@SET_BUILD_PROPERTY@got_revision@\"deadbeef\"@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "clean",
+ "-f",
+ "-d",
+ "-x"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.git clean",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "submodule",
+ "sync"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.submodule sync",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "submodule",
+ "update",
+ "--init",
+ "--recursive"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.submodule update",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "tag release"
+ },
+ {
+ "cmd": [
+ "git tag",
+ "1.2.3-4.5.pre",
+ "deadbeef"
+ ],
+ "name": "tag release.Add tag to release hash",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "push tags to upstream"
+ },
+ {
+ "cmd": [
+ "git push origin",
+ "1.2.3-4.5.pre"
+ ],
+ "name": "push tags to upstream.Push tag to origin",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "publish version"
+ },
+ {
+ "cmd": [
+ "git push origin",
+ "1.2.3-4.5.pre"
+ ],
+ "name": "publish version.Push release to refs/heads/stable",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "name": "$result"
+ }
+]
\ No newline at end of file
diff --git a/recipes/release/release_publish.expected/flutter-1.2-candidate.31.2.3beta.json b/recipes/release/release_publish.expected/flutter-1.2-candidate.31.2.3beta.json
new file mode 100644
index 0000000..c38a81b
--- /dev/null
+++ b/recipes/release/release_publish.expected/flutter-1.2-candidate.31.2.3beta.json
@@ -0,0 +1,166 @@
+[
+ {
+ "cmd": [],
+ "name": "checkout release branch"
+ },
+ {
+ "cmd": [],
+ "name": "checkout release branch.Checkout flutter/flutter",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "python3",
+ "-u",
+ "RECIPE_MODULE[depot_tools::git]/resources/git_setup.py",
+ "--path",
+ "[START_DIR]/flutter",
+ "--url",
+ "https://flutter.googlesource.com/mirrors/flutter"
+ ],
+ "name": "checkout release branch.Checkout flutter/flutter.git setup",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "fetch",
+ "origin",
+ "flutter-1.2-candidate.3",
+ "--recurse-submodules",
+ "--progress",
+ "--tags"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "env": {
+ "PATH": "RECIPE_REPO[depot_tools]:<PATH>"
+ },
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.git fetch",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "checkout",
+ "-f",
+ "FETCH_HEAD"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.git checkout",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "rev-parse",
+ "HEAD"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.read revision",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_TEXT@<br/>checked out 'deadbeef'<br/>@@@",
+ "@@@SET_BUILD_PROPERTY@got_revision@\"deadbeef\"@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "clean",
+ "-f",
+ "-d",
+ "-x"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.git clean",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "submodule",
+ "sync"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.submodule sync",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "submodule",
+ "update",
+ "--init",
+ "--recursive"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.submodule update",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "tag release"
+ },
+ {
+ "cmd": [
+ "git tag",
+ "1.2.3",
+ "deadbeef"
+ ],
+ "name": "tag release.Add tag to release hash",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "push tags to upstream"
+ },
+ {
+ "cmd": [
+ "git push origin",
+ "1.2.3"
+ ],
+ "name": "push tags to upstream.Push tag to origin",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "publish version"
+ },
+ {
+ "cmd": [
+ "git push origin",
+ "1.2.3"
+ ],
+ "name": "publish version.Push release to refs/heads/beta",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "name": "$result"
+ }
+]
\ No newline at end of file
diff --git a/recipes/release/release_publish.expected/flutter-1.2-candidate.31.2.3stable.json b/recipes/release/release_publish.expected/flutter-1.2-candidate.31.2.3stable.json
new file mode 100644
index 0000000..9959fbb
--- /dev/null
+++ b/recipes/release/release_publish.expected/flutter-1.2-candidate.31.2.3stable.json
@@ -0,0 +1,166 @@
+[
+ {
+ "cmd": [],
+ "name": "checkout release branch"
+ },
+ {
+ "cmd": [],
+ "name": "checkout release branch.Checkout flutter/flutter",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "python3",
+ "-u",
+ "RECIPE_MODULE[depot_tools::git]/resources/git_setup.py",
+ "--path",
+ "[START_DIR]/flutter",
+ "--url",
+ "https://flutter.googlesource.com/mirrors/flutter"
+ ],
+ "name": "checkout release branch.Checkout flutter/flutter.git setup",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "fetch",
+ "origin",
+ "flutter-1.2-candidate.3",
+ "--recurse-submodules",
+ "--progress",
+ "--tags"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "env": {
+ "PATH": "RECIPE_REPO[depot_tools]:<PATH>"
+ },
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.git fetch",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "checkout",
+ "-f",
+ "FETCH_HEAD"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.git checkout",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "rev-parse",
+ "HEAD"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.read revision",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_TEXT@<br/>checked out 'deadbeef'<br/>@@@",
+ "@@@SET_BUILD_PROPERTY@got_revision@\"deadbeef\"@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "clean",
+ "-f",
+ "-d",
+ "-x"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.git clean",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "submodule",
+ "sync"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.submodule sync",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "git",
+ "submodule",
+ "update",
+ "--init",
+ "--recursive"
+ ],
+ "cwd": "[START_DIR]/flutter",
+ "infra_step": true,
+ "name": "checkout release branch.Checkout flutter/flutter.submodule update",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "tag release"
+ },
+ {
+ "cmd": [
+ "git tag",
+ "1.2.3",
+ "deadbeef"
+ ],
+ "name": "tag release.Add tag to release hash",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "push tags to upstream"
+ },
+ {
+ "cmd": [
+ "git push origin",
+ "1.2.3"
+ ],
+ "name": "push tags to upstream.Push tag to origin",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "publish version"
+ },
+ {
+ "cmd": [
+ "git push origin",
+ "1.2.3"
+ ],
+ "name": "publish version.Push release to refs/heads/stable",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "name": "$result"
+ }
+]
\ No newline at end of file
diff --git a/recipes/release/release_publish.py b/recipes/release/release_publish.py
new file mode 100644
index 0000000..2344329
--- /dev/null
+++ b/recipes/release/release_publish.py
@@ -0,0 +1,87 @@
+# Copyright 2016 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.
+
+import re
+
+DEPS = [
+ 'flutter/repo_util',
+ 'recipe_engine/path',
+ 'recipe_engine/platform',
+ 'recipe_engine/properties',
+ 'recipe_engine/runtime',
+ 'recipe_engine/step',
+]
+
+stableTagRegex = r'^(\d+)\.(\d+)\.(\d+)$'
+betaTagRegex = r'^(\d+)\.(\d+)\.(\d+)-(\d+)\.(\d+)\.pre$'
+
+def isValidTag(tag):
+ stable = re.search(stableTagRegex, tag)
+ development = re.search(betaTagRegex, tag)
+ return stable or development
+
+"""
+This recipe executes the tag and publishing stages of a flutter release.
+To trigger this recipe, tool proxy must be invoked with multi-party approval.
+Tool proxy information can be found at go/tool-proxy.
+Because of this configuration, the recipe is triggered manually during the
+release process.
+
+It is expected that a valid release branch, tag, and release_channel are passed
+to the recipe.
+"""
+def RunSteps(api):
+ branch = api.properties.get('branch')
+ tag = api.properties.get("tag")
+ release_channel = api.properties.get("release_channel")
+ assert branch and tag and release_channel
+
+ checkout_path = api.path['start_dir'].join('flutter')
+ git_url = api.properties.get('git_url') or 'https://flutter.googlesource.com/mirrors/flutter'
+
+ # Validate the given tag is correctly formatted for either stable or latest
+ assert isValidTag(tag)
+
+ # This recipe should only be executed on linux or mac machines to
+ # guard against Windows git issues
+ assert api.platform.is_linux or api.platform.is_mac
+
+ with api.step.nest('checkout release branch'):
+ release_git_hash = api.repo_util.checkout(
+ 'flutter',
+ checkout_path=checkout_path,
+ url=git_url,
+ ref="refs/heads/%s" % branch,
+ )
+
+ with api.step.nest('tag release'):
+ step_args = ['git tag', tag, release_git_hash]
+ api.step('Add tag to release hash', step_args)
+
+ # Guard tag from being pushed on experimental runs
+ if not api.runtime.is_experimental:
+ with api.step.nest('push tags to upstream'):
+ step_args = ['git push origin', tag]
+ api.step('Push tag to origin', step_args)
+
+ with api.step.nest('publish version'):
+ api.step('Push release to refs/heads/%s' % release_channel, step_args)
+
+
+def GenTests(api):
+ for tag in ('1.2.3-4.5.pre', '1.2.3'):
+ for release_channel in ('stable', 'beta'):
+ test = api.test(
+ '%s%s%s' % (
+ 'flutter-1.2-candidate.3',
+ tag,
+ release_channel
+ ), api.platform('mac', 64),
+ api.properties(
+ branch='flutter-1.2-candidate.3',
+ tag=tag,
+ release_channel=release_channel
+ ), api.repo_util.flutter_environment_data()
+ )
+ yield test