Skip to content

Commit bb0dfb3

Browse files
authored
feat(completions): Add completions command and include in brew formula
1 parent d4c1211 commit bb0dfb3

7 files changed

Lines changed: 120 additions & 46 deletions

File tree

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
name: Publish Homebrew Formula
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
plan:
7+
required: true
8+
type: string
9+
10+
jobs:
11+
publish-homebrew-formula:
12+
runs-on: ubuntu-22.04
13+
env:
14+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
15+
PLAN: ${{ inputs.plan }}
16+
GITHUB_USER: "axo bot"
17+
GITHUB_EMAIL: "admin+bot@axo.dev"
18+
if: ${{ !fromJson(inputs.plan).announcement_is_prerelease || fromJson(inputs.plan).publish_prereleases }}
19+
steps:
20+
- uses: actions/checkout@v6
21+
with:
22+
persist-credentials: true
23+
repository: "hotdata-dev/homebrew-tap"
24+
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
25+
26+
- name: Fetch homebrew formulae
27+
uses: actions/download-artifact@v7
28+
with:
29+
pattern: artifacts-*
30+
path: Formula/
31+
merge-multiple: true
32+
33+
- name: Patch and commit formula files
34+
run: |
35+
git config --global user.name "${GITHUB_USER}"
36+
git config --global user.email "${GITHUB_EMAIL}"
37+
38+
for release in $(echo "$PLAN" | jq --compact-output '.releases[] | select([.artifacts[] | endswith(".rb")] | any)'); do
39+
filename=$(echo "$release" | jq '.artifacts[] | select(endswith(".rb"))' --raw-output)
40+
name=$(echo "$filename" | sed "s/\.rb$//")
41+
version=$(echo "$release" | jq .app_version --raw-output)
42+
43+
export PATH="/home/linuxbrew/.linuxbrew/bin:$PATH"
44+
brew update
45+
brew style --except-cops FormulaAudit/Homepage,FormulaAudit/Desc,FormulaAuditStrict --fix "Formula/${filename}" || true
46+
47+
# Add shell completions generation if not already present
48+
if ! grep -q 'generate_completions_from_executable' "Formula/${filename}"; then
49+
sed -i '/bin\.install "hotdata"/a\ generate_completions_from_executable(bin/"hotdata", "completions")' "Formula/${filename}"
50+
fi
51+
52+
git add "Formula/${filename}"
53+
git commit -m "${name} ${version}"
54+
done
55+
git push
56+
57+
- name: Remove .rb from GitHub Release assets
58+
run: |
59+
TAG=$(echo "$PLAN" | jq -r '.announcement_tag')
60+
if [ -z "$TAG" ] || [ "$TAG" = "null" ]; then
61+
exit 0
62+
fi
63+
for asset in $(gh release view "$TAG" --repo hotdata-dev/hotdata-cli --json assets -q '.assets[].name' | grep '\.rb$'); do
64+
gh release delete-asset "$TAG" "$asset" --repo hotdata-dev/hotdata-cli --yes
65+
done

.github/workflows/release.yml

Lines changed: 11 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -278,61 +278,29 @@ jobs:
278278
279279
gh release create "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file "$RUNNER_TEMP/notes.txt" artifacts/*
280280
281-
publish-homebrew-formula:
281+
custom-publish-homebrew:
282282
needs:
283283
- plan
284284
- host
285-
runs-on: "ubuntu-22.04"
286-
env:
287-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
288-
PLAN: ${{ needs.plan.outputs.val }}
289-
GITHUB_USER: "axo bot"
290-
GITHUB_EMAIL: "admin+bot@axo.dev"
291285
if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }}
292-
steps:
293-
- uses: actions/checkout@v6
294-
with:
295-
persist-credentials: true
296-
repository: "hotdata-dev/homebrew-tap"
297-
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
298-
# So we have access to the formula
299-
- name: Fetch homebrew formulae
300-
uses: actions/download-artifact@v7
301-
with:
302-
pattern: artifacts-*
303-
path: Formula/
304-
merge-multiple: true
305-
# This is extra complex because you can make your Formula name not match your app name
306-
# so we need to find releases with a *.rb file, and publish with that filename.
307-
- name: Commit formula files
308-
run: |
309-
git config --global user.name "${GITHUB_USER}"
310-
git config --global user.email "${GITHUB_EMAIL}"
311-
312-
for release in $(echo "$PLAN" | jq --compact-output '.releases[] | select([.artifacts[] | endswith(".rb")] | any)'); do
313-
filename=$(echo "$release" | jq '.artifacts[] | select(endswith(".rb"))' --raw-output)
314-
name=$(echo "$filename" | sed "s/\.rb$//")
315-
version=$(echo "$release" | jq .app_version --raw-output)
316-
317-
export PATH="/home/linuxbrew/.linuxbrew/bin:$PATH"
318-
brew update
319-
# We avoid reformatting user-provided data such as the app description and homepage.
320-
brew style --except-cops FormulaAudit/Homepage,FormulaAudit/Desc,FormulaAuditStrict --fix "Formula/${filename}" || true
321-
322-
git add "Formula/${filename}"
323-
git commit -m "${name} ${version}"
324-
done
325-
git push
286+
uses: ./.github/workflows/publish-homebrew.yml
287+
with:
288+
plan: ${{ needs.plan.outputs.val }}
289+
secrets: inherit
290+
# publish jobs get escalated permissions
291+
permissions:
292+
"id-token": "write"
293+
"packages": "write"
326294

