From 02a4e0046ef4b8afe80f5b1e8097c984e5a30284 Mon Sep 17 00:00:00 2001 From: Greg Magolan Date: Tue, 10 Sep 2024 12:38:21 -0700 Subject: [PATCH] chore: remove homebrew from release artifacts and switch to monorepo versioning --- .github/workflows/install_snippet.sh | 16 +- .github/workflows/weekly_tag.yaml | 22 ++ ASPECT_COMMUNITY_LICENSE | 116 +++++++++ CONTRIBUTING.md | 51 ---- README.md | 79 ++++-- buildinfo/BUILD.bazel | 2 +- release/BUILD.bazel | 66 +---- release/bazel | 3 - release/brew/BUILD.bazel | 51 ---- release/brew/brew_artifacts.bzl | 256 -------------------- release/brew/brew_bottle.bzl | 109 --------- release/brew/brew_formula.bzl | 19 -- release/brew/brew_platforms.bzl | 52 ---- release/brew/brews.bzl | 32 --- release/brew/generate_formula.sh | 192 --------------- release/brew/tests/BUILD.bazel | 224 ----------------- release/brew/tests/brew_bottle_test.sh | 28 --- release/brew/tests/brew_platforms_tests.bzl | 26 -- release/brew/tests/brews_tests.bzl | 49 ---- release/brew/tests/generate_formula_test.sh | 93 ------- release/cli_brew_artifacts.bzl | 86 ------- release/stage_for_dev.sh | 112 --------- release/verify_homebrew_artifacts.sh | 35 --- release/version.tmpl | 1 - release/version_file.bzl | 22 -- workspace_status.sh | 16 +- 26 files changed, 225 insertions(+), 1533 deletions(-) create mode 100644 .github/workflows/weekly_tag.yaml create mode 100644 ASPECT_COMMUNITY_LICENSE delete mode 100755 release/bazel delete mode 100644 release/brew/BUILD.bazel delete mode 100644 release/brew/brew_artifacts.bzl delete mode 100644 release/brew/brew_bottle.bzl delete mode 100644 release/brew/brew_formula.bzl delete mode 100644 release/brew/brew_platforms.bzl delete mode 100644 release/brew/brews.bzl delete mode 100755 release/brew/generate_formula.sh delete mode 100644 release/brew/tests/BUILD.bazel delete mode 100755 release/brew/tests/brew_bottle_test.sh delete mode 100644 release/brew/tests/brew_platforms_tests.bzl delete mode 100644 release/brew/tests/brews_tests.bzl delete mode 100755 release/brew/tests/generate_formula_test.sh delete mode 100644 release/cli_brew_artifacts.bzl delete mode 100755 release/stage_for_dev.sh delete mode 100755 release/verify_homebrew_artifacts.sh delete mode 100644 release/version.tmpl delete mode 100644 release/version_file.bzl diff --git a/.github/workflows/install_snippet.sh b/.github/workflows/install_snippet.sh index d3a312292..e1a3b69d2 100755 --- a/.github/workflows/install_snippet.sh +++ b/.github/workflows/install_snippet.sh @@ -7,27 +7,23 @@ set -o errexit -o nounset -o pipefail TAG=${GITHUB_REF_NAME} cat < [!NOTE] +> This approach doesn't provide the \`aspect init\` command, which has to run outside a Bazel workspace. + The underlying version of Bazel can be configured in your \`.bazelversion\` file or the \`BAZEL_VERSION\` environment variable. EOF diff --git a/.github/workflows/weekly_tag.yaml b/.github/workflows/weekly_tag.yaml new file mode 100644 index 000000000..986e70a00 --- /dev/null +++ b/.github/workflows/weekly_tag.yaml @@ -0,0 +1,22 @@ +# Apply a tag to HEAD at the beginning of each week. +# We can use this to create semver-looking tags for releases like +# 2020.44.123+abc1234 +on: + schedule: + # Mondays at 5am UTC / midnight EST + - cron: '0 5 * * 1' +jobs: + tagger: + runs-on: ubuntu-latest + steps: + - name: tag HEAD with date +%Y.%V + run: | + curl --request POST \ + --url https://api.github.com/repos/${{ github.repository }}/git/refs \ + --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' \ + --data @- << EOF + { + "ref": "refs/tags/$(date +%Y.%V)", + "sha": "${{ github.sha }}" + } + EOF diff --git a/ASPECT_COMMUNITY_LICENSE b/ASPECT_COMMUNITY_LICENSE new file mode 100644 index 000000000..7de1827f8 --- /dev/null +++ b/ASPECT_COMMUNITY_LICENSE @@ -0,0 +1,116 @@ + Aspect Community License + +BY DOWNLOADING, COPYING, OR OTHERWISE USING THE SOFTWARE WITH WHICH THIS LICENSE AGREEMENT IS +PROVIDED (THE “SOFTWARE”), YOU OR THE ENTITY YOU REPRESENT (“LICENSEE”) ARE CONSENTING TO BE BOUND +BY AND ARE BECOMING A PARTY TO THIS LICENSE AGREEMENT (“AGREEMENT”). + +IF YOU DO NOT AGREE TO ALL OF THE TERMS OF THIS AGREEMENT, THEN YOU MAY NOT DOWNLOAD THE SOFTWARE +AND MUST DELETE ANY COPIES THAT YOU HAVE ALREADY DOWNLOADED. + +IF LICENSEE IS AN ENTITY, YOU REPRESENT AND WARRANT THAT YOU ARE AUTHORIZED TO BIND LICENSEE. +IF THESE TERMS ARE CONSIDERED AN OFFER, ACCEPTANCE IS EXPRESSLY LIMITED TO THESE TERMS. + +1. Grant. + + Subject to the terms of this Agreement, Aspect Build Systems, Inc. (“Aspect”) + hereby grants Licensee (and only Licensee) a limited, non-sublicensable, non-transferable, + royalty-free, nonexclusive license to use the Software only in Licensee’s organization and only + in accordance with any documentation that accompanies it. + + The Software may only be used by a Licensee who is: + (i) an individual (and only for personal use), + (ii) a Small Business (as defined below), + (iii) a non-profit entity or an academic or university institution, or + (iv) a current or former Aspect Customer (as defined below). + + A “Small Business” is any entity with fewer than 50 total employees (including, for purposes + of such calculation, all employees of any entities affiliated with such entity). + + An “Aspect Customer” is any entity that has remitted payment to Aspect at any time. + Such payment may be for professional services such as Bazel OSS support, for software licensing + and maintenence such as Aspect Workflows, or for other products or services sold by Aspect. + +2. Restrictions. + + Licensee may not, directly or indirectly: + (i) copy, distribute, rent, lease, timeshare, operate a service bureau with, use commercially + or for the benefit of a third party, the Software, + (ii) reverse engineer, disassemble, decompile, attempt to discover the source code or + structure, sequence and organization of, or remove any proprietary notices from, any non-source + forms of the Software. + + As between the parties, title, ownership rights, and intellectual property rights in and to the + Software, and any copies or portions thereof, shall remain in Aspect and its suppliers or + licensors. Licensee understands that Aspect may modify or discontinue offering the + Software at any time. The Software is protected by the copyright laws of the United States and + international copyright treaties. + + This Agreement does not grant any rights not expressly granted herein. + +3. Feedback. + + Licensee may provide any feedback, suggestions, or comments to Aspect + regarding the Software (“Feedback”). Licensee hereby grants Aspect a nonexclusive, + perpetual, worldwide, royalty-free, fully paid-up, sublicensable, transferable license to use, + make available and otherwise exploit the Feedback for any purpose. + +4. Support and Upgrades. + + This Agreement does not entitle Licensee to any support, upgrades, + patches, enhancements, or fixes for the Software (collectively, “Support”). + Any such Support for the Software that may be made available by Aspect shall become + part of the Software and subject to this Agreement. + +5. Disclaimer. + + ASPECT PROVIDES THE SOFTWARE “AS IS” AND WITHOUT WARRANTY OF ANY KIND, AND + ASPECT HEREBY DISCLAIMS ALL EXPRESS OR IMPLIED WARRANTIES, INCLUDING WITHOUT LIMITATION + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, PERFORMANCE, ACCURACY, + RELIABILITY, AND NON-INFRINGEMENT. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF + THIS AGREEMENT. + +6. Limitation of liability. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, INCLUDING, WITHOUT + LIMITATION, TORT, CONTRACT, STRICT LIABILITY, OR OTHERWISE, SHALL ASPECT OR ITS + LICENSORS, SUPPLIERS OR RESELLERS BE LIABLE TO LICENSEE OR ANY OTHER PERSON FOR ANY DIRECT, + INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT + LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK STOPPAGE, ACCURACY OF RESULTS, + COMPUTER FAILURE OR MALFUNCTION, DAMAGES RESULTING FROM LICENSEE’S USE OF THE SOFTWARE. + +7. Termination. + + Licensee may terminate this Agreement and the license granted herein at any time + by destroying or removing from all computers, networks, and storage media all copies of the + Software. Aspect may terminate this Agreement and the license granted herein immediately + if Licensee breaches any provision of this Agreement. Upon receiving notice of termination from + Aspect, Licensee will destroy or remove from all computers, networks, and storage media + all copies of the Software. Sections 2 through 9 shall survive termination of this Agreement. + +8. Export Controls. + + Licensee shall comply with all export laws and restrictions and regulations of + the Department of Commerce, the United States Department of Treasury Office of Foreign Assets + Control (“OFAC”), or other United States or foreign agency or authority, and not to export, or + allow the export or re-export of the Software in violation of any such restrictions, laws or + regulations. By downloading or using the Software, Licensee is agreeing to the foregoing and + Licensee is representing and warranting that Licensee is not located in, under the control of, + or a national or resident of any restricted country or on any such list. + +9. Miscellaneous. + + Licensee shall comply with all applicable export laws, restrictions and + regulations in connection with Licensee’s use of the Software, and will not export or + re-export the Software in violation thereof. This Agreement is personal to Licensee and + Licensee shall not assign or transfer the Agreement or the Software to any third party under + any circumstances. + + This Agreement represents the complete agreement concerning this license + between the parties and supersedes all prior agreements and representations between them. + It may be amended only by a writing executed by both parties. + + If any provision of this Agreement is held to be unenforceable for any reason, such provision + shall be reformed only to the extent necessary to make it enforceable. + + This Agreement shall be governed by and construed under California law as such law applies to + agreements between California residents entered into and to be performed within California. \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 73ab74bd2..27fae72a4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -78,54 +78,3 @@ After this, you should be able to merge your changes without any conflicts in th git tag v1.5xx.x git push origin $_ ``` - -5. Update Homebrew Formula - - Once the GitHub release is complete and Aspect CLI release artifacts are available for download, - follow the [instructions](https://github.com/aspect-build/homebrew-aspect#updating-formulas-to-the-latest-release) - in our [homebrew-aspect](https://github.com/aspect-build/homebrew-aspect) repository to update the - Homebrew Formulas in the `aspect-build/aspect` tap. - -## Test Homebrew Formula and Bottles - -### Install and Configure `nginx` - -Install `nginx`. On MacOS, run `brew install nginx`. - -Change the `nginx` config so that it listens on part `8090`. By default, `nginx` will listen on -`localhost:8080`. - -- Find the location of your `nginx` config, run `nginx -t`. -- Update the default server stanza to listen on `8090`. It should look like the following: - -``` - server { - listen 8090; - server_name localhost; -``` - -- Restart `nginx`. Run `brew services restart nginx`. - -### Build, Stage, and Install Aspect CLI with Homebrew - -To verify that the built Homebrew formula and bottles build and install properly, -please run the following: - -```sh -$ bazel run //release:verify_homebrew_artifacts -``` - -This will build the artifacts, copy the bottles to your local `nginx` webserver's -serving directory, create an `aspect-build/aspect` tap, copy the formula to the -tap, install the bottle for your system, and verify that the version from the -CLI matches the expected version. - -NOTE: This is not a test target, because it will copy files to various locations on your local -machine. The default permissions for a test target do not allow this. - -If you would like to perform the set up for this verification step without the assertions, you can -run the following (with or without the `--stamp` flag): - -```sh -$ bazel run //release:stage_for_dev -``` diff --git a/README.md b/README.md index 5fe303f6e..38d725e7c 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ title: Aspect CLI sidebar_label: Overview --- -The `aspect` CLI is a drop-in replacement for the `bazel` CLI that comes with Bazel. +Aspect CLI (`aspect`) is a drop-in replacement for the CLI that comes with [Bazel](http://bazel.build) that adds additional features and extensibility to the popular polyglot build system from Google. -# Why Aspect CLI +# Why Aspect CLI? Every organization has a different engineering culture and developer stack. Bazel was designed for Google's workflows, not yours. @@ -15,13 +15,49 @@ untested Bash script living in `/tools/bazel` which Bazelisk understands as a wr Over time, the wrapper accumulates more code, and is a constant source of developer distress. -See more on our product webpage: +See more on our docsite: + +# Licenses + +# Aspect CLI OSS + +Aspect CLI OSS, the open-source, open-core portion of the Aspect CLI, is found in this repository and is [Apache 2](./LICENSE) licensed. + +# Aspect CLI + +The standard Aspect CLI is built on top of the open-source, open-core portion found is this repository and is licensed under the [Aspect Community License](./ASPECT_COMMUNITY_LICENSE). The parts of the Aspect CLI that are not found in this repository are closed source. + +We intend for Aspect CLI to remain free for individuals (only for personal use), Small Business (fewer than 50 employees), and non-profit or academic institutions. Please contact Aspect at https://aspect.build if you would like to use the Aspect CLI and fall outside of free use. # Installation -## Homebrew (MacOS) +## Aspect CLI OSS + +### Bazelisk (MacOS / Linux) + +Aspect CLI OSS can be installed in an existing Bazel workspace using [bazelisk]. + +> [!NOTE] +> This approach doesn't provide the `aspect init` command, which has to run outside a Bazel workspace. + +From the [OSS releases page](https://github.com/aspect-build/aspect-cli/releases), +copy the `.bazeliskrc` snippet into your `.bazeliskrc` file to install Aspect for all developers in the target repository. + +The underlying version of Bazel can be configured in your `.bazelversion` file or the `BAZEL_VERSION` environment variable. -On MacOS, you can run +### Manual (MacOS / Linux) + +On any platform, you can download the Aspect CLI OSS `aspect` binary for your platform on our +[Releases](https://github.com/aspect-build/aspect-cli/releases) page and add it to your `PATH` manually. + +Note, if you manually install for MacOS, you can bypass the "Unknown Developer" dialog by running +`xattr -c $(which aspect)` before launching `aspect`. + +## Aspect CLI Standard + +### Homebrew (MacOS) + +To install the Aspect CLI on MacOS, you can run ```sh % brew install aspect-build/aspect/aspect @@ -29,27 +65,28 @@ On MacOS, you can run This installs the `aspect` command and also links it to `bazel`, just like the [bazelisk] installer does. -## Manual (MacOS / Linux) +### Bazelisk (MacOS / Linux) -On any platform, you can download the `aspect` binary for your platform on our -[Releases](https://github.com/aspect-build/aspect-cli/releases) page and add it to your `PATH` manually. +Aspect CLI can be installed in an existing Bazel workspace using [bazelisk]. -Note, if you manually install for MacOS, you can bypass the "Unknown Developer" dialog by running -`xattr -c $(which aspect)` before launching `aspect`. +> [!NOTE] +> This approach doesn't provide the `aspect init` command, which has to run outside a Bazel workspace. -## Ensuring everyone on the team uses `aspect` +Configure [bazelisk](https://github.com/bazelbuild/bazelisk) to use the Aspect CLI for all developers in a repository +by adding the following to \`.bazeliskrc\` in the repository root: -In an already-existing Bazel workspace, you can have [bazelisk] -install the Aspect CLI just like it can install the standard Bazel CLI. +\`\`\` +BAZELISK_BASE_URL=https://static.aspect.build/aspect +USE_BAZEL_VERSION=aspect/xxxx.xx.xx +\`\`\` ->[!NOTE] ->This approach doesn't provide the `aspect init` command, which has to run outside a Bazel workspace. +Check the Aspect CLI [Homebrew formula](https://github.com/aspect-build/homebrew-aspect/blob/main/Formula/aspect.rb) for +latest version of Aspect CLI. -From the [releases page](https://github.com/aspect-build/aspect-cli/releases), -copy the `.bazeliskrc` snippet into your `.bazeliskrc` file to install Aspect for all developers in this repository. +> [!NOTE] +> An Aspect CLI releases page with release notes and past releases is coming soon. -Note that in all cases, the `.bazelversion` file continues to indicate which version of the -Bazel tool is fetched and run beneath the wrapper. +The underlying version of Bazel can be configured in your `.bazelversion` file or the `BAZEL_VERSION` environment variable. ## Windows @@ -81,7 +118,7 @@ See the [Plugin Documentation](./plugins.md) for more information on how to writ If you think you've hit a bug please file a [Bug Report](https://github.com/aspect-build/aspect-cli/issues/new/choose). -You can also find us on [Bazel Slack](https://slack.bazel.build/) on the #aspect-dev channel. +You can also find us on [Bazel Slack](https://slack.bazel.build/) on the #aspect-build channel. # For Enterprise @@ -89,6 +126,4 @@ Aspect CLI is built by [Aspect](http://aspect.build). See our website at to learn more about our product offerings. -[bazel]: http://bazel.build -[github releases]: https://github.com/aspect-dev/aspect-cli/releases [bazelisk]: https://github.com/bazelbuild/bazelisk diff --git a/buildinfo/BUILD.bazel b/buildinfo/BUILD.bazel index 9999dd372..9a7dac3c3 100644 --- a/buildinfo/BUILD.bazel +++ b/buildinfo/BUILD.bazel @@ -7,7 +7,7 @@ _GO_STAMP_X_DEFS = { "GitCommit": "{STABLE_BUILD_SCM_SHA}", "GitStatus": "{STABLE_BUILD_SCM_LOCAL_CHANGES}", "HostName": "{BUILD_HOST}", - "Release": "{STABLE_BUILD_SCM_TAG}", + "Release": "{STABLE_ASPECT_CLI_VERSION}", } go_library( diff --git a/release/BUILD.bazel b/release/BUILD.bazel index 8afc24064..1475ad5f0 100644 --- a/release/BUILD.bazel +++ b/release/BUILD.bazel @@ -1,8 +1,7 @@ +load("@aspect_bazel_lib//lib:expand_template.bzl", "expand_template") load("@bazel_skylib//:bzl_library.bzl", "bzl_library") load(":bazelisk_artifacts.bzl", "bazelisk_artifacts") -load(":cli_brew_artifacts.bzl", "cli_brew_artifacts") load(":release.bzl", "multi_platform_binaries", "release") -load(":version_file.bzl", "version_file") multi_platform_binaries( name = "aspect", @@ -10,9 +9,13 @@ multi_platform_binaries( tags = ["manual"], ) -version_file( - name = "aspect_version", - version_var = "STABLE_BUILD_SCM_TAG", +expand_template( + name = "aspect_version_file", + out = "aspect_version", + stamp_substitutions = { + "0.0.0-PLACEHOLDER": "{{STABLE_ASPECT_CLI_BAZELISK_COMPAT_VERSION}}", + }, + template = ["0.0.0-PLACEHOLDER"], ) bazelisk_artifacts( @@ -25,36 +28,12 @@ bazelisk_artifacts( version_file = ":aspect_version", ) -cli_brew_artifacts( - name = "aspect_brew_artifacts", - additional_bins = [":bazel"], - # Based on Bazelisk brew formula: - # https://github.com/Homebrew/homebrew-core/blob/7ee2ad3624ac2364aabf28c8d8ee5efaf8592ef1/Formula/bazelisk.rb - additional_content = """ - conflicts_with "bazel", because: "aspect replaces the bazel binary" - conflicts_with "bazelisk", because: "aspect replaces the bazel binary" -""", - binary_name = "aspect", - bottle_root_url = "https://github.com/aspect-build/aspect-cli/releases/download/0.0.0-PLACEHOLDER", - desc = "Correct, fast, usable: choose three", - formula_name = "aspect", - homepage = "https://aspect.build/cli", - license = "Apache-2.0", - root_files = [ - "//:LICENSE", - "//:README.md", - ], - url = "https://github.com/aspect-build/aspect-cli", - version_file = ":aspect_version", -) - release( name = "release", tags = ["manual"], targets = [ ":aspect", ":aspect_bazelisk_artifacts", - ":aspect_brew_artifacts", ], ) @@ -64,33 +43,6 @@ bzl_library( visibility = ["//visibility:public"], ) -exports_files(["version.tmpl"]) - -# TODO: this is out-of-date and no longer working. Leaving here for future use. -sh_binary( - name = "stage_for_dev", - srcs = ["stage_for_dev.sh"], - data = [ - ":aspect_brew_artifacts_dev", - ], -) - -# This is not a test target because it will copy files to your local -# system. However, it will fail if any steps fail or if the assertions are not -# met. -sh_binary( - name = "verify_homebrew_artifacts", - testonly = True, - srcs = ["verify_homebrew_artifacts.sh"], - data = [ - ":aspect_version", - ":stage_for_dev", - ], - deps = [ - "@aspect_bazel_lib//shlib/lib:assertions", - ], -) - # Demonstration delivery target for Aspect Workflows. # In the future this could be wired up to push dev releases to an S3 bucket. sh_binary( @@ -99,7 +51,6 @@ sh_binary( data = [ ":aspect", ":aspect_bazelisk_artifacts", - ":aspect_brew_artifacts", ], ) @@ -111,7 +62,6 @@ sh_binary( data = [ ":aspect", ":aspect_bazelisk_artifacts", - ":aspect_brew_artifacts", ], tags = ["deliverable"], ) diff --git a/release/bazel b/release/bazel deleted file mode 100755 index 0a7d670cc..000000000 --- a/release/bazel +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash -set -o errexit -o nounset -o pipefail -aspect "$@" diff --git a/release/brew/BUILD.bazel b/release/brew/BUILD.bazel deleted file mode 100644 index c156fa8b7..000000000 --- a/release/brew/BUILD.bazel +++ /dev/null @@ -1,51 +0,0 @@ -load("@bazel_skylib//:bzl_library.bzl", "bzl_library") - -# GH553: Need to make `expand_template` for `rules_js` public before we can -# generate a `bzl_library` for `version_file`. -# gazelle:exclude version_file.bzl - -bzl_library( - name = "brew_bottle", - srcs = ["brew_bottle.bzl"], - visibility = ["//visibility:public"], - deps = [ - "@bazel_skylib//lib:paths", - "@rules_pkg//pkg:mappings.bzl", - "@rules_pkg//pkg:tar.bzl", - ], -) - -sh_binary( - name = "generate_formula", - srcs = ["generate_formula.sh"], - visibility = ["//visibility:public"], -) - -bzl_library( - name = "brew_artifacts", - srcs = ["brew_artifacts.bzl"], - visibility = ["//visibility:public"], - deps = [ - "@bazel_skylib//lib:dicts", - "@bazel_tools//tools/build_defs/hash:hash.bzl", - ], -) - -bzl_library( - name = "brew_platforms", - srcs = ["brew_platforms.bzl"], - visibility = ["//visibility:public"], - deps = ["//release:platforms"], -) - -bzl_library( - name = "brew_formula", - srcs = ["brew_formula.bzl"], - visibility = ["//visibility:public"], -) - -bzl_library( - name = "brews", - srcs = ["brews.bzl"], - visibility = ["//visibility:public"], -) diff --git a/release/brew/brew_artifacts.bzl b/release/brew/brew_artifacts.bzl deleted file mode 100644 index 722fd1ed5..000000000 --- a/release/brew/brew_artifacts.bzl +++ /dev/null @@ -1,256 +0,0 @@ -"""Implementation for `brew_artifacts` rule. - -Generates a Homebrew formula. -""" - -load("@bazel_skylib//lib:dicts.bzl", "dicts") -load("@bazel_tools//tools/build_defs/hash:hash.bzl", "sha256", sha256_tools = "tools") -load(":brews.bzl", "brews") - -def _bottle_info(brew_platform, bottle_file, sha256_file, bottle_entry_file): - return struct( - brew_platform = brew_platform, - bottle_file = bottle_file, - sha256_file = sha256_file, - bottle_entry_file = bottle_entry_file, - ) - -def _bottles_info(bottle_infos, bottles_dir): - return struct( - bottle_infos = bottle_infos, - bottles_dir = bottles_dir, - ) - -def _process_bottle(ctx, target, brew_platform): - tfiles = target.files.to_list() - if len(tfiles) != 1: - fail("A bottle target can only provide a single file. platform: ", brew_platform) - bottle_file = tfiles[0] - - # Generate the SHA256 value - sha256_file = sha256(ctx, bottle_file) - - bottle_entry_file = ctx.actions.declare_file( - "{name}_{platform}.bottle_entry".format( - name = ctx.label.name, - platform = brew_platform, - ), - ) - ctx.actions.run_shell( - outputs = [bottle_entry_file], - inputs = [sha256_file], - arguments = [sha256_file.path, brew_platform, bottle_entry_file.path], - command = """\ -sha256_path="$1" -platform="$2" -out_path="$3" -sha256="$(< "${sha256_path}")" -cat > "${out_path}" <<-EOF -sha256 cellar: :any_skip_relocation, ${platform}: "${sha256}" -EOF -""", - ) - - return _bottle_info( - brew_platform = brew_platform, - bottle_file = bottle_file, - sha256_file = sha256_file, - bottle_entry_file = bottle_entry_file, - ) - -# Example of download URL for bottle -# http://localhost:8090/bottles/aspect-cli-0.0.0.monterey.bottle.tar.gz -# -# curl command: -# /usr/local/Homebrew/Library/Homebrew/shims/shared/curl \ -# --disable \ -# --cookie /dev/null \ -# --globoff \ -# --show-error \ -# --user-agent Homebrew/3.6.6-32-g2bec760\ \(Macintosh\;\ Intel\ Mac\ OS\ X\ 12.6\)\ curl/7.79.1 \ -# --header Accept-Language:\ en \ -# --fail \ -# --retry 3 \ -# --location \ -# --remote-time \ -# --output /Users/chuck/Library/Caches/Homebrew/downloads/1bb170bd5ac5f3aba9ca784daca78cf4897071642b70f2816d846094f30e07d4--aspect-cli-0.0.0.monterey.bottle.tar.gz.incomplete \ -# http://localhost:8090/bottles/aspect-cli-0.0.0.monterey.bottle.tar.gz - -def _collect_bottles(ctx): - bottle_infos = [ - _process_bottle(ctx, target, brew_platform) - for (target, brew_platform) in ctx.attr.bottles.items() - ] - - # Collect the bottles in a directory - bottles_dir = ctx.actions.declare_directory( - "{}_bottles".format(ctx.label.name), - ) - args = ctx.actions.args() - args.add(bottles_dir.path) - args.add(ctx.attr.formula) - args.add(ctx.file.version_file) - inputs = [ctx.file.version_file] - for bi in bottle_infos: - inputs.append(bi.bottle_file) - args.add_all([bi.brew_platform, bi.bottle_file]) - - ctx.actions.run_shell( - outputs = [bottles_dir], - inputs = inputs, - arguments = [args], - command = """\ -output_dir="$1" -formula="$2" -version_file="$3" -shift 3 - -version="$(< "${version_file}")" - -# Create the output directory -mkdir -p "${output_dir}" - -while (("$#")); do - # Read args three at a time - platform="$1" - bottle_path="$2" - shift 2 - - # Copy the bottle to the output directory - cp "${bottle_path}" "${output_dir}/${formula}-${version}.${platform}.bottle.tar.gz" -done -""", - ) - - return _bottles_info( - bottle_infos = bottle_infos, - bottles_dir = bottles_dir, - ) - -def _ruby_class_name(ctx): - if ctx.attr.ruby_class_name != "": - return ctx.attr.ruby_class_name - return brews.ruby_class_name(ctx.attr.formula) - -def _write_formula(ctx, bottle_entries): - inputs = bottle_entries[:] - inputs.append(ctx.file.version_file) - - formula_file = ctx.actions.declare_file( - "{}.rb".format(ctx.label.name), - ) - - args = ctx.actions.args() - args.add("--out", formula_file) - args.add("--ruby_class_name", _ruby_class_name(ctx)) - args.add("--desc", ctx.attr.desc) - args.add("--homepage", ctx.attr.homepage) - args.add("--url", ctx.attr.url) - args.add("--version_file", ctx.file.version_file) - if ctx.attr.license: - args.add("--license", ctx.attr.license) - if ctx.attr.bottle_root_url: - args.add("--bottle_root_url", ctx.attr.bottle_root_url) - args.add_all(bottle_entries, before_each = "--bottle_entry") - - if ctx.attr.additional_content: - additional_content_file = ctx.actions.declare_file( - "{}_additional_content".format(ctx.label.name), - ) - ctx.actions.write(additional_content_file, ctx.attr.additional_content) - args.add("--additional_content", additional_content_file) - inputs.append(additional_content_file) - - ctx.actions.run( - outputs = [formula_file], - inputs = inputs, - executable = ctx.executable._generate_formula_tool, - arguments = [args], - ) - - return formula_file - -def _brew_artifacts_impl(ctx): - if ctx.attr.formula == "": - fail("The formula name must not be blank.") - - bottles_info = _collect_bottles(ctx) - bottle_entries = [bi.bottle_entry_file for bi in bottles_info.bottle_infos] - formula_file = _write_formula(ctx, bottle_entries) - - all_files = [formula_file, bottles_info.bottles_dir] - runfiles = ctx.runfiles(files = all_files) - return [ - DefaultInfo(files = depset(all_files), runfiles = runfiles), - OutputGroupInfo( - formula_file = depset([formula_file]), - bottle_files = depset([bottles_info.bottles_dir]), - all_files = depset(all_files), - ), - ] - -brew_artifacts = rule( - implementation = _brew_artifacts_impl, - attrs = dicts.add({ - "additional_content": attr.string( - doc = "Additional content to add to the formula", - ), - "bottle_root_url": attr.string( - doc = "The root URL from which bottles are downloaded.", - ), - "bottles": attr.label_keyed_string_dict( - doc = "Maps the bottle to the Homebrew platform name.", - allow_files = True, - ), - "desc": attr.string( - mandatory = True, - doc = "The description for the formula.", - ), - "formula": attr.string( - mandatory = True, - doc = "The name of the Homebrew formula.", - ), - "homepage": attr.string( - mandatory = True, - doc = """\ -The URL to which users will be directed for information about the application.\ -""", - ), - "license": attr.string( - doc = "The license for formula.", - ), - "ruby_class_name": attr.string( - doc = """\ -The Ruby class name for the formula. If not provided, this will be calculated \ -from the formula value.\ -""", - ), - # GH329: Finish adding required formula attributes. - # "conflicts_with": attr.string( - # doc = """\ - # A JSON string representing a list of formulas that this formula conflicts with.\ - # """, - # ), - # "depends_on": attr.string_list( - # doc = """\ - # A JSON string representing a list of formulas that this formula dependes upon.\ - # """, - # ), - "url": attr.string( - doc = "The URL from which the source code can be downloaded.", - mandatory = True, - ), - "version_file": attr.label( - doc = "The file that contains the semver for the bottle.", - mandatory = True, - allow_single_file = True, - ), - "_generate_formula_tool": attr.label( - executable = True, - cfg = "exec", - default = "//release/brew:generate_formula", - doc = "The tool used to generate the Homebrew formula.", - ), - }, sha256_tools), - doc = "Generate a Homebrew formula and collect the related bottles.", -) diff --git a/release/brew/brew_bottle.bzl b/release/brew/brew_bottle.bzl deleted file mode 100644 index ef98cddf9..000000000 --- a/release/brew/brew_bottle.bzl +++ /dev/null @@ -1,109 +0,0 @@ -"""Macro for generating a Homebrew bottle - -Implementation for `brew bottle`: -https://github.com/Homebrew/brew/blob/8dc46a7c477929185cba8ca0de5f9c843b3e9385/Library/Homebrew/dev-cmd/bottle.rb#L288 - -Example bottle layout for `bazelisk` version 1.14.0: -``` -bazelisk -└── 1.14.0 - ├── LICENSE - ├── README.md - ├── bin - │ ├── bazel -> bazelisk - │ └── bazelisk - └── share - └── zsh - └── site-functions - └── _bazel -``` - -""" - -load("@aspect_bazel_lib//lib:utils.bzl", "to_label") -load("@bazel_skylib//rules:build_test.bzl", "build_test") -load("@rules_pkg//pkg:mappings.bzl", "pkg_attributes", "pkg_files") -load("@rules_pkg//pkg:tar.bzl", "pkg_tar") - -def brew_bottle( - name, - formula, - version_file, - root_files = None, - bin_files = None, - bin_renames = None, - visibility = None, - testonly = False): - """Define rules for generating a Homebrew bottle and related artifacts. - - Args: - name: The name for the bottle target as a `string`. - formula: The name of the Homebrew formula as a `string`. - version_file: The label referencing a version file as written by `version_file`. - root_files: Optional. A `sequence` of files to be placed in the root of - the bottle. - bin_files: Optional. A `sequence` of files to be placed in the - formula's bin directory. - bin_renames: Optional. A `dict` of `Label -> string` that maps files - that should be renamed before being placed in the `bin` directory. - visibility: Optional. A `list` of visibility declarations that should - be applied to the output targets. - testonly: Optional. A `bool` specifying whether the targets defined by - this macro are for test only. - """ - - srcs = [] - - version_label = to_label(version_file) - package_dir_file_name = "{}_dir_file".format(name) - native.genrule( - name = package_dir_file_name, - outs = ["{}.dir_file".format(name)], - srcs = [version_label], - cmd = """\ - formula="{formula}" - version_file=$(location {version_label}) - """.format( - formula = formula, - version_label = version_label, - ) + """\ - version="$$(< "$${version_file}")" - echo "$${formula}/$${version}" > $@ - """, - testonly = testonly, - ) - - if root_files: - root_files_name = "{}_root_files".format(name) - pkg_files( - name = root_files_name, - srcs = root_files, - testonly = testonly, - ) - srcs.append(root_files_name) - - if bin_files: - bin_files_name = "{}_bin_files".format(name) - pkg_files( - name = bin_files_name, - srcs = bin_files, - renames = bin_renames, - prefix = "bin", - testonly = testonly, - attributes = pkg_attributes(mode = "0555"), - ) - srcs.append(bin_files_name) - - pkg_tar( - name = name, - srcs = srcs, - extension = "tar.gz", - visibility = visibility, - testonly = testonly, - package_dir_file = package_dir_file_name, - ) - - build_test( - name = "{}_build_test".format(name), - targets = [name], - ) diff --git a/release/brew/brew_formula.bzl b/release/brew/brew_formula.bzl deleted file mode 100644 index 5dfd37809..000000000 --- a/release/brew/brew_formula.bzl +++ /dev/null @@ -1,19 +0,0 @@ -"""Implementation for `brew_formula` macro. - -Select the formula file from a `brew_artifacts` declaration. -""" - -def brew_formula(name, artifacts, **kwargs): - """Selects the formula file from a `brew_artifacts` declaration. - - Args: - name: The name of the target as a `string`. - artifacts: A label for a `brew_artifacts` declaration. - **kwargs: Attributes passed along to underlying rules. - """ - native.filegroup( - name = name, - srcs = [artifacts], - output_group = "formula_file", - **kwargs - ) diff --git a/release/brew/brew_platforms.bzl b/release/brew/brew_platforms.bzl deleted file mode 100644 index db60bda4b..000000000 --- a/release/brew/brew_platforms.bzl +++ /dev/null @@ -1,52 +0,0 @@ -"""Module for managing Homebrew platforms""" - -load("//release:platforms.bzl", "platforms") - -# MacOS version names are listed here: -# https://github.com/Homebrew/brew/blob/74e933caa3a778213ba33ff932c7e03e8ab8b329/Library/Homebrew/macos_versions.rb#L10 -_NAMES = struct( - # homebrew CI requires arm bottles to be listed before intel bottles - MONTEREY_X86_64 = "monterey", - MONTEREY_ARM64 = "arm64_monterey", - BIG_SUR_X86_64 = "big_sur", - BIG_SUR_ARM64 = "arm64_big_sur", - LINUX_X86_64 = "x86_64_linux", -) - -def _new(name, go_platform): - """Create a Homebrew platform `struct`. - - Args: - name: The Homebrew name for the platforms as a `string`. - go_platform: A `struct` representing a Go release platform as created - by `platforms.new()`. - - Returns: - A `struct` representing a Homebrew platform. - """ - return struct( - name = name, - go_platform = go_platform, - ) - -_BREW_PLATFORMS = [ - _new(_NAMES.MONTEREY_X86_64, platforms.get(platforms.oss.MACOS, platforms.archs.AMD64)), - _new(_NAMES.MONTEREY_ARM64, platforms.get(platforms.oss.MACOS, platforms.archs.ARM64)), - _new(_NAMES.BIG_SUR_X86_64, platforms.get(platforms.oss.MACOS, platforms.archs.AMD64)), - _new(_NAMES.BIG_SUR_ARM64, platforms.get(platforms.oss.MACOS, platforms.archs.ARM64)), - _new(_NAMES.LINUX_X86_64, platforms.get(platforms.oss.LINUX, platforms.archs.AMD64)), -] - -_BREW_PLATFORMS_LOOKUP = { - bp.name: bp - for bp in _BREW_PLATFORMS -} - -brew_platforms = struct( - # Constants - all = _BREW_PLATFORMS, - names = _NAMES, - by_name = _BREW_PLATFORMS_LOOKUP, - # Functions - new = _new, -) diff --git a/release/brew/brews.bzl b/release/brew/brews.bzl deleted file mode 100644 index 0bbf5f9d0..000000000 --- a/release/brew/brews.bzl +++ /dev/null @@ -1,32 +0,0 @@ -"""Implementation for `brews` Starlark module. - -Provides functions for generating target names and attribute values for -Homebrew macros and rules. -""" - -def _bottle_name(prefix_or_platform, platform = None): - """Generate the target name for a bottle. - - Args: - prefix_or_platform: The prefix or the platform. - platform: If a prefix is specified, this is the platform. - - Returns: - A `string` value. - """ - parts = [prefix_or_platform] - if platform != None: - parts.append(platform) - parts.append("bottle") - return "_".join(parts) - -def _ruby_class_name(name): - normalized_name = name.replace("-", "_").replace(".", "_") - parts = normalized_name.split("_") - parts = [part.title() for part in parts] - return "".join(parts) - -brews = struct( - bottle_name = _bottle_name, - ruby_class_name = _ruby_class_name, -) diff --git a/release/brew/generate_formula.sh b/release/brew/generate_formula.sh deleted file mode 100755 index 270e56ec0..000000000 --- a/release/brew/generate_formula.sh +++ /dev/null @@ -1,192 +0,0 @@ -#!/usr/bin/env bash - -# Functions - -warn() { - local msg="${1:-}" - shift 1 - while (("$#")); do - msg="${msg:-}"$'\n'"${1}" - shift 1 - done - echo >&2 "${msg}" -} - -# Echos the provided message to stderr and exits with an error (1). -fail() { - warn "$@" - exit 1 -} - -# Print an error message and dump the usage/help for the utility. -# This function expects a get_usage function to be defined. -usage_error() { - local msg="${1:-}" - cmd=(fail) - [[ -z "${msg:-}" ]] || cmd+=("${msg}" "") - cmd+=("$(get_usage)") - "${cmd[@]}" -} - -get_usage() { - local utility - utility="$(basename "${BASH_SOURCE[0]}")" - cat <<-EOF - Generate a Homebrew formula from the provided parameters. - - Usage: - ${utility} [OPTION]... - - Required: - --desc The description that is included in the formula. - --formula The name of the formula (e.g., 'foo-bar'). - --homepage The webpage that is exposed by Homebrew. - --url The URL for the source code. This is required even - if one is providing bottles. - --version_file The file that contains the semver. - - Options: - --bottle_entry A platform stanza (e.g., 'sha256: ...') for a - bottle. - --bottle_root_url The base URL from which bottles will be downloaded. - --license The license that governs the use of the application. - --out The output path where to write the formula. - If not provided, it is written to STDOUT. - --ruby_class_name The Ruby class name for the formula. - --additional_content Path to a file containing additional content to add - to the formula - EOF -} - -write() { - local output="${1:-}" - if [[ -n "${output:-}" ]]; then - echo >&3 "${output}" - else - cat >&3 - fi -} - -# Process Arguments - -bottle_entry_paths=() -while (("$#")); do - case "${1}" in - "--help") - get_usage - exit 0 - ;; - "--bottle_entry") - bottle_entry_paths+=("${2}") - shift 2 - ;; - "--bottle_root_url") - bottle_root_url="${2}" - shift 2 - ;; - "--desc") - desc="${2}" - shift 2 - ;; - "--homepage") - homepage="${2}" - shift 2 - ;; - "--license") - license="${2}" - shift 2 - ;; - "--out") - out_path="${2}" - shift 2 - ;; - "--ruby_class_name") - ruby_class_name="${2}" - shift 2 - ;; - "--url") - url="${2}" - shift 2 - ;; - "--version_file") - version_file="${2}" - shift 2 - ;; - "--additional_content") - additional_content="${2}" - shift 2 - ;; - *) - usage_error "Unrecognized argument. ${1}" - ;; - esac -done - -[[ -n "${desc:-}" ]] || usage_error "Missing value for 'desc'." -[[ -n "${homepage:-}" ]] || usage_error "Missing value for 'homepage'." -[[ -n "${ruby_class_name:-}" ]] || usage_error "Missing value for 'ruby_class_name'." -[[ -n "${url:-}" ]] || usage_error "Missing value for 'url'." -[[ -n "${version_file:-}" ]] || usage_error "Missing value for 'version_file'." - -# All generated output will be sent to file descriptor 3. If an output file has -# been assigned, fd 3 will be assigned to that file. Otherwise, fd 3 will be -# assigned to STDOUT. -if [[ -n "${out_path:-}" ]]; then - exec 3<>"${out_path}" -else - # Redirect to STDOUT - exec 3>&1 -fi - -# Cleanup - -cleanup() { - # Close file descriptor 3 - exec 3>&- -} -trap cleanup EXIT - -# Generate Formula - -# Read the version -version="$(<"${version_file}")" - -# Output the start of the formula -write <<-EOF - class ${ruby_class_name} < Formula - desc "${desc}" - homepage "${homepage}" - url "${url}" - version "${version}" -EOF - -if [[ -n "${license:-}" ]]; then - write <<-EOF - license "${license}" - EOF -fi - -if [[ ${#bottle_entry_paths[@]} -gt 0 ]]; then - write " bottle do" - if [[ -n "${bottle_root_url:-}" ]]; then - bottle_root_url="${bottle_root_url/0.0.0-PLACEHOLDER/$version}" - write <<-EOF - root_url "${bottle_root_url}" - EOF - fi - for bottle_entry_path in "${bottle_entry_paths[@]}"; do - bottle_entry="$(<"${bottle_entry_path}")" - write " ${bottle_entry}" - done - write " end" -fi - -if [ "${additional_content:-}" ]; then - if [ ! -f "${additional_content}" ]; then - fail "ERROR: --additional_content file ${additional_content} does not exist" - fi - cat "${additional_content}" >&3 -fi - -# Ouptut the end of the formula -write "end" diff --git a/release/brew/tests/BUILD.bazel b/release/brew/tests/BUILD.bazel deleted file mode 100644 index 7ef080e38..000000000 --- a/release/brew/tests/BUILD.bazel +++ /dev/null @@ -1,224 +0,0 @@ -load("@aspect_bazel_lib//lib:testing.bzl", "assert_contains") -load("@bazel_skylib//rules:build_test.bzl", "build_test") -load("@bazel_skylib//rules:write_file.bzl", "write_file") -load("//release:version_file.bzl", "version_file") -load("//release/brew:brew_artifacts.bzl", "brew_artifacts") -load("//release/brew:brew_bottle.bzl", "brew_bottle") -load("//release/brew:brew_formula.bzl", "brew_formula") -load("//release/brew:brews.bzl", "brews") -load(":brew_platforms_tests.bzl", "brew_platforms_test_suite") -load(":brews_tests.bzl", "brews_test_suite") - -# Starlark Unit Tests - -brews_test_suite() - -brew_platforms_test_suite() - -# Setup for Tests - -_VERSION_FILE_NO_STAMP_NAME = "version_file_no_stamp" - -_VERSION_FILE_WITH_STAMP_NAME = "version_file_with_stamp" - -version_file( - name = _VERSION_FILE_NO_STAMP_NAME, - stamp = 0, - version_var = "STABLE_BUILD_SCM_TAG", -) - -version_file( - name = _VERSION_FILE_WITH_STAMP_NAME, - stamp = 1, - version_var = "STABLE_BUILD_SCM_TAG", -) - -write_file( - name = "test_version", - testonly = True, - out = "test.version", - content = [ - "1.2.3", - "", - ], -) - -_FORMULA = "myapp" - -_ALL_BREW_PLATFORMS = [ - "monterey", - "arm64_monterey", - "x86_64_linux", -] - -write_file( - name = "test_readme", - testonly = True, - out = "README.md", - content = [ - "# Interesting Title", - "", - ], -) - -write_file( - name = "binary_no_rename", - testonly = True, - out = "goodbye", - content = [ - "echo 'Goodbye, World!'", - ], - is_executable = True, -) - -[ - write_file( - name = "{}_binary".format(p), - testonly = True, - out = "hello_{}".format(p), - content = [ - "echo 'Hello, World!'", - "echo 'I am {}'".format(p), - ], - is_executable = True, - ) - for p in _ALL_BREW_PLATFORMS -] - -[ - brew_bottle( - name = brews.bottle_name(p), - testonly = True, - bin_files = [ - "{}_binary".format(p), - ":binary_no_rename", - ], - bin_renames = { - "{}_binary".format(p): "hello", - }, - formula = _FORMULA, - root_files = [":test_readme"], - version_file = ":test_version", - ) - for p in _ALL_BREW_PLATFORMS -] - -_ARTIFACTS_NAME = "{}_artifacts".format(_FORMULA) - -brew_artifacts( - name = _ARTIFACTS_NAME, - testonly = True, - bottles = { - brews.bottle_name(p): p - for p in _ALL_BREW_PLATFORMS - }, - desc = "This is my cool app", - formula = _FORMULA, - homepage = "https://example.com/myapp", - url = "https://github.com/example/foo.git", - version_file = ":test_version", -) - -# Other Formulas - -_BOTTLE_ROOT_URL_ARTIFACTS_NAME = _ARTIFACTS_NAME + "_with_bottle_root_url" - -brew_artifacts( - name = _BOTTLE_ROOT_URL_ARTIFACTS_NAME, - testonly = True, - bottle_root_url = "https://cdn.example.com/brew_bottles", - bottles = { - brews.bottle_name(p): p - for p in _ALL_BREW_PLATFORMS - }, - desc = "This is my cool app", - formula = _FORMULA, - homepage = "https://example.com/myapp", - ruby_class_name = "OverrideClassName", - url = "https://github.com/example/foo.git", - version_file = ":test_version", -) - -# Tests - -assert_contains( - name = "{}_test".format(_VERSION_FILE_NO_STAMP_NAME), - actual = _VERSION_FILE_NO_STAMP_NAME, - expected = "0.0.0-VERSION-PLACEHOLDER", -) - -# TODO: fix on GitHub actions where the workspace status command's `git describe --tags` -# fails with `fatal: No tags can describe 'e5ac90b62d1801a5fa8f846b5be869a21bf5a14b'` on -# GitHub actions (even when fetch-depth is set to 0 on actions/checkout@v4 step) which -# leave STABLE_BUILD_SCM_TAG unset and this test fails. -# assert_contains( -# name = "{}_test".format(_VERSION_FILE_WITH_STAMP_NAME), -# actual = _VERSION_FILE_WITH_STAMP_NAME, -# expected = "5", # this will need to change to 6. when we bump major -# ) - -build_test( - name = "build_test", - targets = [_ARTIFACTS_NAME], -) - -_FORMULA_NAME = "{}_formula".format(_ARTIFACTS_NAME) - -brew_formula( - name = _FORMULA_NAME, - testonly = True, - artifacts = _ARTIFACTS_NAME, -) - -assert_contains( - name = "{}_test".format(_FORMULA_NAME), - actual = _FORMULA_NAME, - expected = "class Myapp < Formula", -) - -_BOTTLE_ROOT_URL_FORMULA_NAME = "{}_formula".format( - _BOTTLE_ROOT_URL_ARTIFACTS_NAME, -) - -brew_formula( - name = _BOTTLE_ROOT_URL_FORMULA_NAME, - testonly = True, - artifacts = _BOTTLE_ROOT_URL_ARTIFACTS_NAME, -) - -assert_contains( - name = "{}_override_test".format(_BOTTLE_ROOT_URL_FORMULA_NAME), - actual = _BOTTLE_ROOT_URL_FORMULA_NAME, - expected = "class OverrideClassName < Formula", -) - -assert_contains( - name = "{}_bottle_test".format(_BOTTLE_ROOT_URL_FORMULA_NAME), - actual = _BOTTLE_ROOT_URL_FORMULA_NAME, - expected = """\ - bottle do - root_url "https://cdn.example.com/brew_bottles" -""", -) - -sh_test( - name = "brew_bottle_test", - srcs = ["brew_bottle_test.sh"], - data = [ - ":monterey_bottle", - ], - deps = [ - "@aspect_bazel_lib//shlib/lib:assertions", - ], -) - -sh_test( - name = "generate_formula_test", - srcs = ["generate_formula_test.sh"], - data = [ - "//release/brew:generate_formula", - ], - deps = [ - "@aspect_bazel_lib//shlib/lib:assertions", - ], -) diff --git a/release/brew/tests/brew_bottle_test.sh b/release/brew/tests/brew_bottle_test.sh deleted file mode 100755 index 634a2f0da..000000000 --- a/release/brew/tests/brew_bottle_test.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash - -# MARK - Locate Deps - -assertions_sh_location=aspect_bazel_lib/shlib/lib/assertions.sh -assertions_sh="$(rlocation "${assertions_sh_location}")" || - (echo >&2 "Failed to locate ${assertions_sh_location}" && exit 1) -# shellcheck source=/dev/null -source "${assertions_sh}" - -monterey_bottle_tar_gz_location=build_aspect_cli/release/brew/tests/monterey_bottle.tar.gz -monterey_bottle_tar_gz="$(rlocation "${monterey_bottle_tar_gz_location}")" || - (echo >&2 "Failed to locate ${monterey_bottle_tar_gz_location}" && exit 1) - -# MARK - Test - -actual_listing="$(tar -tf "${monterey_bottle_tar_gz}")" -expected_listing="$( - cat <<-EOF - myapp/ - myapp/1.2.3/ - myapp/1.2.3/README.md - myapp/1.2.3/bin/ - myapp/1.2.3/bin/goodbye - myapp/1.2.3/bin/hello - EOF -)" -assert_equal "${expected_listing}" "${actual_listing}" diff --git a/release/brew/tests/brew_platforms_tests.bzl b/release/brew/tests/brew_platforms_tests.bzl deleted file mode 100644 index 39db02f15..000000000 --- a/release/brew/tests/brew_platforms_tests.bzl +++ /dev/null @@ -1,26 +0,0 @@ -"""Tests for `brew_platforms` module""" - -load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest") -load("//release:platforms.bzl", "platforms") -load("//release/brew:brew_platforms.bzl", "brew_platforms") - -def _new_test(ctx): - env = unittest.begin(ctx) - - go_platform = platforms.get(platforms.oss.MACOS, platforms.archs.ARM64) - actual = brew_platforms.new(brew_platforms.names.MONTEREY_ARM64, go_platform) - expected = struct( - name = brew_platforms.names.MONTEREY_ARM64, - go_platform = go_platform, - ) - asserts.equals(env, expected, actual) - - return unittest.end(env) - -new_test = unittest.make(_new_test) - -def brew_platforms_test_suite(): - return unittest.suite( - "brew_platforms_tests", - new_test, - ) diff --git a/release/brew/tests/brews_tests.bzl b/release/brew/tests/brews_tests.bzl deleted file mode 100644 index 33e4f51ee..000000000 --- a/release/brew/tests/brews_tests.bzl +++ /dev/null @@ -1,49 +0,0 @@ -"""Tests for `brews` Starlark module.""" - -load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest") -load("//release/brew:brews.bzl", "brews") - -def _bottle_name_test(ctx): - env = unittest.begin(ctx) - - actual = brews.bottle_name("monterey") - asserts.equals(env, "monterey_bottle", actual) - - actual = brews.bottle_name("foo", "monterey") - asserts.equals(env, "foo_monterey_bottle", actual) - - actual = brews.bottle_name("foo", "arm64_monterey") - asserts.equals(env, "foo_arm64_monterey_bottle", actual) - - return unittest.end(env) - -bottle_name_test = unittest.make(_bottle_name_test) - -def _ruby_class_name_test(ctx): - env = unittest.begin(ctx) - - actual = brews.ruby_class_name("foo") - asserts.equals(env, "Foo", actual) - - actual = brews.ruby_class_name("foo-bar") - asserts.equals(env, "FooBar", actual) - - actual = brews.ruby_class_name("foo_bar") - asserts.equals(env, "FooBar", actual) - - actual = brews.ruby_class_name("foo.bar") - asserts.equals(env, "FooBar", actual) - - actual = brews.ruby_class_name("foo_bar-chicken.hello") - asserts.equals(env, "FooBarChickenHello", actual) - - return unittest.end(env) - -ruby_class_name_test = unittest.make(_ruby_class_name_test) - -def brews_test_suite(): - return unittest.suite( - "brews_tests", - bottle_name_test, - ruby_class_name_test, - ) diff --git a/release/brew/tests/generate_formula_test.sh b/release/brew/tests/generate_formula_test.sh deleted file mode 100755 index 46acb8086..000000000 --- a/release/brew/tests/generate_formula_test.sh +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env bash - -# MARK - Locate Deps - -assertions_sh_location=aspect_bazel_lib/shlib/lib/assertions.sh -assertions_sh="$(rlocation "${assertions_sh_location}")" || - (echo >&2 "Failed to locate ${assertions_sh_location}" && exit 1) -# shellcheck source=/dev/null -source "${assertions_sh}" - -generate_formula_sh_location=build_aspect_cli/release/brew/generate_formula.sh -generate_formula_sh="$(rlocation "${generate_formula_sh_location}")" || - (echo >&2 "Failed to locate ${generate_formula_sh_location}" && exit 1) - -# Setup - -monterey_bottle_entry_path="monterey.bottle_entry" -cat >"${monterey_bottle_entry_path}" <<-EOF - sha256 cellar: :any_skip_relocation, monterey: "ASHA256A" -EOF - -arm64_monterey_bottle_entry_path="arm64_monterey.bottle_entry" -cat >"${arm64_monterey_bottle_entry_path}" <<-EOF - sha256 cellar: :any_skip_relocation, arm64_monterey: "ASHA256B" -EOF - -version_file="version" -cat >"${version_file}" <<-EOF - 1.2.3 -EOF - -# MARK - Functions - -assert_ml_match() { - local actual="${1}" - local errmsg="${2:-}" - local expected - expected="$(&2 "${msg}" -} - -# Echos the provided message to stderr and exits with an error (1). -fail() { - warn "$@" - exit 1 -} - -# Print an error message and dump the usage/help for the utility. -# This function expects a get_usage function to be defined. -usage_error() { - local msg="${1:-}" - cmd=(fail) - [[ -z "${msg:-}" ]] || cmd+=("${msg}" "") - cmd+=("$(get_usage)") - "${cmd[@]}" -} - -get_usage() { - local utility - utility="$(basename "${BASH_SOURCE[0]}")" - cat <<-EOF - Builds, stages, and installs locally built Homebrew formula and bottles. - - Usage: - ${utility} [OPTION]... - - Options: - --help Show help message. - EOF -} - -# Process Args - -# Default location for nginx on Macos installed by Homebrew. -default_nginx_www_path="/usr/local/var/www" -bottles_output_basename="bottles" -bottles_output_dir="${default_nginx_www_path}/${bottles_output_basename}" -homebrew_taps_dir="$(brew --repository)/Library/Taps" - -formula="aspect" -brew_repo_user="aspect-build" -brew_repo_name="aspect" -brew_repo_url="https://github.com/${brew_repo_user}/homebrew-${brew_repo_name}" -aspect_tap="${brew_repo_user}/${brew_repo_name}" -fully_qualified_formula="${aspect_tap}/${formula}" -aspect_tap_dir="${homebrew_taps_dir}/${brew_repo_user}/homebrew-${brew_repo_name}" -formula_out_path="${aspect_tap_dir}/Formula/${formula}.rb" - -while (("$#")); do - case "${1}" in - "--help") - get_usage - exit 0 - ;; - *) - usage_error "Unrecognized argument. ${1}" - ;; - esac -done - -# Check for external tool dependencies -which >/dev/null brew || - fail "Homebrew must be installed to proceed. For instructions, please see https://brew.sh/." -which >/dev/null nginx || - fail "nginx must be installed to proceed. Run 'brew install nginx'." - -# Copy the bottles to the local web server -mkdir -p "${bottles_output_dir}" -echo "Copy bottles to local web server directory. ${bottles_output_dir}" -cp -fv "${aspect_cli_brew_artifacts_dev_bottles}"/* "${bottles_output_dir}/" - -# Uninstall the Aspect CLI, if it is installed -brew list --formula "${fully_qualified_formula}" >/dev/null 2>&1 && - echo "Uninstall formula. ${fully_qualified_formula}" && - brew uninstall "${fully_qualified_formula}" - -# If the tap is not present, add it. -(brew tap | grep "aspect-build/aspect") || - (echo "Add tap. ${aspect_tap}" && brew tap "${aspect_tap}" "${brew_repo_url}") - -# Copy the formula -echo "Update formula. ${formula_out_path}" -mkdir -p "$(dirname "${formula_out_path}")" -cp -f "${aspect_cli_brew_artifacts_dev_rb}" "${formula_out_path}" - -# Uninstalling Bazel & Bazelisk -brew unlink bazelisk >/dev/null 2>&1 || true -brew unlink bazel >/dev/null 2>&1 || true - -# Install Aspect CLI -echo "Install formula. ${fully_qualified_formula}" -brew install --verbose "${fully_qualified_formula}" diff --git a/release/verify_homebrew_artifacts.sh b/release/verify_homebrew_artifacts.sh deleted file mode 100755 index b7cc4be69..000000000 --- a/release/verify_homebrew_artifacts.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash - -# MARK - Locate Deps - -assertions_sh_location=aspect_bazel_lib/shlib/lib/assertions.sh -assertions_sh="$(rlocation "${assertions_sh_location}")" || - (echo >&2 "Failed to locate ${assertions_sh_location}" && exit 1) -# shellcheck source=/dev/null -source "${assertions_sh}" - -stage_for_dev_sh_location=build_aspect_cli/release/stage_for_dev.sh -stage_for_dev_sh="$(rlocation "${stage_for_dev_sh_location}")" || - (echo >&2 "Failed to locate ${stage_for_dev_sh_location}" && exit 1) - -aspect_version_location=build_aspect_cli/release/aspect_version.version -aspect_version="$(rlocation "${aspect_version_location}")" || - (echo >&2 "Failed to locate ${aspect_version_location}" && exit 1) - -# MARK - Test - -expected_version="$(<"${aspect_version}")" - -# Copy the bottles and formula to the correct spots -"${stage_for_dev_sh}" - -# Confirm that -output="$(aspect --version 2>/dev/null)" - -# If the expected version is the placeholder (i.e., --stamp was not specified), -# then expect the unstamped version message. -if [[ "${expected_version}" == "0.0.0-VERSION-PLACEHOLDER" ]]; then - expected_version="unknown \[not built with --stamp\]" -fi - -assert_match "aspect ${expected_version}" "${output}" diff --git a/release/version.tmpl b/release/version.tmpl deleted file mode 100644 index 64d2a43f6..000000000 --- a/release/version.tmpl +++ /dev/null @@ -1 +0,0 @@ -0.0.0-VERSION-PLACEHOLDER diff --git a/release/version_file.bzl b/release/version_file.bzl deleted file mode 100644 index 955233137..000000000 --- a/release/version_file.bzl +++ /dev/null @@ -1,22 +0,0 @@ -"""Macro to generate a version file""" - -load("@aspect_bazel_lib//lib:expand_template.bzl", "expand_template") - -def version_file(name, version_var, **kwargs): - """Generate a file that contains the semver stored in the specified \ - workspace status variable. - - Args: - name: The name of the target. - version_var: The name of the workspace status variable. - **kwargs: Other attributes passsed to underlying rules. - """ - expand_template( - name = name, - out = "{}.version".format(name), - stamp_substitutions = { - "0.0.0-VERSION-PLACEHOLDER": "{{" + version_var + "}}", - }, - template = "//release:version.tmpl", - **kwargs - ) diff --git a/workspace_status.sh b/workspace_status.sh index 1a19a0d7e..a7df8627e 100755 --- a/workspace_status.sh +++ b/workspace_status.sh @@ -23,5 +23,19 @@ echo "STABLE_BUILD_SCM_SHA $(git rev-parse HEAD)" echo "STABLE_BUILD_SCM_LOCAL_CHANGES $(has_local_changes)" if [ "$(git tag | wc -l)" -gt 0 ]; then - echo "STABLE_BUILD_SCM_TAG $(git describe --tags)" + # Follows https://blog.aspect.build/versioning-releases-from-a-monorepo + monorepo_version=$( + git describe --tags --long --match="[0-9][0-9][0-9][0-9].[0-9][0-9]" | + sed -e 's/-/./;s/-g/-/' + ) + + # Variant of monorepo_version that conforms with the version scheme Bazelisk supports. + # It assumes the upstream `bazel` binary releases are the only ones referenced, + # so we are forced to adopt a matching scheme. + # https://github.com/bazelbuild/bazelisk/blob/47f60477721681a117cbf905784ee5220100e68b/versions/versions.go#L20-L25 + # shellcheck disable=SC2001 + bazelisk_compat_version=$(sed 's/-.*//' <<<"$monorepo_version") + + echo "STABLE_ASPECT_CLI_BAZELISK_COMPAT_VERSION ${bazelisk_compat_version}" + echo "STABLE_ASPECT_CLI_VERSION ${monorepo_version}" fi