Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ jobs:
node scripts/validate-supply-chain-workflow.mjs
node scripts/validate-release-workflow.mjs
node --test scripts/release-security.test.mjs scripts/supply-chain-workflow.test.mjs scripts/resolve-release-context.test.mjs scripts/release-workflow.test.mjs
python3 -m unittest scripts/test_normalize_macos_binary.py scripts/test_package_release.py
python3 -m unittest scripts/test_generate_cli_assets.py scripts/test_normalize_macos_binary.py scripts/test_package_release.py
- name: Validate pinned example templates
env:
STACK_SPECIFICATION_DIR: ${{ github.workspace }}/.stack-specification
Expand All @@ -82,6 +82,24 @@ jobs:
run: cargo +stable fmt --check
- name: Run tests
run: cargo +stable test --locked
- name: Validate generated completion and manual assets
shell: bash
run: |
python3 scripts/generate_cli_assets.py --binary target/debug/stack --check
bash -n distribution/generated/share/bash-completion/completions/stack
source distribution/generated/share/bash-completion/completions/stack
COMP_WORDS=(stack r)
COMP_CWORD=1
_stack_completion
test "${COMPREPLY[*]}" = render
COMP_WORDS=(stack icons li)
COMP_CWORD=2
_stack_completion
test "${COMPREPLY[*]}" = list
COMP_WORDS=(stack icons list a)
COMP_CWORD=3
_stack_completion
test "${COMPREPLY[*]}" = "aws azure"
- name: Run canonical formatter suite
env:
STACK_SPECIFICATION_DIR: ${{ github.workspace }}/.stack-specification
Expand Down Expand Up @@ -127,6 +145,11 @@ jobs:
./target/release/stack update --help
./target/release/stack lsp --help
./target/release/stack icons --help
./target/release/stack completions --help
./target/release/stack completions bash | cmp distribution/generated/share/bash-completion/completions/stack -
./target/release/stack completions zsh | cmp distribution/generated/share/zsh/site-functions/_stack -
./target/release/stack completions fish | cmp distribution/generated/share/fish/vendor_completions.d/stack.fish -
./target/release/stack manpage | cmp distribution/generated/share/man/man1/stack.1 -
./target/release/stack icons list
./target/release/stack icons list aws s3
./target/release/stack icons import --help
Expand All @@ -140,6 +163,7 @@ jobs:
test -s CONTRIBUTING.md
test -s SECURITY.md
test -s docs/language-server.md
test -s docs/completions.md
test -s docs/self-update.md
test -s docs/publication-audit.md
test -s docs/provider-icon-import.md
Expand All @@ -151,9 +175,14 @@ jobs:
test -s distribution/distribution-contract.schema.json
test -s distribution/install-receipt.schema.json
test -s distribution/release-manifest.schema.json
test -s distribution/generated/share/bash-completion/completions/stack
test -s distribution/generated/share/zsh/site-functions/_stack
test -s distribution/generated/share/fish/vendor_completions.d/stack.fish
test -s distribution/generated/share/man/man1/stack.1
test -s Cargo.toml
test -s Cargo.lock
test -s src/config.rs
test -s src/command_docs.rs
test -s src/lsp.rs
test -s src/update.rs
test -s src/update/install.rs
Expand All @@ -176,6 +205,8 @@ jobs:
test -s scripts/release-security.mjs
test -s scripts/release-security.test.mjs
test -s scripts/package_release.py
test -s scripts/generate_cli_assets.py
test -s scripts/test_generate_cli_assets.py
test -s scripts/normalize_macos_binary.py
test -s scripts/test_normalize_macos_binary.py
test -s scripts/test_package_release.py
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "stack-cli"
version = "0.3.0"
version = "0.4.0"
edition = "2024"
rust-version = "1.85"
publish = false
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ stack icons list aws s3
stack icons import gcp --accept-terms
stack icons import simple-icons --accept-terms
stack render arch.stack -o arch.svg --notice arch.NOTICE.md
stack completions zsh
stack manpage
```

`stack help`, `stack -h`, and `stack --help` print top-level help. Use `stack help <COMMAND>` or `<COMMAND> -h` / `<COMMAND> --help` for command-specific usage and examples; nested icon help is available through `stack help icons <COMMAND>`. `stack version`, `stack -v`, `stack -V`, and `stack --version` print the same Cargo package version. Help and version output use standard output and exit with status `0`. Invalid arguments and unknown commands use standard error and status `2`; close command typos include a suggested command and the relevant help invocation.
Expand All @@ -61,6 +63,8 @@ stack render arch.stack -o arch.svg --notice arch.NOTICE.md

`stack update` is implemented for future receipted direct installations, with `--check`, exact-version selection, authenticated release-manifest and archive verification, and rollback-aware atomic replacement. It refuses Homebrew, Aqua, Cargo, and unknown ownership. The published 0.3.0 binary does not contain this command and its manual installation has no receipt, so the self-update channel remains planned. See the [self-update contract](./docs/self-update.md).

`stack completions <bash|zsh|fish>` and `stack manpage` generate deterministic shell integration and an offline roff manual from the CLI command metadata. Future release archives carry the exact generated files; Homebrew installs them into its managed completion and manual paths, while direct, Aqua, and future Cargo users can generate them into user-owned locations without modifying shell startup files. See the [completion and manual guide](./docs/completions.md).

`stack icons list [PROVIDER] [QUERY]` searches the asset-free catalog by ID, product name, or category. The catalog currently contains 1,051 IDs: 305 AWS, 45 Google Cloud, 639 Azure, and 62 curated developer and collaboration tool icons. This command reads only metadata embedded in the CLI.

`stack icons import <PROVIDER> --accept-terms` downloads the audited official archive set, verifies every complete SHA-256 before ZIP processing, reads allowlisted SVG entries with fixed size limits, sanitizes active and external content, preserves official colors and geometry, and writes the manifest, notice, and processed SVGs atomically. The default store is `$XDG_CONFIG_HOME/stack/icons`, falling back to `$HOME/.config/stack/icons`. `$XDG_CONFIG_HOME/stack/config.yaml` can set an absolute `default_icons_path`. Use `-o <DIRECTORY>` to put provider child directories below a project-local root. See [the provider icon guide](./docs/provider-icon-import.md) for configuration, project-local usage, sources, hashes, and rights.
Expand All @@ -83,9 +87,10 @@ The CLI requires Rust 1.85 or newer.
cargo run -- check arch.stack
cargo test --locked
cargo clippy --all-targets --all-features --locked -- -D warnings
python3 scripts/generate_cli_assets.py --binary target/debug/stack --check
```

