Skip to content
Open
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
7 changes: 7 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,10 @@ indent_size = 2
end_of_line = lf
#insert_final_newline = true
trim_trailing_whitespace = true

# gofmt mandates tabs; the default above would fight it.
[*.go]
indent_style = tab

[Makefile]
indent_style = tab
86 changes: 86 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: Release Build
on:
push:
branches:
- main
pull_request:
workflow_dispatch:
merge_group:
types: [checks_requested]

permissions:
contents: read

jobs:
# Validates .goreleaser.yaml and cross-compiles every published target, so a
# break in the release pipeline surfaces on the pull request rather than at
# tag time, when it can only be fixed with another tag.
snapshot:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
fetch-depth: 0

- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
with:
go-version-file: go.mod
cache-dependency-path: go.sum

- name: Check GoReleaser config
uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3
with:
version: "~> v2"
args: check

- name: Build snapshot
uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3
with:
version: "~> v2"
args: release --snapshot --clean --skip=validate

# Asserts the properties install.sh and the docs depend on, against the
# archive a user actually downloads.
- name: Verify release archive
run: |
set -euo pipefail

test -f dist/checksums.txt

archive=$(ls dist/*_linux_amd64.tar.gz)
contents=$(tar tzf "$archive")

# The binary must sit at the archive root. A nested directory means
# `tar xzf` hands the user a folder instead of something runnable.
grep -qx understackctl <<<"$contents"
grep -qx LICENSE <<<"$contents"
grep -qx README.md <<<"$contents"
grep -qx 'completions/understackctl.bash' <<<"$contents"
grep -qx 'completions/understackctl.powershell' <<<"$contents"

# macOS users get one archive that runs on both architectures.
test -f dist/*_darwin_all.tar.gz

# Windows archives are zips holding a .exe.
unzip -l dist/*_windows_amd64.zip | grep -q 'understackctl\.exe'

mkdir -p /tmp/verify
tar xzf "$archive" -C /tmp/verify
/tmp/verify/understackctl version

# A release binary must never fall back to the "dev" placeholder;
# that would mean the ldflags in .goreleaser.yaml stopped matching
# the variable paths in internal/version.
if /tmp/verify/understackctl version | grep -qx 'Version: dev'; then
echo "::error::version was not stamped into the binary"
exit 1
fi

- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: snapshot-archives
path: |
dist/*.tar.gz
dist/*.zip
dist/checksums.txt
retention-days: 7
9 changes: 8 additions & 1 deletion .github/workflows/go-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,15 @@ permissions:
contents: read

jobs:
# Runs on every platform we publish a binary for. This tool does a lot of
# path manipulation and shells out to kubeseal/argo/helm/git, which is
# exactly where cross-platform bugs hide.
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6

Expand Down
46 changes: 28 additions & 18 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ name: Releases
on:
push:
tags:
# Matches v0.1.0 and pre-releases such as v0.1.0-rc.1. GoReleaser's
# `prerelease: auto` keeps the latter from being marked "latest".
- "v[0-9]+.[0-9]+.[0-9]+"
- "v[0-9]+.[0-9]+.[0-9]+-*"

permissions:
contents: read
Expand All @@ -12,35 +15,42 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: write
# Required by actions/attest: id-token to mint the Sigstore OIDC token,
# attestations to persist the result. artifact-metadata is not needed
# because we do not push to a registry, so no storage record is created.
id-token: write
packages: write
attestations: write
steps:
- name: Checkout
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
# GoReleaser needs the full history and tags to build the changelog.
fetch-depth: 0

- name: Setup Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
with:
go-version-file: 'go.mod'
cache-dependency-path: 'go.sum'
cache: true
go-version-file: go.mod
cache-dependency-path: go.sum

- name: Install dependencies
run: sudo apt-get install -y sed grep

- name: Build and Package
run: |
make build-all package-all checksums

- name: Upload release artifacts
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3
with:
make_latest: true
files: |
build/*.zip
build/*.tar.gz
build/checksums.txt
version: "~> v2"
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Uncomment once the tap/bucket repositories and their PATs exist,
# and set skip_upload: false in .goreleaser.yaml. See the comments
# there for the full checklist.
# HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
# SCOOP_BUCKET_TOKEN: ${{ secrets.SCOOP_BUCKET_TOKEN }}

# Generates SLSA build provenance for every artifact listed in
# checksums.txt, so anyone can confirm an archive was built by this
# workflow from this commit:
# gh attestation verify <archive> --repo rackerlabs/understackctl
- name: Attest build provenance
uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2
with:
subject-checksums: dist/checksums.txt
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ vendor/
dist/
build/

# generated by scripts/completions.sh for release archives
completions/

# IntelliJ
.idea
*.iml
Expand Down
183 changes: 183 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
#
# Release configuration for understackctl.
#
# Local use:
# goreleaser check validate this file
# goreleaser build --snapshot --clean cross-compile without releasing
# goreleaser release --snapshot --clean build archives + checksums locally
#
# Releases are cut by .github/workflows/release.yaml on a v* tag.
version: 2

project_name: understackctl

before:
hooks:
- go mod download
# Generates completions/ for inclusion in the archives.
- sh ./scripts/completions.sh

builds:
- id: understackctl
binary: understackctl
main: .
env:
- CGO_ENABLED=0
flags:
# -trimpath keeps absolute build paths out of the binary, which is what
# makes the output reproducible.
- -trimpath
ldflags:
- -s -w
- -X github.com/rackerlabs/understackctl/internal/version.version={{ .Version }}
- -X github.com/rackerlabs/understackctl/internal/version.commit={{ .ShortCommit }}
- -X github.com/rackerlabs/understackctl/internal/version.date={{ .CommitDate }}
goos:
- linux
- darwin
- windows
goarch:
- amd64
- arm64
# Pin file timestamps to the commit so repeated builds of the same tag
# produce byte-identical archives.
mod_timestamp: "{{ .CommitTimestamp }}"

# A single darwin_all artifact that runs on both Intel and Apple Silicon, so a
# macOS user who is unsure which they have cannot pick wrong. replace: false
# keeps the smaller per-arch archives too; install.sh and Homebrew use those.
universal_binaries:
- id: understackctl-universal
ids:
- understackctl
name_template: understackctl
replace: false

archives:
- id: archives
ids:
- understackctl
- understackctl-universal
# No wrap_in_directory: the binary sits at the archive root, so
# `tar xzf understackctl_*.tar.gz` yields a runnable binary rather than a
# directory to go hunting through.
name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
formats:
- tar.gz
format_overrides:
- goos: windows
formats:
- zip
files:
- LICENSE
- README.md
- src: completions/*
dst: completions

checksum:
name_template: checksums.txt
algorithm: sha256

snapshot:
version_template: "{{ incpatch .Version }}-snapshot-{{ .ShortCommit }}"

changelog:
use: github
sort: asc
filters:
exclude:
- "^docs:"
- "^test:"
- "^chore:"
- "^ci:"
- "^style:"
- Merge pull request
- Merge branch
groups:
- title: Features
regexp: '^.*?feat(\([[:word:]]+\))??!?:.+$'
order: 0
- title: Bug fixes
regexp: '^.*?fix(\([[:word:]]+\))??!?:.+$'
order: 1
- title: Dependency updates
regexp: '^.*?(deps|build)(\([[:word:]]+\))??!?:.+$'
order: 2
- title: Other work
order: 999

release:
github:
owner: rackerlabs
name: understackctl
# A -rc/-beta tag is published as a pre-release and, because of that, is not
# marked "latest" even though make_latest is true.
prerelease: auto
make_latest: true
footer: |
## Installing

```bash
curl -fsSL https://raw.githubusercontent.com/rackerlabs/understackctl/main/install.sh | sh
```

Or download the archive for your platform below and move `understackctl`
onto your `PATH`. Verify what you downloaded first:

```bash
sha256sum --check --ignore-missing checksums.txt
gh attestation verify understackctl_*_linux_amd64.tar.gz --repo rackerlabs/understackctl
```

See the [installation guide](https://github.com/rackerlabs/understackctl#installation)
for Homebrew, Scoop, `go install` and shell completion setup.

# --- Package managers -------------------------------------------------------
#
# Both blocks below are configured but DISABLED (skip_upload: true) because
# publishing needs infrastructure that does not exist yet. To turn either on:
#
# 1. Create the target repository under the rackerlabs org:
# Homebrew -> rackerlabs/homebrew-tap
# Scoop -> rackerlabs/scoop-bucket
# 2. Create a PAT with `contents: write` on that repository and add it to
# this repo's Actions secrets as HOMEBREW_TAP_TOKEN / SCOOP_BUCKET_TOKEN.
# The default GITHUB_TOKEN cannot push to another repository.
# 3. Uncomment the matching `env:` line in .github/workflows/release.yaml.
# 4. Change skip_upload below to false.
#
# Until step 4, a release builds these artifacts and does not push them, so
# nothing here can break a release.

homebrew_casks:
- name: understackctl
skip_upload: true
repository:
owner: rackerlabs
name: homebrew-tap
token: "{{ if index .Env \"HOMEBREW_TAP_TOKEN\" }}{{ .Env.HOMEBREW_TAP_TOKEN }}{{ end }}"
homepage: https://github.com/rackerlabs/understackctl
description: CLI tool for managing UnderStack deployments
license: apache-2.0
completions:
bash: completions/understackctl.bash
zsh: completions/understackctl.zsh
fish: completions/understackctl.fish
hooks:
post:
install: |
if system_command("/usr/bin/xattr", args: ["-h"]).exit_status == 0
system_command "/usr/bin/xattr", args: ["-dr", "com.apple.quarantine", "#{staged_path}/understackctl"]
end

scoops:
- name: understackctl
skip_upload: true
repository:
owner: rackerlabs
name: scoop-bucket
token: "{{ if index .Env \"SCOOP_BUCKET_TOKEN\" }}{{ .Env.SCOOP_BUCKET_TOKEN }}{{ end }}"
homepage: https://github.com/rackerlabs/understackctl
description: CLI tool for managing UnderStack deployments
license: Apache-2.0
Loading
Loading