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
10 changes: 10 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
# Don't pick up brand-new action releases immediately; compromised
# versions are usually yanked within days of publication.
cooldown:
default-days: 7
81 changes: 81 additions & 0 deletions .github/scripts/render-snapshot-cask.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#!/usr/bin/env bash
# Renders the jira-cli-snapshot cask from a GoReleaser snapshot dist/.
# GoReleaser OSS only writes casks on real releases, so the snapshot channel
# renders the same shape itself, with checksums from the snapshot build.
#
# Usage: render-snapshot-cask.sh <dist-dir> <release-tag>
# The cask is written to stdout.
set -euo pipefail

DIST="$1"
TAG="$2"

VERSION=$(jq -r .version "$DIST/metadata.json")

sha() {
awk -v f="jira_${VERSION}_$1.tar.gz" '$2 == f { print $1 }' "$DIST/checksums.txt" | grep .
}

MACOS_INTEL=$(sha macOS_x86_64)
MACOS_ARM=$(sha macOS_arm64)
LINUX_INTEL=$(sha linux_x86_64)
LINUX_ARM=$(sha linux_arm64)

cat <<EOF
# This file was generated by the snapshot workflow in rethab/jira-cli. DO NOT EDIT.
cask "jira-cli-snapshot" do
version "$VERSION"

on_macos do
on_intel do
sha256 "$MACOS_INTEL"
url "https://github.com/rethab/jira-cli/releases/download/$TAG/jira_#{version}_macOS_x86_64.tar.gz",
verified: "github.com/rethab/jira-cli/"
rename "jira_#{version}_macOS_x86_64/bin/jira", "bin/jira"
end
on_arm do
sha256 "$MACOS_ARM"
url "https://github.com/rethab/jira-cli/releases/download/$TAG/jira_#{version}_macOS_arm64.tar.gz",
verified: "github.com/rethab/jira-cli/"
rename "jira_#{version}_macOS_arm64/bin/jira", "bin/jira"
end
end

on_linux do
on_intel do
sha256 "$LINUX_INTEL"
url "https://github.com/rethab/jira-cli/releases/download/$TAG/jira_#{version}_linux_x86_64.tar.gz",
verified: "github.com/rethab/jira-cli/"
rename "jira_#{version}_linux_x86_64/bin/jira", "bin/jira"
end
on_arm do
sha256 "$LINUX_ARM"
url "https://github.com/rethab/jira-cli/releases/download/$TAG/jira_#{version}_linux_arm64.tar.gz",
verified: "github.com/rethab/jira-cli/"
rename "jira_#{version}_linux_arm64/bin/jira", "bin/jira"
end
end

name "jira-cli-snapshot"
desc "🔥 Feature-rich interactive Jira command-line (snapshot of main)"
homepage "https://github.com/rethab/jira-cli"

livecheck do
skip "Auto-generated on every merge to main."
end

conflicts_with cask: "jira-cli"

binary "bin/jira"

postflight do
if OS.mac?
system_command "/usr/bin/xattr", args: ["-dr", "com.apple.quarantine", "#{staged_path}/bin/jira"]
end
end
generate_completions_from_executable "bin/jira", "completion",
shells: [:bash, :zsh, :fish]

caveats "This is an unstable snapshot build of the main branch."
end
EOF
15 changes: 10 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
on:
pull_request:
types: [opened, synchronize, reopened]
release:
types: [published]
push:
branches: [main]

name: Build

permissions:
contents: read

jobs:
tests:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false

- name: Setup Go
uses: actions/setup-go@v5
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version: '^1.25.6'
# Follow the toolchain declared in go.mod: a floating constraint
# resolves to Go versions golangci-lint cannot typecheck yet.
go-version-file: 'go.mod'

- name: Install dependencies
run: make deps
Expand Down
21 changes: 13 additions & 8 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
name: Publish a Docker image
run-name: Docker image for ${{ github.ref_name }}

# Triggered by the tag push, not release-published: releases here are created
# by workflows using GITHUB_TOKEN, and GitHub suppresses events from that
# token, so a release trigger would never fire.
on:
workflow_dispatch:
release:
types: [published, prereleased]
push:
tags: ['v*']

env:
REGISTRY: ghcr.io
Expand All @@ -19,31 +22,33 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false

