Skip to content

Set up from a terminal

The tutorial sets up the hub and its projects in your browser. Every step works in a terminal as well, with the same checks and the same results on GitHub. You can mix both: the browser shows what the terminal did.

Go to a clone of your tap and run init:

Terminal window
cd homebrew-tap
bunx @doguyilmaz/tapster init

init walks through five parts. Each part can run again and skips what is done. If anything stops it, run the same command again.

Nothing to answer here. tapster:

  • creates a tapster environment that only the main branch can open. Your keys go into it;
  • adds a ruleset that keeps main from being deleted or force-pushed, by anyone including you;
  • lets the hub’s workflows run only GitHub’s own actions and tapster’s, each pinned by commit;
  • makes the workflows’ default token read-only.

Press Enter for yes. Answer n if you skipped the Apple step. tapster then leaves out the Apple parts below, and tapster add later leaves the macOS builds out of each project’s entry.

The hub needs a GitHub App to write releases to your projects. tapster opens a page in your browser that shows the App and the permissions it asks for.

  1. Read the page and click Continue to GitHub.
  2. GitHub shows the same App. Click Create GitHub App.
  3. GitHub sends you back to a page that says Your tapster App is created. Close it.

tapster then opens the App’s install page:

  1. Choose Only select repositories.
  2. Pick the project you will add in the next step. You can add more projects later.
  3. Never pick the hub itself. The App can write to every repository it is installed on. The hub holds your keys.
  4. Click Install.

Drag each file from Finder into the terminal when tapster asks for it, then press Enter.

tapster opens the .p12 with your password to check that it is a Developer ID Application certificate that has not expired. The password is not shown while you type.

On a Mac, tapster asks Apple whether the key works before it stores it. Elsewhere Apple checks it at the first release.

tapster keeps files that already exist, such as your own README. The workflow pins the exact tapster you ran by its commit.

Commit and push them:

Terminal window
git add -A
git commit -m "Set up tapster"
git push

The hub is ready. It has no projects yet, so its runs find nothing to do.

Go to a clone of the project you want to publish and run add:

Terminal window
cd my-tool
bunx @doguyilmaz/tapster add

The first time, tapster asks which hub publishes the project and remembers the answer in the clone:

tapster recognizes three kinds of projects. Each line it prints starts with - and says what it did.

  • Go with GoReleaser (a .goreleaser.yaml next to go.mod): tapster turns on draft releases, names the checksum file checksums.txt and removes notarize, homebrew_casks, brews and scoops, because the hub does those now. In the workflow that runs GoReleaser (release.yml or the file you name with --workflow), it adds a step that attests the archives. See Move a GoReleaser project.
  • Bun (a package.json with bin and a bun.lock): tapster writes .github/workflows/release.yml. It builds every platform in a job that can only read the repository. A second job attests the archives and opens the draft. See Bun projects.
  • A Mac app with Sparkle: see Mac apps with Sparkle, which has its own order of steps.

Every release workflow also gets a step named Ring the tapster hub. It does nothing until you add the doorbell.

This keeps a stolen App key from tagging code for your hub to sign. The rules cover every branch too: only you can push to the project now, so every push of yours shows the same note. Collaborators and bots such as Renovate or release-please can no longer push branches. Two cases have an option:

tapster writes the project’s entry for the hub’s tapster.yml and opens a pull request on the hub with it:

If the repository’s GitHub description is one that Homebrew would reject, tapster says so and suggests a better one in the entry. Homebrew wants a short description that starts with a capital letter and has no full stop at the end.

If you picked this project when you created the hub, skip it. Otherwise open the link and click Install.

tapster commits nothing. When it ends with Review the changes with git diff, then commit and push them., do this:

  • Merge the pull request on your hub.

  • Open the install link if tapster printed one for a project the App does not reach yet.

  • Review the changes in the project, then commit and push them:

    Terminal window
    git diff
    git add -A
    git commit -m "Release through tapster"
    git push
  • Release. tapster’s last line is a gh command that tags the latest commit of the default branch on GitHub, with the next patch version after the highest tag there:

    Terminal window
    gh api --method POST repos/you/my-tool/git/refs -f ref=refs/tags/v0.2.2 -f sha="$(gh api repos/you/my-tool/commits/main --jq 'if (.commit.message | test("(?i)\\[(skip ci|ci skip|no ci|skip actions|actions skip)\\]")) or ([.commit.message | splits("\\r?\\n[ \\t]*\\r?\\n") | select(test("\\S"))] | length > 1 and (last | test("(?im)^skip-checks:\\s*true\\s*$"))) then error("the latest commit of main carries a skip marker, so a tag on it may not start the release workflow") else .sha end')"

    It tags GitHub’s copy, not your clone, so a clone that is behind or on another branch cannot put the tag on the wrong commit. It stops when that commit’s message carries a skip marker such as [skip ci], because GitHub would start no release workflow for its tag. A project whose workflow tags by itself (--auto-tag) gets no command.

If you run tapster add again later, it changes no file that is already right. When the hub entry lacks what the project ships now, such as an app in its macOS archives, it prints the lines it would add and proposes them in a pull request on the hub that changes no other line. It never removes or rewrites what you wrote. What it cannot derive, such as entitlements, it lists for you to write by hand.

tapster doctor in a clone of the hub runs the same checks as Health in the browser and names the command that fixes each finding.