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
34 changes: 34 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: CI

on:
pull_request:
push:
branches:
- main
workflow_dispatch:

permissions:
contents: read

jobs:
test:
name: Test CLI and installers
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4

- name: Set up Go
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
with:
go-version: "1.25.x"
cache: true

- name: Check Unix installer syntax
run: sh -n install.sh

- name: Vet
run: go vet ./...

- name: Test
run: go test ./... -count=1
69 changes: 64 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,53 @@ on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
tag:
description: "Existing release tag to build or repair (for example, v0.0.1-alpha)"
required: true
type: string

concurrency:
group: release-${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }}
cancel-in-progress: false

permissions:
contents: read

jobs:
prepare:
name: Validate release tag
runs-on: ubuntu-latest
outputs:
tag: ${{ steps.release-tag.outputs.tag }}
tag_ref: ${{ steps.release-tag.outputs.tag_ref }}
steps:
- name: Resolve release tag
id: release-tag
env:
RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }}
run: |
if [[ ! "${RELEASE_TAG}" =~ ^v[A-Za-z0-9._-]+$ ]]; then
echo "Release tag must start with 'v' and contain only letters, numbers, dots, underscores, or hyphens: ${RELEASE_TAG}" >&2
exit 1
fi
if ! git check-ref-format "refs/tags/${RELEASE_TAG}"; then
echo "Invalid release tag: ${RELEASE_TAG}" >&2
exit 1
fi
printf 'tag=%s\n' "${RELEASE_TAG}" >> "${GITHUB_OUTPUT}"
printf 'tag_ref=refs/tags/%s\n' "${RELEASE_TAG}" >> "${GITHUB_OUTPUT}"

test:
name: Test
needs: prepare
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
ref: ${{ needs.prepare.outputs.tag_ref }}

- name: Set up Go
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
Expand All @@ -33,7 +69,9 @@ jobs:

build:
name: Build ${{ matrix.goos }}/${{ matrix.goarch }}
needs: test
needs:
- prepare
- test
runs-on: ubuntu-latest
strategy:
fail-fast: false
Expand All @@ -54,6 +92,8 @@ jobs:
steps:
- name: Check out repository
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
ref: ${{ needs.prepare.outputs.tag_ref }}

- name: Set up Go
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
Expand All @@ -63,11 +103,12 @@ jobs:

- name: Build archive
env:
RELEASE_TAG: ${{ needs.prepare.outputs.tag }}
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
CGO_ENABLED: "0"
run: |
version="${GITHUB_REF_NAME}"
version="${RELEASE_TAG}"
commit="$(git rev-parse --short HEAD)"
build_date="$(date -u '+%Y-%m-%dT%H:%M:%SZ')"
mkdir -p package dist
Expand All @@ -88,7 +129,7 @@ jobs:
- name: Verify release metadata
if: matrix.goos == 'linux' && matrix.goarch == 'amd64'
env:
EXPECTED_VERSION: ${{ github.ref_name }}
EXPECTED_VERSION: ${{ needs.prepare.outputs.tag }}
run: |
expected_commit="$(git rev-parse --short HEAD)"
version_json="$(./package/stackdome version -o json)"
Expand All @@ -107,13 +148,17 @@ jobs:

publish:
name: Publish GitHub release
needs: build
needs:
- prepare
- build
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Check out repository
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
ref: ${{ needs.prepare.outputs.tag_ref }}

- name: Download archives
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
Expand All @@ -129,4 +174,18 @@ jobs:
- name: Publish release
env:
GH_TOKEN: ${{ github.token }}
run: gh release create "${GITHUB_REF_NAME}" dist/* --verify-tag --generate-notes --title "Stackdome CLI ${GITHUB_REF_NAME}"
RELEASE_TAG: ${{ needs.prepare.outputs.tag }}
run: |
if gh release view "${RELEASE_TAG}" >/dev/null 2>&1; then
release_is_draft="$(gh release view "${RELEASE_TAG}" --json isDraft --jq .isDraft)"
else
gh release create "${RELEASE_TAG}" --draft --verify-tag --generate-notes --title "Stackdome CLI ${RELEASE_TAG}"
release_is_draft=true
fi

gh release upload "${RELEASE_TAG}" dist/*.tar.gz dist/*.zip --clobber
gh release upload "${RELEASE_TAG}" dist/checksums.txt --clobber

if [[ "${release_is_draft}" == "true" ]]; then
gh release edit "${RELEASE_TAG}" --draft=false
fi
41 changes: 41 additions & 0 deletions .github/workflows/windows-installer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Test Windows installer

on:
pull_request:
paths:
- "install.ps1"
- "install_windows_contract_test.go"
- "tests/install_windows/**"
- ".github/workflows/windows-installer.yml"
push:
branches:
- main
paths:
- "install.ps1"
- "install_windows_contract_test.go"
- "tests/install_windows/**"
- ".github/workflows/windows-installer.yml"
workflow_dispatch:

permissions:
contents: read

jobs:
test:
name: PowerShell 5.1 and PowerShell 7
runs-on: windows-latest
env:
STACKDOME_REQUIRE_BOTH_POWERSHELLS: "1"
steps:
- name: Check out repository
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4

- name: Set up Go
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
with:
go-version: "1.25.x"
cache: true

- name: Test Windows installer
shell: pwsh
run: go test ./tests/install_windows -count=1 -v
62 changes: 62 additions & 0 deletions INSTALL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Install the Stackdome CLI

The installers download the latest GitHub release for the current platform and
verify its SHA-256 checksum before installing it.

## macOS and Linux

```sh
curl -fsSL https://raw.githubusercontent.com/Stackdome/stackdome-cli/main/install.sh | sh
```

For agents and CI, download first so a network failure cannot be hidden by
pipeline exit-status behavior:

```sh
installer_file=$(mktemp)
trap 'rm -f "$installer_file"' EXIT
curl -fsSL https://raw.githubusercontent.com/Stackdome/stackdome-cli/main/install.sh -o "$installer_file"
sh "$installer_file"
```

The installer supports Intel/AMD64 and ARM64. It writes to `/usr/local/bin`
when that directory is writable, otherwise it uses `$HOME/.local/bin`.

To install a specific version or directory:

```sh
curl -fsSL https://raw.githubusercontent.com/Stackdome/stackdome-cli/main/install.sh \
| STACKDOME_VERSION=v0.0.1-alpha STACKDOME_INSTALL_DIR="$HOME/.local/bin" sh
```

## Windows PowerShell

```powershell
irm https://raw.githubusercontent.com/Stackdome/stackdome-cli/main/install.ps1 | iex
```

For agents and CI, fetch the script before evaluating it so download errors are
terminal:

```powershell
$installer = Invoke-RestMethod -ErrorAction Stop https://raw.githubusercontent.com/Stackdome/stackdome-cli/main/install.ps1
& ([ScriptBlock]::Create([string]$installer))
```

The installer supports AMD64 and ARM64. By default it installs to
`%LOCALAPPDATA%\Programs\Stackdome\bin` and adds that directory to the user
`PATH`.

To install a specific version or directory:

```powershell
$env:STACKDOME_VERSION = 'v0.0.1-alpha'
$env:STACKDOME_INSTALL_DIR = "$env:LOCALAPPDATA\Programs\Stackdome\bin"
irm https://raw.githubusercontent.com/Stackdome/stackdome-cli/main/install.ps1 | iex
```

## Branded URLs

A branded CLI installation URL can proxy `install.sh` and `install.ps1` from
this repository. The self-hosted Stackdome installer remains a separate
artifact owned by the Hub repository and should not point at these CLI scripts.
Loading
Loading