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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,7 @@ tokens.enc
# OS artifacts
.DS_Store
Thumbs.db

# Python bytecode from running scripts/*.py locally
__pycache__/
*.pyc
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ the GitHub Release body, so every release PR must add one. Unreleased work goes

## [Unreleased]

## [0.1.0] - 2026-09-11

### Added

- **Authentication** (`zdk auth`): OAuth authorization code with PKCE on a single-use loopback listener (`--port`, `--no-browser` with a paste-back flow, `--redirect-uri`, `--expires-in`), client credentials for CI (`--client-credentials`, `--store-secret`), and the legacy API-token ramp (`--api-token`) that prints a one-line countdown to the 27 Oct 2026 / 30 Apr 2027 deadlines. `status`, `whoami`, `refresh [--force]`, `logout [--no-revoke]`, `test`, `token --format raw|bearer|json`, and `scopes list|show|check|preset` over the 52-scope catalogue with the `agent`, `admin`, `readonly` and `exporter` presets. Pre-emptive refresh at 80 % of the token lifetime with rotation persisted before use; local scope pre-flight (`SCOPE_MISSING`, exit 4) before any request.
Expand All @@ -25,3 +27,6 @@ the GitHub Release body, so every release PR must add one. Unreleased work goes
- **Output**: `table` on a terminal, `json` when piped, plus `ndjson`, `csv`, `tsv`, `yaml` and `raw`; `--fields`/`--exclude` projection, `--compact`, `--sideload` joins, an embedded jq filter (`--jq`), and one-line JSON errors on stderr with stable `code` strings and exit codes; `zdk --help-json` for tool-definition generation.
- **Shell integration**: `zdk completions bash|zsh|fish|powershell|elvish` and `zdk man --to DIR` (one page per subcommand), both shipped in release archives.
- **Distribution**: 7-target release pipeline (macOS arm64/x64, Linux musl arm64/x64 and glibc x64, Windows x64/arm64) with build-provenance attestations, `checksums-sha256.txt`, Homebrew tap and Scoop bucket updates.

[Unreleased]: https://github.com/osodevops/zendesk-cli/compare/v0.1.0...HEAD
[0.1.0]: https://github.com/osodevops/zendesk-cli/releases/tag/v0.1.0
6 changes: 3 additions & 3 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ members = ["crates/zdk-core", "crates/zdk-cli", "xtask"]
default-members = ["crates/zdk-core", "crates/zdk-cli"]

[workspace.package]
version = "0.0.0"
version = "0.1.0"
edition = "2024"
rust-version = "1.88"
license = "MIT"
Expand All @@ -15,7 +15,7 @@ keywords = ["zendesk", "cli", "oauth", "support", "ai-agent"]
categories = ["command-line-utilities"]

[workspace.dependencies]
zdk-core = { path = "crates/zdk-core", version = "0.0.0" }
zdk-core = { path = "crates/zdk-core", version = "0.1.0" } # keep equal to [workspace.package] version (guarded by scripts/check-release-version.py)

# CLI
clap = { version = "4.6", features = ["derive", "env", "string", "wrap_help"] }
Expand Down
10 changes: 5 additions & 5 deletions crates/zdk-cli/tests/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ fn version_flag_and_command() {
.arg("--version")
.assert()
.success()
.stdout(predicate::str::is_match(r"^zdk 0\.0\.0\n$").expect("re"));
.stdout(predicate::str::is_match(r"^zdk \d+\.\d+\.\d+\n$").expect("re"));
h.zdk()
.args(["version", "-o", "table"])
.assert()
.success()
.stdout("zdk 0.0.0\n");
.stdout(concat!("zdk ", env!("CARGO_PKG_VERSION"), "\n"));
// Piped (the default here) means JSON.
let out = h
.zdk()
Expand All @@ -52,7 +52,7 @@ fn version_flag_and_command() {
.get_output()
.stdout
.clone();
assert_eq!(json(&out)["version"], "0.0.0");
assert_eq!(json(&out)["version"], env!("CARGO_PKG_VERSION"));
}

#[test]
Expand All @@ -67,7 +67,7 @@ fn version_json_has_target_and_spec_versions() {
.stdout
.clone();
let v = json(&out);
assert_eq!(v["version"], "0.0.0");
assert_eq!(v["version"], env!("CARGO_PKG_VERSION"));
assert!(v["target"].as_str().is_some_and(|t| t.contains('-')), "{v}");
assert!(v["spec_versions"].is_array(), "{v}");
}
Expand All @@ -85,7 +85,7 @@ fn help_json_is_a_walkable_tree() {
.clone();
let v = json(&out);
assert_eq!(v["binary"], "zdk");
assert_eq!(v["version"], "0.0.0");
assert_eq!(v["version"], env!("CARGO_PKG_VERSION"));
let subs = v["subcommands"].as_array().expect("subcommands");
let config = subs
.iter()
Expand Down
2 changes: 2 additions & 0 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ license-files = [{ path = "LICENSE", hash = 0xbd0eed23 }]
[bans]
multiple-versions = "allow"
wildcards = "deny"
# Workspace members are path dependencies without a version until crates.io publishing.
allow-wildcard-paths = true

[sources]
unknown-registry = "deny"
Expand Down
20 changes: 20 additions & 0 deletions scripts/check-release-version.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,25 @@ def verify_changelog_version(version: str) -> None:
fail(f"CHANGELOG.md is missing a `## [{version}]` release section (it becomes the release body).")


def verify_internal_dep_pins(version: str) -> None:
"""[workspace.dependencies] path entries for workspace members carry a `version`
(crates.io requires it); it must equal the workspace version or `cargo update`
and publishing break in confusing ways."""
root = parse_toml(Path("Cargo.toml").read_text(encoding="utf-8"), "Cargo.toml")
members = load_workspace_member_names()
stale: list[str] = []
for name, spec in root.get("workspace", {}).get("dependencies", {}).items():
if isinstance(spec, dict) and "path" in spec and name in members:
pinned = spec.get("version")
if isinstance(pinned, str) and pinned.lstrip("=^") != version:
stale.append(f"{name} pins {pinned}")
if stale:
fail(
f"[workspace.dependencies] path pins are out of sync with {version}: "
f"{', '.join(stale)}. Edit the `version = ...` on those entries in Cargo.toml."
)


def tag_exists(tag: str) -> bool:
result = subprocess.run(
["git", "rev-parse", "--verify", "--quiet", f"refs/tags/{tag}"],
Expand Down Expand Up @@ -225,6 +244,7 @@ def main() -> None:
fail(f"[workspace.package] version must increase (base: {base_version}, head: {head_version}).")

verify_lockfile_version(head_version)
verify_internal_dep_pins(head_version)
verify_changelog_version(head_version)

if args.mode == "guard" and args.event_name == "pull_request" and tag_exists(tag):
Expand Down