[bazel] Create release automation
1. Import the github CLI tool `gh`.
2. Use bazel rules to automate the release process.
A release can be performed via:
```bash
bazel run //release -- RELEASE_TAG_NAME
```
This will build the release artifacts, create a tag within the
repository with `RELEASE_TAG_NAME`, create a release from that tag and
upload the release artifacts to github under that release.
Signed-off-by: Chris Frantz <cfrantz@google.com>
diff --git a/WORKSPACE b/WORKSPACE
index af21688..07b2a31 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -19,6 +19,10 @@
load("//third_party/lowrisc_toolchain:deps.bzl", "lowrisc_toolchain_deps")
lowrisc_toolchain_deps()
+# Tools for release automation
+load("//third_party/github:repos.bzl", "github_tools_repos")
+github_tools_repos()
+
# Go Toolchain
load("//third_party/go:repos.bzl", "go_repos")
go_repos()
diff --git a/release/BUILD b/release/BUILD
index 2d918b3..d24bccf 100644
--- a/release/BUILD
+++ b/release/BUILD
@@ -3,6 +3,7 @@
# SPDX-License-Identifier: Apache-2.0
load("@rules_pkg//pkg:tar.bzl", "pkg_tar")
+load("//third_party/github:rules.bzl", "release")
package(default_visibility = ["//visibility:public"])
@@ -20,3 +21,11 @@
extension = "tar.xz",
tags = ["manual"],
)
+
+release(
+ name = "release",
+ artifacts = {
+ ":opentitan": "Opentitan software and FPGA artifacts",
+ },
+ tags = ["manual"],
+)
diff --git a/rules/exclude_files.bzl b/rules/exclude_files.bzl
index e47443b..4315a84 100644
--- a/rules/exclude_files.bzl
+++ b/rules/exclude_files.bzl
@@ -23,7 +23,7 @@
doc = "Targets producing file outputs",
),
"exclude_suffix": attr.string_list(
- doc = "File suffixes to exlucude from the result",
+ doc = "File suffixes to exclude from the result",
),
},
)
diff --git a/third_party/github/BUILD.bazel b/third_party/github/BUILD.bazel
new file mode 100644
index 0000000..4d86275
--- /dev/null
+++ b/third_party/github/BUILD.bazel
@@ -0,0 +1,8 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+exports_files(
+ glob(["**"]),
+ visibility = ["//visibility:public"],
+)
diff --git a/third_party/github/BUILD.gh.bazel b/third_party/github/BUILD.gh.bazel
new file mode 100644
index 0000000..a7f3504
--- /dev/null
+++ b/third_party/github/BUILD.gh.bazel
@@ -0,0 +1,10 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+package(default_visibility = ["//visibility:public"])
+
+filegroup(
+ name = "gh",
+ srcs = ["bin/gh"],
+)
diff --git a/third_party/github/release.template.bash b/third_party/github/release.template.bash
new file mode 100644
index 0000000..88e5bb7
--- /dev/null
+++ b/third_party/github/release.template.bash
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+ARTIFACTS=(@@ARTIFACTS@@)
+FILES=(@@FILES@@)
+GH=@@GH@@
+REMOTE="@@REMOTE@@"
+@@ENV@@
+
+BRANCH=$(cd "$BUILD_WORKSPACE_DIRECTORY" && git branch --show-current)
+RELEASE_TAG=$(cd "$BUILD_WORKSPACE_DIRECTORY" && git describe --abbrev=0 --tags)
+
+if $(${GH} release list | egrep -q "\s${RELEASE_TAG}\s"); then
+ echo "A release with tag ${RELEASE_TAG} already exists."
+ echo
+ echo "To make a new release, create a new tag first."
+ exit 1
+fi
+
+declare -A DIGEST=()
+for f in "${FILES[@]}"; do
+ b=$(basename ${f})
+ DIGEST[${b}]=$(sha256sum ${f} | cut -f1 -d' ')
+done
+
+export ARTIFACTS BRANCH FILES GH REMOTE RELEASE_TAG DIGEST
+@@SCRIPT@@
+
+${GH} release create --target="${BRANCH}" "$@" "${RELEASE_TAG}" "${ARTIFACTS[@]}"
diff --git a/third_party/github/repos.bzl b/third_party/github/repos.bzl
new file mode 100644
index 0000000..c124408
--- /dev/null
+++ b/third_party/github/repos.bzl
@@ -0,0 +1,14 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+def github_tools_repos():
+ http_archive(
+ name = "com_github_gh",
+ url = "https://github.com/cli/cli/releases/download/v2.13.0/gh_2.13.0_linux_amd64.tar.gz",
+ sha256 = "9e833e02428cd49e0af73bc7dc4cafa329fe3ecba1bfe92f0859bf5b11916401",
+ build_file = Label("//third_party/github:BUILD.gh.bazel"),
+ strip_prefix = "gh_2.13.0_linux_amd64",
+ )
diff --git a/third_party/github/rules.bzl b/third_party/github/rules.bzl
new file mode 100644
index 0000000..ede6eca
--- /dev/null
+++ b/third_party/github/rules.bzl
@@ -0,0 +1,65 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+def _release_impl(ctx):
+ artifacts = []
+ runfiles = []
+ for k, v in ctx.attr.artifacts.items():
+ files = k[DefaultInfo].files.to_list()
+ if len(files) > 1:
+ fail("Artifacts must produce a single file")
+ runfiles.extend(files)
+ artifacts.append("'{}#{}'".format(files[0].short_path, v))
+
+ env = "\n".join(["export {}=\"{}\"".format(k, v) for k, v in ctx.attr.env.items()])
+ runner = ctx.actions.declare_file(ctx.label.name + ".bash")
+ ctx.actions.expand_template(
+ template = ctx.file._runner,
+ output = runner,
+ is_executable = True,
+ substitutions = {
+ "@@ARTIFACTS@@": " ".join(artifacts),
+ "@@ENV@@": env,
+ "@@FILES@@": " ".join([f.short_path for f in runfiles]),
+ "@@REMOTE@@": ctx.attr.remote,
+ "@@SCRIPT@@": ctx.attr.script,
+ "@@GH@@": ctx.executable._gh.path,
+ },
+ )
+
+ return DefaultInfo(
+ files = depset([runner]),
+ runfiles = ctx.runfiles(files = [ctx.executable._gh] + runfiles),
+ executable = runner,
+ )
+
+release = rule(
+ implementation = _release_impl,
+ attrs = {
+ "artifacts": attr.label_keyed_string_dict(
+ doc = "Mapping of release artifacts to their text descriptions",
+ allow_files = True,
+ ),
+ "remote": attr.string(
+ default = "origin",
+ doc = "The remote to push the release tag to",
+ ),
+ "script": attr.string(
+ doc = "Script operation to perform before the github release operation",
+ ),
+ "env": attr.string_dict(
+ doc = "Additional environment variables for the script",
+ ),
+ "_gh": attr.label(
+ default = "@com_github_gh//:gh",
+ cfg = "exec",
+ executable = True,
+ ),
+ "_runner": attr.label(
+ default = "//third_party/github:release.template.bash",
+ allow_single_file = True,
+ ),
+ },
+ executable = True,
+)