From def08a53130f076173abf9601739da6cf2773824 Mon Sep 17 00:00:00 2001 From: Claudear <262350598+claudear@users.noreply.github.com> Date: Fri, 7 Aug 2026 15:08:10 +0000 Subject: [PATCH 1/3] fix(release): publish APT repo and Homebrew tap to abnegate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `publish-apt` job derived its clone URL from `github.repository_owner`, which resolves to `appwrite` now that claudear lives under the Appwrite org. `appwrite/apt-repo` does not exist, so every release failed with: fatal: repository 'https://github.com/appwrite/apt-repo.git/' not found The APT repo is hosted at `abnegate/apt-repo` — the same host the README tells users to install from (`abnegate.github.io/apt-repo`). The Homebrew tap has the identical defect: `appwrite/homebrew-tap` 404s while `abnegate/homebrew-tap` is the tap the README documents (`brew tap abnegate/tap`). Both clone URLs are now pinned to `abnegate`. The formula template's `{{REPO_OWNER}}` placeholder is left alone — it builds release *download* URLs, which do point at the source repo. Adds tests that pin both workflow push targets to the owner documented in the README install instructions, so the two cannot drift apart again. Co-Authored-By: Claude Opus 5 --- .github/workflows/release.yml | 8 ++- tests/release_workflow.rs | 121 ++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 tests/release_workflow.rs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 51b3bf89..1fbf9ea0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -171,7 +171,9 @@ jobs: env: HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} run: | - git clone https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/${{ github.repository_owner }}/homebrew-tap.git + # The tap is hosted under abnegate, not this repo's owner, so it + # cannot be derived from github.repository_owner. + git clone https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/abnegate/homebrew-tap.git mkdir -p homebrew-tap/Formula cp claudear.rb homebrew-tap/Formula/ cd homebrew-tap @@ -272,7 +274,9 @@ jobs: env: APT_REPO_TOKEN: ${{ secrets.APT_REPO_TOKEN }} run: | - git clone https://x-access-token:${APT_REPO_TOKEN}@github.com/${{ github.repository_owner }}/apt-repo.git + # The APT repo is hosted under abnegate, not this repo's owner, so it + # cannot be derived from github.repository_owner. + git clone https://x-access-token:${APT_REPO_TOKEN}@github.com/abnegate/apt-repo.git - name: Update APT repository env: diff --git a/tests/release_workflow.rs b/tests/release_workflow.rs new file mode 100644 index 00000000..23e5be0e --- /dev/null +++ b/tests/release_workflow.rs @@ -0,0 +1,121 @@ +//! Guards the release workflow's package-repository targets. +//! +//! The APT repo and Homebrew tap are hosted under a different owner than the +//! `claudear` source repo, so `github.repository_owner` resolves to the wrong +//! org and the publish jobs fail with "repository not found". These tests pin +//! the workflow's push targets to the owner documented in the README install +//! instructions, so the two can never drift apart again. + +use std::fs; + +fn read(relative: &str) -> String { + let path = format!("{}/{relative}", env!("CARGO_MANIFEST_DIR")); + fs::read_to_string(&path).unwrap_or_else(|e| panic!("failed to read {path}: {e}")) +} + +/// Owner of the APT repository users are told to install from, e.g. `abnegate` +/// in `https://abnegate.github.io/apt-repo`. +fn documented_apt_owner(readme: &str) -> String { + let before = readme + .split_once(".github.io/apt-repo") + .expect("README should document the APT repository URL") + .0; + + before + .rsplit_once("https://") + .expect("the APT repository URL should be absolute") + .1 + .to_string() +} + +/// Owner of the Homebrew tap users are told to install from, e.g. `abnegate` +/// in `brew tap abnegate/tap`. +fn documented_tap_owner(readme: &str) -> String { + let tap = readme + .split_once("brew tap ") + .expect("README should document the Homebrew tap") + .1 + .lines() + .next() + .expect("the tap line should not be empty") + .trim(); + + tap.split_once('/') + .expect("the tap should be written as owner/name") + .0 + .to_string() +} + +#[test] +fn apt_publish_job_clones_the_documented_apt_repository() { + let workflow = read(".github/workflows/release.yml"); + let owner = documented_apt_owner(&read("README.md")); + + let expected = format!("github.com/{owner}/apt-repo.git"); + assert!( + workflow.contains(&expected), + "release.yml should clone the APT repo from {expected}, since that is \ + where the README tells users to install from" + ); +} + +#[test] +fn apt_publish_job_does_not_use_the_source_repository_owner() { + let workflow = read(".github/workflows/release.yml"); + + let clone_line = workflow + .lines() + .find(|line| line.contains("apt-repo.git")) + .expect("release.yml should clone the APT repository"); + + assert!( + !clone_line.contains("github.repository_owner"), + "the APT repo is not owned by the source repository's owner, so \ + `github.repository_owner` resolves to a non-existent repo: {}", + clone_line.trim() + ); +} + +#[test] +fn homebrew_publish_job_clones_the_documented_tap() { + let workflow = read(".github/workflows/release.yml"); + let owner = documented_tap_owner(&read("README.md")); + + let expected = format!("github.com/{owner}/homebrew-tap.git"); + assert!( + workflow.contains(&expected), + "release.yml should clone the Homebrew tap from {expected}, since that \ + is where the README tells users to tap from" + ); +} + +#[test] +fn homebrew_publish_job_does_not_use_the_source_repository_owner() { + let workflow = read(".github/workflows/release.yml"); + + let clone_line = workflow + .lines() + .find(|line| line.contains("homebrew-tap.git")) + .expect("release.yml should clone the Homebrew tap"); + + assert!( + !clone_line.contains("github.repository_owner"), + "the Homebrew tap is not owned by the source repository's owner, so \ + `github.repository_owner` resolves to a non-existent repo: {}", + clone_line.trim() + ); +} + +/// The formula's download URLs point at the *source* repo's releases, which +/// really is `github.repository_owner` — make sure the fix above was not +/// over-applied to it. +#[test] +fn formula_template_still_uses_the_source_repository_owner() { + let workflow = read(".github/workflows/release.yml"); + + assert!( + workflow.contains("s/{{REPO_OWNER}}/${{ github.repository_owner }}/g"), + "the Homebrew formula downloads release assets from the source repo, \ + so the REPO_OWNER placeholder must stay bound to github.repository_owner" + ); +} From 6ff5ca0aff8a24ca371e57c14d632686ea7bc275 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k <83803257+ArnabChatterjee20k@users.noreply.github.com> Date: Fri, 7 Aug 2026 21:17:39 +0530 Subject: [PATCH 2/3] Delete tests/release_workflow.rs --- tests/release_workflow.rs | 121 -------------------------------------- 1 file changed, 121 deletions(-) delete mode 100644 tests/release_workflow.rs diff --git a/tests/release_workflow.rs b/tests/release_workflow.rs deleted file mode 100644 index 23e5be0e..00000000 --- a/tests/release_workflow.rs +++ /dev/null @@ -1,121 +0,0 @@ -//! Guards the release workflow's package-repository targets. -//! -//! The APT repo and Homebrew tap are hosted under a different owner than the -//! `claudear` source repo, so `github.repository_owner` resolves to the wrong -//! org and the publish jobs fail with "repository not found". These tests pin -//! the workflow's push targets to the owner documented in the README install -//! instructions, so the two can never drift apart again. - -use std::fs; - -fn read(relative: &str) -> String { - let path = format!("{}/{relative}", env!("CARGO_MANIFEST_DIR")); - fs::read_to_string(&path).unwrap_or_else(|e| panic!("failed to read {path}: {e}")) -} - -/// Owner of the APT repository users are told to install from, e.g. `abnegate` -/// in `https://abnegate.github.io/apt-repo`. -fn documented_apt_owner(readme: &str) -> String { - let before = readme - .split_once(".github.io/apt-repo") - .expect("README should document the APT repository URL") - .0; - - before - .rsplit_once("https://") - .expect("the APT repository URL should be absolute") - .1 - .to_string() -} - -/// Owner of the Homebrew tap users are told to install from, e.g. `abnegate` -/// in `brew tap abnegate/tap`. -fn documented_tap_owner(readme: &str) -> String { - let tap = readme - .split_once("brew tap ") - .expect("README should document the Homebrew tap") - .1 - .lines() - .next() - .expect("the tap line should not be empty") - .trim(); - - tap.split_once('/') - .expect("the tap should be written as owner/name") - .0 - .to_string() -} - -#[test] -fn apt_publish_job_clones_the_documented_apt_repository() { - let workflow = read(".github/workflows/release.yml"); - let owner = documented_apt_owner(&read("README.md")); - - let expected = format!("github.com/{owner}/apt-repo.git"); - assert!( - workflow.contains(&expected), - "release.yml should clone the APT repo from {expected}, since that is \ - where the README tells users to install from" - ); -} - -#[test] -fn apt_publish_job_does_not_use_the_source_repository_owner() { - let workflow = read(".github/workflows/release.yml"); - - let clone_line = workflow - .lines() - .find(|line| line.contains("apt-repo.git")) - .expect("release.yml should clone the APT repository"); - - assert!( - !clone_line.contains("github.repository_owner"), - "the APT repo is not owned by the source repository's owner, so \ - `github.repository_owner` resolves to a non-existent repo: {}", - clone_line.trim() - ); -} - -#[test] -fn homebrew_publish_job_clones_the_documented_tap() { - let workflow = read(".github/workflows/release.yml"); - let owner = documented_tap_owner(&read("README.md")); - - let expected = format!("github.com/{owner}/homebrew-tap.git"); - assert!( - workflow.contains(&expected), - "release.yml should clone the Homebrew tap from {expected}, since that \ - is where the README tells users to tap from" - ); -} - -#[test] -fn homebrew_publish_job_does_not_use_the_source_repository_owner() { - let workflow = read(".github/workflows/release.yml"); - - let clone_line = workflow - .lines() - .find(|line| line.contains("homebrew-tap.git")) - .expect("release.yml should clone the Homebrew tap"); - - assert!( - !clone_line.contains("github.repository_owner"), - "the Homebrew tap is not owned by the source repository's owner, so \ - `github.repository_owner` resolves to a non-existent repo: {}", - clone_line.trim() - ); -} - -/// The formula's download URLs point at the *source* repo's releases, which -/// really is `github.repository_owner` — make sure the fix above was not -/// over-applied to it. -#[test] -fn formula_template_still_uses_the_source_repository_owner() { - let workflow = read(".github/workflows/release.yml"); - - assert!( - workflow.contains("s/{{REPO_OWNER}}/${{ github.repository_owner }}/g"), - "the Homebrew formula downloads release assets from the source repo, \ - so the REPO_OWNER placeholder must stay bound to github.repository_owner" - ); -} From 29281891216801435d12a634a943e0656d5e817e Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Mon, 10 Aug 2026 10:33:58 +0530 Subject: [PATCH 3/3] removed redundant comments --- .github/workflows/release.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1fbf9ea0..eb72c1f7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -171,8 +171,6 @@ jobs: env: HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} run: | - # The tap is hosted under abnegate, not this repo's owner, so it - # cannot be derived from github.repository_owner. git clone https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/abnegate/homebrew-tap.git mkdir -p homebrew-tap/Formula cp claudear.rb homebrew-tap/Formula/ @@ -274,8 +272,6 @@ jobs: env: APT_REPO_TOKEN: ${{ secrets.APT_REPO_TOKEN }} run: | - # The APT repo is hosted under abnegate, not this repo's owner, so it - # cannot be derived from github.repository_owner. git clone https://x-access-token:${APT_REPO_TOKEN}@github.com/abnegate/apt-repo.git - name: Update APT repository