diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 30a72e8..e81dba7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -161,3 +161,100 @@ jobs: name: binaries path: dist/* retention-days: 30 + + homebrew: + name: Update Homebrew tap + runs-on: ubuntu-latest + needs: build + if: startsWith(github.ref, 'refs/tags/') + env: + # Set HOMEBREW_TAP_TOKEN (a fine-grained PAT with push access to the tap + # repo) to enable this job. Without it the job no-ops, so releases from + # forks or before the secret is configured never fail. HOMEBREW_TAP_REPO + # is the `homebrew-` repository backing `brew install /tap/sshx`. + HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} + HOMEBREW_TAP_REPO: talkincode/homebrew-tap + steps: + - name: Download release artifacts + if: ${{ env.HOMEBREW_TAP_TOKEN != '' }} + uses: actions/download-artifact@v4 + with: + name: binaries + path: dist-artifacts + + - name: Render and push formula + if: ${{ env.HOMEBREW_TAP_TOKEN != '' }} + run: | + set -euo pipefail + TAG="${GITHUB_REF#refs/tags/}" # e.g. v1.2.0 + VERSION="${TAG#v}" # e.g. 1.2.0 + BASE_URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${TAG}" + CHECKSUMS="dist-artifacts/checksums.txt" + + # Look up the sha256 for a given archive name from checksums.txt + # (format: " ", as produced by `sha256sum *`). + sha() { + local hash + hash="$(awk -v f="$1" '$2 == f { print $1; exit }' "$CHECKSUMS")" + [ -n "$hash" ] || { echo "missing checksum for $1" >&2; exit 1; } + echo "$hash" + } + + DARWIN_ARM64_SHA="$(sha sshx-darwin-arm64.tar.gz)" + DARWIN_AMD64_SHA="$(sha sshx-darwin-amd64.tar.gz)" + LINUX_ARM64_SHA="$(sha sshx-linux-arm64.tar.gz)" + LINUX_AMD64_SHA="$(sha sshx-linux-amd64.tar.gz)" + + git clone --depth 1 \ + "https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/${HOMEBREW_TAP_REPO}.git" tap + mkdir -p tap/Formula + + cat > tap/Formula/sshx.rb < "sshx" + end + + test do + assert_match version.to_s, shell_output("#{bin}/sshx --version") + end + end + EOF + + cd tap + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add Formula/sshx.rb + if git diff --cached --quiet; then + echo "Formula already up to date for ${VERSION}" + else + git commit -m "sshx ${VERSION}" + git push + fi diff --git a/AGENT.md b/AGENT.md index 739213c..db08dd9 100644 --- a/AGENT.md +++ b/AGENT.md @@ -284,7 +284,8 @@ unless the mission in §1–§3 is formally revised. `scripts/release-note.sh` (`make renote`). - `release.yml` cross-compiles and publishes artifacts on tag push. - Install paths: `go install`, `install.sh` (Linux/macOS), `install.ps1` - (Windows), or manual binary download. + (Windows), a Homebrew tap (`talkincode/homebrew-tap`, opt-in via the + `HOMEBREW_TAP_TOKEN` secret), or manual binary download. ## 12. Guidelines for AI Coding Agents diff --git a/CHANGELOG.md b/CHANGELOG.md index 5297a1e..91c70e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - An mdBook documentation site with English and Chinese guides for getting started, host management, SFTP, scripting, security, scenarios, and troubleshooting. +- Release automation now publishes/updates a Homebrew tap formula + (`talkincode/homebrew-tap`) on every tagged release, so macOS/Linux users can + `brew install talkincode/tap/sshx`. The step is opt-in via the + `HOMEBREW_TAP_TOKEN` repository secret and no-ops otherwise. ### Changed diff --git a/README.md b/README.md index 536a57c..05ffaf9 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,14 @@ sshx -h=192.168.1.100 "uptime" **Note:** Make sure `$GOPATH/bin` (typically `~/go/bin`) is in your PATH. +### Homebrew (macOS / Linux) + +```bash +brew install talkincode/tap/sshx +``` + +This pulls prebuilt binaries from the [talkincode/homebrew-tap](https://github.com/talkincode/homebrew-tap) repository, updated automatically on every tagged release. + ### One-Line Installation Script #### Linux / macOS diff --git a/README_CN.md b/README_CN.md index 58e9269..88fba6a 100644 --- a/README_CN.md +++ b/README_CN.md @@ -94,6 +94,14 @@ sshx -h=192.168.1.100 "uptime" **注意:** 确保 `$GOPATH/bin`(通常是 `~/go/bin`)在您的 PATH 中。 +### Homebrew(macOS / Linux) + +```bash +brew install talkincode/tap/sshx +``` + +该命令会从 [talkincode/homebrew-tap](https://github.com/talkincode/homebrew-tap) 仓库拉取预编译二进制文件,每次打 tag 发布时自动更新。 + ### 一键安装脚本 #### Linux / macOS diff --git a/RELEASE.md b/RELEASE.md index 25882f4..e80c871 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -67,6 +67,8 @@ After pushing the tag, GitHub Actions will automatically: 5. ✅ Upload all binaries to the Release +6. ✅ Publish/update the Homebrew tap formula (if `HOMEBREW_TAP_TOKEN` is configured; see below) + ### 5. Verify Release Visit the GitHub Releases page to verify: @@ -159,6 +161,47 @@ ls -lh bin/ 2. Verify network connection 3. Review detailed error messages in Actions logs +## Homebrew Tap Publishing + +On every tag push, the `homebrew` job in `.github/workflows/release.yml` renders and +pushes a `Formula/sshx.rb` file to the `talkincode/homebrew-tap` repository, so +users can run: + +```bash +brew install talkincode/tap/sshx +``` + +The formula is built from the `checksums.txt` produced by the `build` job, and +covers `darwin`/`linux` on both `amd64` and `arm64`. Windows has no Homebrew +equivalent, so it is intentionally excluded from the formula. + +### One-time setup + +1. Create (or reuse) a `talkincode/homebrew-tap` repository with a `Formula/` + directory. +2. Generate a fine-grained GitHub Personal Access Token scoped to `Contents: + write` on that repository only. +3. Add it as a repository secret named `HOMEBREW_TAP_TOKEN` in `talkincode/sshx` + (Settings → Secrets and variables → Actions). + +If `HOMEBREW_TAP_TOKEN` is not set, the `homebrew` job no-ops (its steps are +skipped) and the rest of the release is unaffected — this mirrors how the +project treats other optional publish integrations. + +### Verifying a published formula + +```bash +brew tap talkincode/tap +brew install sshx +sshx --version +``` + +Or inspect the rendered formula directly: + +``` +https://github.com/talkincode/homebrew-tap/blob/main/Formula/sshx.rb +``` + ## CI/CD Workflows ### Release Workflow (.github/workflows/release.yml) diff --git a/docs/roadmap.md b/docs/roadmap.md index 2d672d7..e02c742 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -83,7 +83,7 @@ internal/sshclient - 构建、发布和质量守护 - Makefile 提供构建、测试、覆盖率、lint、跨平台编译和安装目标;CI 在 Ubuntu 和 macOS 上使用 Go 1.24 运行测试、race、覆盖率、lint 和安全扫描;release workflow 在 tag push 时构建 Linux、macOS、Windows 产物并生成 checksums。证据:`Makefile`、`.github/workflows/ci.yml`、`.github/workflows/release.yml`、`RELEASE.md`。 + Makefile 提供构建、测试、覆盖率、lint、跨平台编译和安装目标;CI 在 Ubuntu 和 macOS 上使用 Go 1.24 运行测试、race、覆盖率、lint 和安全扫描;release workflow 在 tag push 时构建 Linux、macOS、Windows 产物并生成 checksums,并在配置 `HOMEBREW_TAP_TOKEN` 后自动渲染、推送 Homebrew tap formula(`talkincode/homebrew-tap`)。证据:`Makefile`、`.github/workflows/ci.yml`、`.github/workflows/release.yml`、`RELEASE.md`。 ## 非目标(铁律)