327295
announce:
328296
needs:
329297
- plan
330298
- host
331-
- publish-homebrew-formula
299+
- custom-publish-homebrew
332300
# use "always() && ..." to allow us to wait for all publish jobs while
333301
# still allowing individual publish jobs to skip themselves (for prereleases).
334302
# "host" however must run to completion, no skipping allowed!
335-
if: ${{ always() && needs.host.result == 'success' && (needs.publish-homebrew-formula.result == 'skipped' || needs.publish-homebrew-formula.result == 'success') }}
303+
if: ${{ always() && needs.host.result == 'success' && (needs.custom-publish-homebrew.result == 'skipped' || needs.custom-publish-homebrew.result == 'success') }}
336304
runs-on: "ubuntu-22.04"
337305
env:
338306
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Cargo.lock

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ rand = "0.8"
2727
sha2 = "0.10"
2828
tiny_http = "0.12"
2929
tabled = { version = "0.20", features = ["ansi"] }
30+
clap_complete = "4"
3031
inquire = "0.9.4"
3132
indicatif = "0.17"
3233
nix = { version = "0.29", features = ["fs"] }

dist-workspace.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,12 @@ ci = "github"
1111
installers = ["shell", "homebrew"]
1212
# Target platforms to build apps for (Rust target-triple syntax)
1313
targets = ["aarch64-apple-darwin", "aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu"]
14-
# A GitHub repo to push Homebrew formulas to
15-
tap = "hotdata-dev/homebrew-tap"
14+
# Customize the Homebrew formula name
1615
formula = "cli"
1716
# Path that installers should place binaries in
1817
install-path = "~/.hotdata/cli"
1918
# Publish jobs to run in CI
20-
publish-jobs = ["homebrew"]
19+
publish-jobs = ["./publish-homebrew"]
2120
# Whether to install an updater program
2221
install-updater = false
2322

src/command.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,30 @@ pub enum Commands {
104104
#[command(subcommand)]
105105
command: Option<JobsCommands>,
106106
},
107+
108+
/// Generate shell completions
109+
Completions {
110+
/// Shell to generate completions for
111+
#[arg(value_enum)]
112+
shell: ShellChoice,
113+
},
114+
}
115+
116+
#[derive(Clone, clap::ValueEnum)]
117+
pub enum ShellChoice {
118+
Bash,
119+
Zsh,
120+
Fish,
121+
}
122+
123+
impl From<ShellChoice> for clap_complete::Shell {
124+
fn from(s: ShellChoice) -> Self {
125+
match s {
126+
ShellChoice::Bash => clap_complete::Shell::Bash,
127+
ShellChoice::Zsh => clap_complete::Shell::Zsh,
128+
ShellChoice::Fish => clap_complete::Shell::Fish,
129+
}
130+
}
107131
}
108132

109133
#[derive(Subcommand)]

src/main.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,13 @@ fn main() {
195195
}
196196
}
197197
}
198+
Commands::Completions { shell } => {
199+
use clap::CommandFactory;
200+
use clap_complete::generate;
201+
let shell: clap_complete::Shell = shell.into();
202+
let mut cmd = Cli::command();
203+
generate(shell, &mut cmd, "hotdata", &mut std::io::stdout());
204+
}
198205
},
199206
}
200207
}

0 commit comments

Comments
 (0)