Skip to content

feat: initial public release of the hyperlift CLI - #1

Merged
csabasim merged 10 commits into
mainfrom
feat/initial_release
Aug 12, 2026
Merged

feat: initial public release of the hyperlift CLI#1
csabasim merged 10 commits into
mainfrom
feat/initial_release

Conversation

@csabasim

@csabasim csabasim commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

What it does

hyperlift is the command-line client for Hyperlift container applications.
It talks to the public Spaceship External API and signs in with an
API key and secret.

Main commands

  • apps: list, get, build, start, stop, restart, with --wait to poll
    until the operation really finishes rather than when the API accepts it.
  • env: get, set, unset, as read-modify-write, since the API replaces the
    whole map.
  • logs: runtime and build logs, cursor-paged; --follow polls because
    the API has no streaming endpoint.
  • metrics: time series in each series' own unit.
  • auth: login, whoami, logout, with the secret in the OS keyring.
  • update: checksum-verified self-update that refuses to touch a binary a
    package manager owns (package manager install is tbd)

Try it

The repo ships a mock of the API, so no credentials are needed:

make mock                      # terminal 1: serves on :8080

make build                     # terminal 2
export HYPERLIFT_BASE_URL=http://localhost:8080
export HYPERLIFT_API_KEY=demo HYPERLIFT_API_SECRET=demo

./bin/hyperlift apps list
./bin/hyperlift apps get app_a1b2c3 --json
./bin/hyperlift apps restart app_a1b2c3 --wait
./bin/hyperlift logs app_a1b2c3 --follow

The mock holds a transient state for a few seconds, so e.g. --wait visibly polls.

For the real API, use a shell without those exports, or the base URL override
sends you straight back to the mock. Create a key and secret in the
API Manager with the
hyperlift:read, hyperlift:execute and hyperlift:manage scopes, then
make install and hyperlift auth login. For details, see the README.

Some details

  • One Go package per command group in internal/cmd/: apps, auth, env,
    logs, metrics, update and version. None build their own dependencies.
    internal/cmdutil holds the exit-code mapping and the Factory, which hands
    out the API client, config, streams and prompter lazily.
    internal/cmd/root assembles the tree and registers the persistent flags.
  • An HTTP client in internal/client, with its own transport for auth headers, retries and a debug trace.
  • Credential storage in internal/keyring and internal/config: OS keyring,
    with a file fallback when there is no keyring.
  • A mock of the API, and a test suite that checks the mock against the
    published OpenAPI document so it cannot quietly drift. internal/testapi/testdata
    • The current OpenAPI document can be fetched with make refresh-spec
  • scripts/install.sh
  • A Makefile for the everyday targets: build, install, test, lint,
    fmt, mock, run-mock and refresh-spec.
  • Release and CI config: GoReleaser with signing (both checksum and cosign), three workflows, lint rules, dependabot.
  • Every PR does a full GoReleaser build and checks the release asset names, then throws the artifacts away

Manage Hyperlift applications over the Spaceship External API: auth, apps list/get and the build, start, stop and restart verbs with --wait, env read-modify-write, logs with --follow, metrics, and self-update.
Comment thread internal/client/problem.go
Comment thread internal/cmd/root/root.go Outdated
Comment thread internal/cmd/root/root.go
@yunussandikci

Copy link
Copy Markdown

One another thing, is it easily possible to fetch openapi spec file dynamically while building (or maybe part of the CI to verify if its identical)? So that, we will never be able to forget updating it

@csabasim

Copy link
Copy Markdown
Contributor Author

@yunussandikci
Implemented in the latest commit, as the CI variant so it fails in the PR rather than at build time.

So now the CI uses the same script make refresh-spec uses and fails when the pin differs.

The pin is also reduced to the Hyperlift subset now, so a domains or other unrelated schema change can't fail our PRs, so we check purely Hyperlift schema drift.

Btw the script is only slightly complex because unfortunately docs.spaceship.dev does not expose the OpenAPI schema directly. It uses Redoc, which enables downloading through the website and it actually has the schema inside its HTML document (which we scrape), but no direct URL for it. But it's working this way.

But to summarize, it was a good idea and now we cannot forget to update the OpenAPI spec file :)

@csabasim
csabasim merged commit 2353af3 into main Aug 12, 2026
7 checks passed
@csabasim
csabasim deleted the feat/initial_release branch August 12, 2026 12:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants