Skip to content

Commit cdaa793

Browse files
committed
feat(homebrew): add a Homebrew tap formula + release job
Add `brew install codellm-devkit/tap/codeanalyzer-python`: - packaging/homebrew/generate_formula.sh emits a formula that depends on `uv` and installs version-pinned wrappers running the published PyPI release via `uvx`. The package is pure-Python with heavy native deps (ray, pandas, numpy), so vendoring every transitive dependency as a Homebrew resource is impractical and pip-at-build-time is blocked by the sandbox; the uv-tool approach keeps the formula tiny and `brew install` sandbox-safe. - release.yml gains a `homebrew` job (needs: release) that regenerates the formula on each tag and pushes it to codellm-devkit/homebrew-tap (requires the HOMEBREW_TAP_TOKEN secret, same as the codeanalyzer-typescript release). - README: Install via Homebrew section; CHANGELOG: Unreleased entry.
1 parent ddd6df4 commit cdaa793

4 files changed

Lines changed: 111 additions & 0 deletions

File tree

.github/workflows/release.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,43 @@ jobs:
136136

137137
- name: Publish to PyPI via Trusted Publishing
138138
run: uv publish
139+
140+
# Regenerate the Homebrew formula and push it to the shared tap. Split into its
141+
# own job (needs: release) so a tap-push failure -- e.g. a missing
142+
# HOMEBREW_TAP_TOKEN -- is isolated from the PyPI and GitHub Release steps above.
143+
# The non-Rust equivalent of what cargo-dist does for you.
144+
homebrew:
145+
needs: release
146+
if: startsWith(github.ref, 'refs/tags/')
147+
runs-on: ubuntu-latest
148+
steps:
149+
- name: Check out code
150+
uses: actions/checkout@v4
151+
152+
- name: Derive version from tag
153+
id: ver
154+
run: echo "version=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT"
155+
156+
- name: Generate Homebrew formula
157+
env:
158+
REPO: ${{ github.repository }}
159+
VERSION: ${{ steps.ver.outputs.version }}
160+
run: |
161+
chmod +x packaging/homebrew/generate_formula.sh
162+
./packaging/homebrew/generate_formula.sh > codeanalyzer-python.rb
163+
cat codeanalyzer-python.rb
164+
165+
- name: Push formula to codellm-devkit/homebrew-tap
166+
env:
167+
TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} # PAT with write access to homebrew-tap
168+
VERSION: ${{ steps.ver.outputs.version }}
169+
run: |
170+
git clone "https://x-access-token:${TAP_TOKEN}@github.com/codellm-devkit/homebrew-tap.git" tap
171+
mkdir -p tap/Formula
172+
cp codeanalyzer-python.rb tap/Formula/codeanalyzer-python.rb
173+
cd tap
174+
git config user.name "github-actions[bot]"
175+
git config user.email "github-actions[bot]@users.noreply.github.com"
176+
git add Formula/codeanalyzer-python.rb
177+
git commit -m "codeanalyzer-python ${VERSION}" || { echo "no formula change"; exit 0; }
178+
git push

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [Unreleased]
9+
10+
### Added
11+
- **Homebrew tap**`brew install codellm-devkit/tap/codeanalyzer-python`. The release workflow auto-generates a formula (`packaging/homebrew/generate_formula.sh`) that installs the pinned PyPI release as an isolated `uv` tool, and pushes it to `codellm-devkit/homebrew-tap`. Because the package is pure-Python with heavy native dependencies (`ray`, `pandas`, `numpy`), the formula depends on `uv` and runs the release via `uvx` rather than vendoring every transitive dependency as a Homebrew resource.
12+
813
## [0.2.0] - 2026-06-20
914

1015
### Added

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ and merges them with the Jedi-derived edges, also backfilling callees Jedi could
3636
- [Prerequisites](#prerequisites)
3737
- [Install via pip (PyPI)](#install-via-pip-pypi)
3838
- [Install via shell script](#install-via-shell-script)
39+
- [Install via Homebrew](#install-via-homebrew)
3940
- [Build from source](#build-from-source)
4041
- [Usage](#usage)
4142
- [Options](#options)
@@ -102,6 +103,15 @@ Install the CLI as an isolated tool with the one-line installer (provisions via
102103
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/codellm-devkit/codeanalyzer-python/releases/latest/download/canpy-installer.sh | sh
103104
```
104105

106+
### Install via Homebrew
107+
108+
```sh
109+
brew install codellm-devkit/tap/codeanalyzer-python
110+
```
111+
112+
The formula depends on [uv](https://docs.astral.sh/uv/) and installs `canpy` as an isolated,
113+
version-pinned uv tool (the package and its dependencies are resolved and cached on first run).
114+
105115
### Build from source
106116

107117
This project uses [uv](https://docs.astral.sh/uv/) for dependency management.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Generate the Homebrew formula for codeanalyzer-python (the `canpy` CLI).
4+
#
5+
# Unlike the codeanalyzer-typescript sibling -- which ships a single self-contained
6+
# binary that the formula just downloads -- codeanalyzer-python is a pure-Python
7+
# package published to PyPI with heavy native dependencies (ray, pandas, numpy).
8+
# Vendoring every transitive dependency as a Homebrew `resource` is impractical
9+
# (ray is not buildable from an sdist), and pip-installing at build time is blocked
10+
# by Homebrew's network sandbox.
11+
#
12+
# So the formula stays tiny: it depends on `uv` and installs version-pinned wrapper
13+
# scripts that run the published PyPI release via `uvx` (uv resolves and caches the
14+
# isolated environment on first run). This keeps `brew install` sandbox-safe (no
15+
# network at build time) while pinning the exact released version.
16+
#
17+
# Usage:
18+
# REPO=codellm-devkit/codeanalyzer-python VERSION=0.2.0 \
19+
# ./generate_formula.sh > codeanalyzer-python.rb
20+
#
21+
set -euo pipefail
22+
23+
REPO="${REPO:?set REPO, e.g. codellm-devkit/codeanalyzer-python}"
24+
VERSION="${VERSION:?set VERSION, e.g. 0.2.0}"
25+
26+
cat <<EOF
27+
# This file is auto-generated by packaging/homebrew/generate_formula.sh on release.
28+
# Do not edit by hand -- changes will be overwritten on the next tag.
29+
class CodeanalyzerPython < Formula
30+
desc "CLDK Python analyzer (canpy) -- emits canonical analysis.json or a Neo4j graph"
31+
homepage "https://github.com/${REPO}"
32+
version "${VERSION}"
33+
license "Apache-2.0"
34+
35+
# codeanalyzer-python is a pure-Python PyPI package with heavy native deps
36+
# (ray, pandas, numpy). Rather than vendor every transitive dependency as a
37+
# Homebrew resource, install the pinned PyPI release as an isolated uv tool;
38+
# uv resolves and caches the environment on first run.
39+
depends_on "uv"
40+
41+
def install
42+
%w[canpy codeanalyzer].each do |exe|
43+
(bin/exe).write <<~SH
44+
#!/bin/bash
45+
exec uvx --from "codeanalyzer-python==#{version}" #{exe} "\$@"
46+
SH
47+
chmod 0755, bin/exe
48+
end
49+
end
50+
51+
test do
52+
assert_match "codeanalyzer-python==#{version}", File.read(bin/"canpy")
53+
assert_predicate bin/"canpy", :executable?
54+
end
55+
end
56+
EOF

0 commit comments

Comments
 (0)