From ca1f4f15528b85c09c29c0fa75fa901fea30627f Mon Sep 17 00:00:00 2001 From: Long Ho Date: Sun, 23 Aug 2026 13:11:54 +0700 Subject: [PATCH 1/2] feat(bazel): publish codescythe BCR overlay --- .github/workflows/bcr.yml | 79 ++++++++++++ .github/workflows/cli-release.yml | 8 ++ .github/workflows/publish-bcr.yml | 108 ++++++++++++++++ README.md | 22 ++++ bcr/bazel_registry.json | 1 + bcr/modules/codescythe/0.10.1/MODULE.bazel | 12 ++ .../codescythe/0.10.1/overlay/BUILD.bazel | 7 ++ .../codescythe/0.10.1/overlay/MODULE.bazel | 12 ++ .../codescythe/0.10.1/overlay/extensions.bzl | 115 ++++++++++++++++++ .../codescythe/0.10.1/overlay/toolchain.bzl | 37 ++++++ bcr/modules/codescythe/0.10.1/presubmit.yml | 13 ++ bcr/modules/codescythe/0.10.1/source.json | 11 ++ bcr/modules/codescythe/metadata.json | 19 +++ 13 files changed, 444 insertions(+) create mode 100644 .github/workflows/bcr.yml create mode 100644 .github/workflows/publish-bcr.yml create mode 100644 bcr/bazel_registry.json create mode 100644 bcr/modules/codescythe/0.10.1/MODULE.bazel create mode 100644 bcr/modules/codescythe/0.10.1/overlay/BUILD.bazel create mode 100644 bcr/modules/codescythe/0.10.1/overlay/MODULE.bazel create mode 100644 bcr/modules/codescythe/0.10.1/overlay/extensions.bzl create mode 100644 bcr/modules/codescythe/0.10.1/overlay/toolchain.bzl create mode 100644 bcr/modules/codescythe/0.10.1/presubmit.yml create mode 100644 bcr/modules/codescythe/0.10.1/source.json create mode 100644 bcr/modules/codescythe/metadata.json diff --git a/.github/workflows/bcr.yml b/.github/workflows/bcr.yml new file mode 100644 index 0000000..a7d1b44 --- /dev/null +++ b/.github/workflows/bcr.yml @@ -0,0 +1,79 @@ +name: Validate BCR overlay + +on: + pull_request: + paths: + - ".github/workflows/bcr.yml" + - ".github/workflows/publish-bcr.yml" + - "bcr/**" + push: + branches: + - main + paths: + - ".github/workflows/bcr.yml" + - ".github/workflows/publish-bcr.yml" + - "bcr/**" + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + validate: + name: Validate ${{ matrix.name }} + runs-on: ${{ matrix.runner }} + strategy: + fail-fast: false + matrix: + include: + - name: macOS ARM64 + runner: macos-15 + - name: Linux AMD64 + runner: ubuntu-24.04-16core + - name: Linux ARM64 + runner: ubuntu-24.04-arm + + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + + - name: Setup Bazel + uses: bazel-contrib/setup-bazel@c5acdfb288317d0b5c0bbd7a396a3dc868bb0f86 + with: + bazelisk-cache: true + disk-cache: ${{ github.workflow }}-${{ matrix.runner }} + repository-cache: true + + - name: Validate overlay + run: | + set -euo pipefail + + version="$(jq -r '.versions[-1]' bcr/modules/codescythe/metadata.json)" + module="bcr/modules/codescythe/$version" + cmp "$module/MODULE.bazel" "$module/overlay/MODULE.bazel" + + node -e ' + const fs = require("node:fs"); + const crypto = require("node:crypto"); + const root = process.argv[1]; + const source = JSON.parse(fs.readFileSync(`${root}/source.json`)); + for (const [name, expected] of Object.entries(source.overlay)) { + const content = fs.readFileSync(`${root}/overlay/${name}`); + const actual = `sha256-${crypto.createHash("sha256").update(content).digest("base64")}`; + if (actual !== expected) throw new Error(`${name}: ${actual} !== ${expected}`); + } + ' "$module" + + consumer="$RUNNER_TEMP/codescythe-bcr" + mkdir -p "$consumer" + printf 'module(name = "codescythe_bcr_validation")\nbazel_dep(name = "codescythe", version = "%s")\n' \ + "$version" > "$consumer/MODULE.bazel" + touch "$consumer/BUILD.bazel" + cd "$consumer" + + bazel run \ + --lockfile_mode=off \ + --registry="file://$GITHUB_WORKSPACE/bcr" \ + --registry=https://bcr.bazel.build \ + @codescythe//:codescythe -- --version diff --git a/.github/workflows/cli-release.yml b/.github/workflows/cli-release.yml index 34cfec3..f9e8436 100644 --- a/.github/workflows/cli-release.yml +++ b/.github/workflows/cli-release.yml @@ -201,3 +201,11 @@ jobs: release/codescythe-linux-arm64 \ release/checksums.txt \ --clobber + + publish-to-bcr: + name: Publish BCR overlay + needs: release + uses: ./.github/workflows/publish-bcr.yml + permissions: + contents: read + secrets: inherit diff --git a/.github/workflows/publish-bcr.yml b/.github/workflows/publish-bcr.yml new file mode 100644 index 0000000..5e667b3 --- /dev/null +++ b/.github/workflows/publish-bcr.yml @@ -0,0 +1,108 @@ +name: Publish BCR overlay + +on: + workflow_call: + inputs: + version: + required: false + type: string + workflow_dispatch: + inputs: + version: + description: "Checked-in Codescythe module version" + required: false + type: string + +permissions: + contents: read + +jobs: + publish: + runs-on: ubuntu-24.04-16core + + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + persist-credentials: false + + - name: Checkout Bazel Central Registry + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + repository: bazelbuild/bazel-central-registry + path: bazel-central-registry + persist-credentials: false + + - name: Stage registry entry + id: module + env: + REQUESTED_VERSION: ${{ inputs.version }} + run: | + set -euo pipefail + + source=bcr/modules/codescythe + version="${REQUESTED_VERSION:-$(jq -r '.versions[-1]' "$source/metadata.json")}" + target=bazel-central-registry/modules/codescythe + test -d "$source/$version" + mkdir -p "$target" + + if [[ -f "$target/metadata.json" ]]; then + jq --slurp \ + '.[0] as $current | .[1] | .versions = (($current.versions + .versions) | unique)' \ + "$target/metadata.json" "$source/metadata.json" > "$target/metadata.json.tmp" + mv "$target/metadata.json.tmp" "$target/metadata.json" + else + cp "$source/metadata.json" "$target/metadata.json" + fi + + cp -R "$source/$version" "$target/$version" + echo "version=$version" >> "$GITHUB_OUTPUT" + + - name: Publish registry branch + id: publish + env: + BCR_PUBLISH_TOKEN: ${{ secrets.RELEASE_TOKEN }} + VERSION: ${{ steps.module.outputs.version }} + run: | + set -euo pipefail + + branch="codescythe-$VERSION" + registry=bazel-central-registry + git -C "$registry" checkout -b "$branch" + git -C "$registry" add modules/codescythe + git -C "$registry" \ + -c user.name=pplx-oss \ + -c user.email=ossmaintainers@perplexity.ai \ + commit -m "codescythe@$VERSION" + git -C "$registry" remote add publish \ + "https://x-access-token:$BCR_PUBLISH_TOKEN@github.com/perplexityai/bazel-central-registry.git" + git -C "$registry" push --force publish "$branch" + echo "branch=$branch" >> "$GITHUB_OUTPUT" + + - name: Open BCR pull request + env: + GH_TOKEN: ${{ secrets.RELEASE_TOKEN }} + VERSION: ${{ steps.module.outputs.version }} + BRANCH: ${{ steps.publish.outputs.branch }} + run: | + set -euo pipefail + + pr_url="$(gh api \ + --method GET \ + repos/bazelbuild/bazel-central-registry/pulls \ + -f state=open \ + -f "head=perplexityai:$BRANCH" \ + --jq '.[0].html_url')" + + if [[ -z "$pr_url" ]]; then + pr_url="$(gh api \ + --method POST \ + repos/bazelbuild/bazel-central-registry/pulls \ + -f "title=codescythe@$VERSION" \ + -f "head=perplexityai:$BRANCH" \ + -f base=main \ + -f body='Publish the Codescythe binary toolchain overlay.' \ + --jq .html_url)" + fi + + echo "$pr_url" >> "$GITHUB_STEP_SUMMARY" diff --git a/README.md b/README.md index 9a696cb..fa7c9d8 100644 --- a/README.md +++ b/README.md @@ -418,6 +418,28 @@ flowchart LR n1 -->|"named import #bazel_generated/client:client"| n0 ``` +## Bazel + +Add the published toolchain module to `MODULE.bazel`: + +```starlark +bazel_dep(name = "codescythe", version = "0.10.1") +``` + +Run the binary selected for your execution platform: + +```sh +bazel run @codescythe//:codescythe -- --help +``` + +The toolchain supports macOS ARM64, Linux AMD64, and Linux ARM64. Custom rules +can request `@codescythe//:toolchain_type` and access +`ctx.toolchains["@codescythe//:toolchain_type"].codescythe`. + +Codescythe must inspect the complete configured source tree, including files +unreachable from Bazel targets. Do not use a `deps` closure or aspect as its +source inventory. + ## Contributing See [CONTRIBUTING.md](CONTRIBUTING.md) for the repository layout, architecture, diff --git a/bcr/bazel_registry.json b/bcr/bazel_registry.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/bcr/bazel_registry.json @@ -0,0 +1 @@ +{} diff --git a/bcr/modules/codescythe/0.10.1/MODULE.bazel b/bcr/modules/codescythe/0.10.1/MODULE.bazel new file mode 100644 index 0000000..f9c739d --- /dev/null +++ b/bcr/modules/codescythe/0.10.1/MODULE.bazel @@ -0,0 +1,12 @@ +module( + name = "codescythe", + version = "0.10.1", + bazel_compatibility = [">=8.5.0"], +) + +bazel_dep(name = "platforms", version = "1.1.0") + +codescythe = use_extension("//:extensions.bzl", "codescythe") +use_repo(codescythe, "codescythe_toolchains") + +register_toolchains("@codescythe_toolchains//:all") diff --git a/bcr/modules/codescythe/0.10.1/overlay/BUILD.bazel b/bcr/modules/codescythe/0.10.1/overlay/BUILD.bazel new file mode 100644 index 0000000..94837c8 --- /dev/null +++ b/bcr/modules/codescythe/0.10.1/overlay/BUILD.bazel @@ -0,0 +1,7 @@ +load(":toolchain.bzl", "codescythe_binary") + +package(default_visibility = ["//visibility:public"]) + +toolchain_type(name = "toolchain_type") + +codescythe_binary(name = "codescythe") diff --git a/bcr/modules/codescythe/0.10.1/overlay/MODULE.bazel b/bcr/modules/codescythe/0.10.1/overlay/MODULE.bazel new file mode 100644 index 0000000..f9c739d --- /dev/null +++ b/bcr/modules/codescythe/0.10.1/overlay/MODULE.bazel @@ -0,0 +1,12 @@ +module( + name = "codescythe", + version = "0.10.1", + bazel_compatibility = [">=8.5.0"], +) + +bazel_dep(name = "platforms", version = "1.1.0") + +codescythe = use_extension("//:extensions.bzl", "codescythe") +use_repo(codescythe, "codescythe_toolchains") + +register_toolchains("@codescythe_toolchains//:all") diff --git a/bcr/modules/codescythe/0.10.1/overlay/extensions.bzl b/bcr/modules/codescythe/0.10.1/overlay/extensions.bzl new file mode 100644 index 0000000..d8f07b5 --- /dev/null +++ b/bcr/modules/codescythe/0.10.1/overlay/extensions.bzl @@ -0,0 +1,115 @@ +"""Download and register platform-specific Codescythe binaries.""" + +_PLATFORMS = { + "darwin_arm64": struct( + asset = "codescythe-darwin-arm64", + constraints = ["@platforms//os:macos", "@platforms//cpu:arm64"], + ), + "linux_amd64": struct( + asset = "codescythe-linux-amd64", + constraints = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + ), + "linux_arm64": struct( + asset = "codescythe-linux-arm64", + constraints = ["@platforms//os:linux", "@platforms//cpu:arm64"], + ), +} + +def _codescythe_repository_impl(repository_ctx): + release_url = "https://github.com/perplexityai/codescythe/releases/download/codescythe_cli_v{}".format(repository_ctx.attr.version) + repository_ctx.download( + url = release_url + "/checksums.txt", + output = "checksums.txt", + ) + + checksum = None + for line in repository_ctx.read("checksums.txt").splitlines(): + fields = [field for field in line.split(" ") if field] + if len(fields) == 2 and fields[1] == repository_ctx.attr.asset: + checksum = fields[0] + break + + if checksum == None: + fail("No checksum found for {} in release {}".format( + repository_ctx.attr.asset, + repository_ctx.attr.version, + )) + + repository_ctx.download( + url = release_url + "/" + repository_ctx.attr.asset, + output = "codescythe", + sha256 = checksum, + executable = True, + ) + repository_ctx.file( + "BUILD.bazel", + 'exports_files(["codescythe"], visibility = ["//visibility:public"])\n', + ) + +_codescythe_repository = repository_rule( + implementation = _codescythe_repository_impl, + attrs = { + "asset": attr.string(mandatory = True), + "version": attr.string(mandatory = True), + }, +) + +def _codescythe_toolchains_repository_impl(repository_ctx): + lines = [ + 'load("@codescythe//:toolchain.bzl", "codescythe_toolchain")', + "", + 'package(default_visibility = ["//visibility:public"])', + "", + ] + + for name, platform in _PLATFORMS.items(): + lines.extend([ + "codescythe_toolchain(", + ' name = "{}_toolchain_impl",'.format(name), + ' codescythe = "@codescythe_{}//:codescythe",'.format(name), + ")", + "", + "toolchain(", + ' name = "{}_toolchain",'.format(name), + " exec_compatible_with = {},".format(repr(platform.constraints)), + ' toolchain = ":{}_toolchain_impl",'.format(name), + ' toolchain_type = "@codescythe//:toolchain_type",', + ")", + "", + ]) + + repository_ctx.file("BUILD.bazel", "\n".join(lines)) + +_codescythe_toolchains_repository = repository_rule( + implementation = _codescythe_toolchains_repository_impl, +) + +def _codescythe_impl(module_ctx): + version = None + for module in module_ctx.modules: + if module.name == "codescythe": + version = module.version + + for module in module_ctx.modules: + for settings in module.tags.toolchain: + if settings.version: + version = settings.version + + if not version: + fail("Could not determine the Codescythe release version") + + for name, platform in _PLATFORMS.items(): + _codescythe_repository( + name = "codescythe_" + name, + asset = platform.asset, + version = version, + ) + + _codescythe_toolchains_repository(name = "codescythe_toolchains") + +codescythe = module_extension( + implementation = _codescythe_impl, + tag_classes = { + "toolchain": tag_class(attrs = {"version": attr.string()}), + }, +) diff --git a/bcr/modules/codescythe/0.10.1/overlay/toolchain.bzl b/bcr/modules/codescythe/0.10.1/overlay/toolchain.bzl new file mode 100644 index 0000000..7b28264 --- /dev/null +++ b/bcr/modules/codescythe/0.10.1/overlay/toolchain.bzl @@ -0,0 +1,37 @@ +"""Codescythe binary toolchain.""" + +def _codescythe_toolchain_impl(ctx): + return [platform_common.ToolchainInfo( + codescythe = ctx.executable.codescythe, + )] + +codescythe_toolchain = rule( + implementation = _codescythe_toolchain_impl, + attrs = { + "codescythe": attr.label( + allow_single_file = True, + cfg = "exec", + executable = True, + mandatory = True, + ), + }, +) + +def _codescythe_binary_impl(ctx): + codescythe = ctx.toolchains["//:toolchain_type"].codescythe + executable = ctx.actions.declare_file(ctx.label.name) + ctx.actions.symlink( + output = executable, + target_file = codescythe, + is_executable = True, + ) + return [DefaultInfo( + executable = executable, + runfiles = ctx.runfiles(files = [codescythe]), + )] + +codescythe_binary = rule( + implementation = _codescythe_binary_impl, + executable = True, + toolchains = ["//:toolchain_type"], +) diff --git a/bcr/modules/codescythe/0.10.1/presubmit.yml b/bcr/modules/codescythe/0.10.1/presubmit.yml new file mode 100644 index 0000000..ddf4e34 --- /dev/null +++ b/bcr/modules/codescythe/0.10.1/presubmit.yml @@ -0,0 +1,13 @@ +matrix: + platform: + - macos_arm64 + - ubuntu2204 + - ubuntu2204_arm64 + bazel: ["8.x", "9.x"] +tasks: + build_binary: + name: Build Codescythe binary + platform: ${{ platform }} + bazel: ${{ bazel }} + build_targets: + - "@codescythe//:codescythe" diff --git a/bcr/modules/codescythe/0.10.1/source.json b/bcr/modules/codescythe/0.10.1/source.json new file mode 100644 index 0000000..17a57f1 --- /dev/null +++ b/bcr/modules/codescythe/0.10.1/source.json @@ -0,0 +1,11 @@ +{ + "url": "https://github.com/perplexityai/codescythe/archive/refs/tags/codescythe_cli_v0.10.1.tar.gz", + "integrity": "sha256-LeLiBjtSWW/tQVXOAa6eDQI4MmBolxIYtc0ukRCW5lQ=", + "strip_prefix": "codescythe-codescythe_cli_v0.10.1", + "overlay": { + "BUILD.bazel": "sha256-Xvy9R+IqlTF1S7QTvE0DEDgB9LUSrQJiFMVGlo5Ymns=", + "MODULE.bazel": "sha256-DF6Qg9DJ35CrEQuQU84KFDdiUf7Bb294pRgKENiX0Uk=", + "extensions.bzl": "sha256-kkmFVSOtgsRGdmekp8RMXX5XTKBf+j6yEnV41dVGgOw=", + "toolchain.bzl": "sha256-/UqULRt2DiSc3JR9Dj+Le8/ka0OY7vbm526LL57Lpps=" + } +} diff --git a/bcr/modules/codescythe/metadata.json b/bcr/modules/codescythe/metadata.json new file mode 100644 index 0000000..205f057 --- /dev/null +++ b/bcr/modules/codescythe/metadata.json @@ -0,0 +1,19 @@ +{ + "homepage": "https://github.com/perplexityai/codescythe", + "maintainers": [ + { + "email": "holevietlong@gmail.com", + "github": "longlho", + "github_user_id": 198255, + "name": "Long Ho" + }, + { + "email": "ossmaintainers@perplexity.ai", + "github": "pplx-oss", + "github_user_id": 287052873 + } + ], + "repository": ["github:perplexityai/codescythe"], + "versions": ["0.10.1"], + "yanked_versions": {} +} From f84506d13dc144c8a42444d5c8db9a68e9d245ff Mon Sep 17 00:00:00 2001 From: Long Ho Date: Sun, 23 Aug 2026 13:18:33 +0700 Subject: [PATCH 2/2] fix(bazel): use dedicated BCR publishing token --- .github/workflows/publish-bcr.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-bcr.yml b/.github/workflows/publish-bcr.yml index 5e667b3..4c9d47b 100644 --- a/.github/workflows/publish-bcr.yml +++ b/.github/workflows/publish-bcr.yml @@ -61,7 +61,7 @@ jobs: - name: Publish registry branch id: publish env: - BCR_PUBLISH_TOKEN: ${{ secrets.RELEASE_TOKEN }} + BCR_PUBLISH_TOKEN: ${{ secrets.BCR_PUBLISH_TOKEN }} VERSION: ${{ steps.module.outputs.version }} run: | set -euo pipefail @@ -81,7 +81,7 @@ jobs: - name: Open BCR pull request env: - GH_TOKEN: ${{ secrets.RELEASE_TOKEN }} + GH_TOKEN: ${{ secrets.BCR_PUBLISH_TOKEN }} VERSION: ${{ steps.module.outputs.version }} BRANCH: ${{ steps.publish.outputs.branch }} run: |