- name: Log in to the Container registry
uses: docker/login-action@v3
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
with:
platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7,linux/arm/v8

- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
context: .
file: ./Dockerfile
Expand Down
53 changes: 53 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
on:
push:
tags: ['v*']

name: Release

permissions: {}

jobs:
goreleaser:
runs-on: ubuntu-latest
permissions:
contents: write # create the release and upload assets
id-token: write # OIDC token for keyless provenance signing
attestations: write # store the provenance attestation
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
# GoReleaser derives the changelog and build metadata from history.
fetch-depth: 0
# GoReleaser authenticates via env, not the checkout credentials;
# don't leave the token behind in .git/config.
persist-credentials: false

- name: Setup Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
# Build releases with the exact toolchain declared in go.mod; a
# floating constraint makes builds unreproducible.
go-version-file: 'go.mod'
# Release builds must not restore a shared cache anyone with cache
# write access could poison.
cache: false

- name: Install syft
uses: anchore/sbom-action/download-syft@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0

- name: Run GoReleaser
uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3
with:
# Pinned exactly: a floating constraint would pull whatever the
# newest GoReleaser release is at tag time.
version: v2.17.0
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}

- name: Attest build provenance
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
subject-checksums: dist/checksums.txt
95 changes: 95 additions & 0 deletions .github/workflows/snapshot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
on:
push:
branches: [main]

name: Snapshot

permissions: {}

# One snapshot at a time; a newer merge supersedes an in-flight build.
concurrency:
group: snapshot
cancel-in-progress: true

jobs:
snapshot:
runs-on: ubuntu-latest
permissions:
contents: write # create the snapshot prerelease
id-token: write # OIDC token for keyless provenance signing
attestations: write # store the provenance attestation
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
persist-credentials: false

- name: Setup Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: 'go.mod'
# Snapshot artifacts are published too; same cache-poisoning
# rationale as the release workflow.
cache: false

- name: Install syft
uses: anchore/sbom-action/download-syft@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0

- name: Build snapshot
uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3
with:
version: v2.17.0
# Snapshot mode never publishes; the steps below publish explicitly.
args: release --snapshot --clean

- name: Publish snapshot prerelease
id: publish
env:
GH_TOKEN: ${{ github.token }}
run: |
version=$(jq -r .version dist/metadata.json)
tag="snapshot-${version}"
gh release create "$tag" \
--prerelease \
--target "$GITHUB_SHA" \
--title "snapshot ${version}" \
--notes "Automated snapshot of main at ${GITHUB_SHA}. Not a stable release." \
dist/*.tar.gz dist/*.zip dist/checksums.txt dist/*.sbom.json
echo "tag=$tag" >> "$GITHUB_OUTPUT"

- name: Attest build provenance
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
subject-checksums: dist/checksums.txt

- name: Update snapshot cask in tap
env:
GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
TAG: ${{ steps.publish.outputs.tag }}
# The contents API commits without the token ever touching disk, and
# GitHub signs the commit (shows as verified).
run: |
./.github/scripts/render-snapshot-cask.sh dist "$TAG" > jira-cli-snapshot.rb
existing=$(gh api repos/rethab/homebrew-jira-cli/contents/Casks/jira-cli-snapshot.rb --jq .sha 2>/dev/null || true)
gh api -X PUT repos/rethab/homebrew-jira-cli/contents/Casks/jira-cli-snapshot.rb \
-f message="Snapshot cask update for $TAG" \
-f content="$(base64 -w0 jira-cli-snapshot.rb)" \
-f "committer[name]=github-actions[bot]" \
-f "committer[email]=41898282+github-actions[bot]@users.noreply.github.com" \
${existing:+-f sha="$existing"} > /dev/null

- name: Prune old snapshots
env:
GH_TOKEN: ${{ github.token }}
KEEP: '5'
# Tolerates failure: with immutable releases enabled, old snapshots
# cannot be deleted and simply accumulate.
run: |
gh release list --limit 100 --json tagName,createdAt \
--jq '[.[] | select(.tagName | startswith("snapshot-"))] | sort_by(.createdAt) | reverse | .[].tagName' \
| tail -n "+$((KEEP + 1))" \
| while read -r tag; do
gh release delete "$tag" --cleanup-tag --yes \
|| echo "could not prune $tag (immutable releases?)"
done
Loading