CI validates formatting, unit and process-level integration tests, release metadata and workflow security policies, at least 90% line/region coverage and 95% function coverage, Clippy, documentation, a release build, `--help`, and `--version` on stable Rust. Tests and Clippy also run on Rust 1.85.
CI validates formatting, unit and process-level integration tests, generated completion and manual drift, release metadata and workflow security policies, at least 90% line/region coverage and 95% function coverage, Clippy, documentation, a release build, `--help`, and `--version` on stable Rust. Tests and Clippy also run on Rust 1.85.

Canonical formatter behavior is checked against the pinned `stack-sh/specification` fixture revision recorded in `tests/specification-revision`.

Expand Down
20 changes: 16 additions & 4 deletions distribution/distribution-contract.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"sourceCargoPackage": "stack-cli",
"publishedCargoPackage": null,
"sourceVersionFile": "Cargo.toml",
"currentSourceVersion": "0.3.0",
"currentSourceVersion": "0.4.0",
"minimumRustVersion": "1.85"
},
"availability": {
Expand All @@ -30,8 +30,18 @@
"stack",
"LICENSE",
"NOTICE",
"THIRD_PARTY_LICENSES.md"
"THIRD_PARTY_LICENSES.md",
"share/bash-completion/completions/stack",
"share/zsh/site-functions/_stack",
"share/fish/vendor_completions.d/stack.fish",
"share/man/man1/stack.1"
],
"completionPaths": {
"bash": "share/bash-completion/completions/stack",
"zsh": "share/zsh/site-functions/_stack",
"fish": "share/fish/vendor_completions.d/stack.fish"
},
"manpagePath": "share/man/man1/stack.1",
"releaseManifestNameTemplate": "stack-v{version}-release-manifest.json",
"installReceiptSchema": "distribution/install-receipt.schema.json",
"checksumNameTemplate": "stack-v{version}-checksums.txt",
Expand Down Expand Up @@ -114,7 +124,7 @@
"aarch64-unknown-linux-gnu",
"x86_64-unknown-linux-gnu"
],
"owns": "canonical immutable binary archives, release manifest, checksums, signature bundle, SBOMs, and provenance",
"owns": "canonical immutable binary archives with generated shell completions and manual page, release manifest, checksums, signature bundle, SBOMs, and provenance",
"source": "tagged stack-sh/cli source",
"updatePolicy": "stable releases only unless the user requests an exact prerelease"
},
Expand All @@ -126,7 +136,7 @@
"aarch64-unknown-linux-gnu",
"x86_64-unknown-linux-gnu"
],
"owns": "formula metadata, GitHub archive URL and SHA-256 mapping, install, upgrade, and uninstall lifecycle on current Homebrew tier-1 hosts",
"owns": "formula metadata, GitHub archive URL and SHA-256 mapping, completion and manual placement, install, upgrade, and uninstall lifecycle on current Homebrew tier-1 hosts",
"source": "github-release",
"updatePolicy": "Homebrew owns upgrades; stack self-update must refuse replacement"
},
Expand Down Expand Up @@ -178,6 +188,8 @@
"all archive contents and metadata names match this contract",
"all checksums, Sigstore bundles, SBOMs, and provenance verify",
"stack --version, help, init, check, and render pass on each target",
"generated shell completion source matches the archived bash, zsh, and fish files",
"generated manual page matches the archived stack.1 file",
"the release manifest records minimumSupportedCliVersion and each verified channel"
],
"selfUpdateActivation": [
Expand Down
15 changes: 14 additions & 1 deletion distribution/distribution-contract.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@
"archiveNameTemplate",
"archiveRootTemplate",
"requiredEntries",
"completionPaths",
"manpagePath",
"releaseManifestNameTemplate",
"installReceiptSchema",
"checksumNameTemplate",
Expand All @@ -86,10 +88,21 @@
"archiveRootTemplate": { "$ref": "#/$defs/template" },
"requiredEntries": {
"type": "array",
"minItems": 4,
"minItems": 8,
"uniqueItems": true,
"items": { "type": "string", "minLength": 1 }
},
"completionPaths": {
"type": "object",
"additionalProperties": false,
"required": ["bash", "zsh", "fish"],
"properties": {
"bash": { "const": "share/bash-completion/completions/stack" },
"zsh": { "const": "share/zsh/site-functions/_stack" },
"fish": { "const": "share/fish/vendor_completions.d/stack.fish" }
}
},
"manpagePath": { "const": "share/man/man1/stack.1" },
"releaseManifestNameTemplate": { "$ref": "#/$defs/template" },
"installReceiptSchema": { "const": "distribution/install-receipt.schema.json" },
"checksumNameTemplate": { "$ref": "#/$defs/template" },
Expand Down
43 changes: 43 additions & 0 deletions distribution/generated/share/bash-completion/completions/stack
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Generated by `stack completions bash`; do not edit.
_stack_completion() {
local current previous context words
current="${COMP_WORDS[COMP_CWORD]-}"
previous="${COMP_WORDS[COMP_CWORD-1]-}"
context="${COMP_WORDS[1]-}"
if [[ "$context" == icons && $COMP_CWORD -ge 3 ]]; then
context="icons ${COMP_WORDS[2]-}"
fi
case "$previous" in
--template) words="hello-stack application-and-data groups-and-layout commerce-platform aws-serverless-checkout gcp-data-service azure-event-platform github-delivery-workflow mixed-provider-platform" ;;
--provider-pack|-o|--output|--notice) compopt -o default 2>/dev/null || true; return ;;
--version) COMPREPLY=(); return ;;
*) words="" ;;
esac
if [[ -z "$words" ]]; then
if (( COMP_CWORD == 1 )); then
words="init check fmt render update lsp icons completions manpage help version -h --help -v -V --version"
else
case "$context" in
"init") words="--template -o --output --force -h --help" ;;
"check") words="-h --help" ;;
"fmt") words="- --check -h --help" ;;
"render") words="--provider-pack -o --notice -h --help" ;;
"update") words="--check --version -h --help" ;;
"lsp") words="-h --help" ;;
"icons") words="list import help -h --help" ;;
"icons list") words="aws gcp azure simple-icons -h --help" ;;
"icons import") words="aws gcp azure simple-icons --accept-terms -o -h --help" ;;
"completions") words="bash zsh fish -h --help" ;;
"manpage") words="-h --help" ;;
"help") words="init check fmt render update lsp icons completions manpage help version -h --help" ;;
"version") words="-h --help" ;;
*) words="" ;;
esac
fi
fi
COMPREPLY=( $(compgen -W "$words" -- "$current") )
if (( ${#COMPREPLY[@]} == 0 )); then
compopt -o default 2>/dev/null || true
fi
}
complete -F _stack_completion stack
Loading