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
64 changes: 58 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,69 @@
name: Release

# Releases the newest version in CHANGELOG.md when no tag exists for it yet.
# The test matrix must pass before the tag and the GitHub release are created.
on:
push:
tags:
- "v*.*.*"
branches:
- master
paths:
- CHANGELOG.md
workflow_dispatch: {}

permissions: {}

concurrency:
group: release-${{ github.workflow }}-${{ github.ref }}
group: release-${{ github.workflow }}
Comment thread
cloudsmith-iduffy marked this conversation as resolved.
cancel-in-progress: false
queue: max

jobs:
version:
name: Find the version to release
if: github.ref == 'refs/heads/master'
permissions:
contents: read
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
tag: ${{ steps.version.outputs.tag }}
released: ${{ steps.version.outputs.released }}
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Read the newest CHANGELOG version
id: version
run: |
set -euo pipefail
version="$(sed -n 's/^## \[\([0-9]*\.[0-9]*\.[0-9]*\)\].*/\1/p' CHANGELOG.md | head -n 1)"
test -n "$version"
tag="v$version"
echo "tag=$tag" >> "$GITHUB_OUTPUT"
status=0
git ls-remote --exit-code --tags origin "refs/tags/$tag" > /dev/null || status=$?
case "$status" in
0) echo "$tag is already released"; echo "released=true" >> "$GITHUB_OUTPUT" ;;
2) echo "$tag is not released yet"; echo "released=false" >> "$GITHUB_OUTPUT" ;;
*) exit "$status" ;;
esac

test:
name: Test
needs: version
if: needs.version.outputs.released == 'false'
permissions:
contents: read
id-token: write # required whenever OIDC inputs are set
uses: $/.github/workflows/test.yml
secrets:
CLOUDSMITH_API_KEY: ${{ secrets.CLOUDSMITH_API_KEY }}

release:
name: Create release and move major tag
needs: [version, test]
permissions:
contents: write # create the release and move the major tag
runs-on: ubuntu-latest
Expand All @@ -27,13 +77,15 @@ jobs:
- name: Create GitHub release
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.ref_name }}
run: gh release create "$TAG" --title "Release $TAG" --verify-tag
TAG: ${{ needs.version.outputs.tag }}
run: |
gh release view "$TAG" > /dev/null 2>&1 \
|| gh release create "$TAG" --title "Release $TAG" --target "$GITHUB_SHA"

- name: Update floating major tag
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.ref_name }}
TAG: ${{ needs.version.outputs.tag }}
run: |
major="${TAG%%.*}"
echo "Pointing $major at $TAG ($GITHUB_SHA)"
Expand Down
51 changes: 51 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ name: Test
on:
push:
workflow_dispatch: {}
workflow_call:
secrets:
CLOUDSMITH_API_KEY:
required: false

permissions:
contents: read
Expand All @@ -26,6 +30,8 @@ jobs:
run: |
bash -n scripts/setup.sh
bash -n scripts/test-setup.sh
bash -n scripts/bump-cli-version.sh
bash -n scripts/test-bump-cli-version.sh
sh -n installer/install.sh

- name: Install ShellCheck
Expand All @@ -35,6 +41,8 @@ jobs:
run: |
shellcheck --severity=style scripts/setup.sh
shellcheck --severity=style scripts/test-setup.sh
shellcheck --severity=style scripts/bump-cli-version.sh
shellcheck --severity=style scripts/test-bump-cli-version.sh
shellcheck --shell=sh --severity=style installer/install.sh

lint-powershell:
Expand Down Expand Up @@ -94,6 +102,11 @@ jobs:
shell: bash
run: bash scripts/test-setup.sh

- name: Test CLI version bump
if: runner.os != 'Windows'
shell: bash
run: bash scripts/test-bump-cli-version.sh

- name: Test PowerShell setup
if: runner.os == 'Windows'
shell: pwsh
Expand Down Expand Up @@ -163,6 +176,18 @@ jobs:
test -n "$OUTPUT_BIN_DIRECTORY"
cloudsmith --version | tr -d '\r' | grep -Fx "CLI Package Version: $OUTPUT_CLI_VERSION"

- name: Check the pinned CLI version
shell: bash
env:
OUTPUT_CLI_VERSION: ${{ steps.setup.outputs.cli-version }}
run: |
set -euo pipefail
pinned_version="$(tr -d '\r' < action.yml | awk '
/^ cli-version:/ { in_cli_version = 1 }
in_cli_version && /^ default:/ { gsub(/"/, "", $2); print $2; exit }
')"
test "$OUTPUT_CLI_VERSION" = "$pinned_version"

- name: Check exported environment
shell: bash
run: |
Expand Down Expand Up @@ -212,6 +237,32 @@ jobs:
test "$CLOUDSMITH_OIDC_AUDIENCE" = "test-audience"
cloudsmith --version | tr -d '\r' | grep -Fx "CLI Package Version: 1.20.1"

test-latest-version:
name: Install latest version
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Install Cloudsmith CLI
id: setup
uses: $/
with:
cli-version: latest
api-key: placeholder-key

- name: Check installation
shell: bash
env:
OUTPUT_CLI_VERSION: ${{ steps.setup.outputs.cli-version }}
run: |
set -euo pipefail
test -n "$OUTPUT_CLI_VERSION"
cloudsmith --version | tr -d '\r' | grep -Fx "CLI Package Version: $OUTPUT_CLI_VERSION"

test-input-validation:
name: Input validation
runs-on: ubuntu-latest
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
---

## [3.2.0] - 2026-10-01
---
### Changed

- `cli-version` now defaults to a pinned Cloudsmith CLI version (1.27.0) instead of `latest`. A workflow that pins this action to a commit SHA now installs the same CLI version on every run. Set `cli-version: latest` to keep the previous floating behavior.
- Each Cloudsmith CLI release now opens a pull request that pins the new CLI version. When the pull request merges, the action publishes a patch release, or a minor release if unreleased changes are pending, and moves the `v3` tag.

## [3.1.1] - 2026-09-10
---
### Fixed
Expand Down
18 changes: 18 additions & 0 deletions CONTRIBUTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,29 @@ Thank you for considering contributing to the Cloudsmith CLI Setup action!
shellcheck --severity=style scripts/setup.sh
pwsh -Command "Invoke-ScriptAnalyzer -Path scripts/setup.ps1 -Settings PSGallery -EnableExit"
bash scripts/test-setup.sh
bash scripts/test-bump-cli-version.sh
pwsh -NoProfile -File scripts/test-setup.ps1
```

4. Commit, push to your fork, and open a pull request.

## Releasing

The `Release` workflow runs when `CHANGELOG.md` changes on `master`. If the
newest version in `CHANGELOG.md` has no tag, the workflow runs the test
matrix. When the tests pass, it creates the tag and the GitHub release. It
also moves the floating major tag, for example `v3`, to the new release.

To release action changes, add a version section to `CHANGELOG.md` in a pull
request. Use a minor or major version as Semantic Versioning requires.

Each Cloudsmith CLI release opens a pull request from `cloudsmith-bot`. The
release workflow of the CLI runs `scripts/bump-cli-version.sh` to make the
change. The script pins the default `cli-version` in `action.yml` to the new
CLI version. It also adds a patch version section to `CHANGELOG.md`. If
`[Unreleased]` has entries, the script adds a minor version section that
includes them. Merge the pull request to release it.

## Variables and Secrets for GitHub Actions

The install and validation test jobs run without any configuration. To run the
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Install the standalone [Cloudsmith CLI](https://github.com/cloudsmith-io/cloudsm
| Runners | Linux, macOS, and Windows |
| Architectures | x86-64, plus Linux and macOS ARM64 |
| Runtime dependencies | No Python or Node.js; `export-auth-token` additionally uses `jq` on Linux and macOS |
| Version selection | Latest release or a specific CLI version |
| Version selection | A CLI version pinned by each action release, a specific CLI version, or the latest release |

## Quick start

Expand Down Expand Up @@ -96,7 +96,7 @@ An authentication method is required: provide `api-key`, or provide both `oidc-n

| Input | Description | Required | Default |
| --- | --- | --- | --- |
| `cli-version` | CLI version to install, such as `1.20.0` | No | `latest` |
| `cli-version` | CLI version to install, such as `1.20.0`, or `latest` | No | The CLI version that the action release pins |
| `install-directory` | Root directory for versioned CLI installations | No | `RUNNER_TEMP/cloudsmith-cli` |
| `verify-auth` | Run `cloudsmith whoami` after setup | No | `false` |

Expand Down
4 changes: 2 additions & 2 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ branding:

inputs:
cli-version:
description: "Cloudsmith CLI version to install, for example '1.20.0', or 'latest'."
description: "Cloudsmith CLI version to install, for example '1.20.0', or 'latest'. Defaults to the CLI version that this action release pins."
required: false
default: "latest"
default: "1.27.0"
install-directory:
description: "Root directory for versioned CLI installations. Defaults to RUNNER_TEMP/cloudsmith-cli."
required: false
Expand Down
62 changes: 62 additions & 0 deletions scripts/bump-cli-version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env bash
Comment thread
cloudsmith-iduffy marked this conversation as resolved.
# Pins the default cli-version in action.yml to a new Cloudsmith CLI release
# and records the change as a release of the action in CHANGELOG.md. The
# release is a patch release, or a minor release that also includes the
# entries under [Unreleased] when there are any.
# Prints the new action version. Prints nothing when action.yml already pins
# that version or a newer one.
# Usage: scripts/bump-cli-version.sh CLI_VERSION
set -euo pipefail

cli_version="${1:-}"
[[ "$cli_version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] \
|| { echo "usage: $0 MAJOR.MINOR.PATCH" >&2; exit 1; }

pinned_version="$(awk '
/^ cli-version:/ { in_cli_version = 1 }
in_cli_version && /^ default:/ { gsub(/"/, "", $2); print $2; exit }
' action.yml)"
[[ -n "$pinned_version" ]] || { echo "no cli-version default in action.yml" >&2; exit 1; }
newest_version="$(printf '%s\n' "$pinned_version" "$cli_version" | sort -V | tail -n 1)"
if [[ "$pinned_version" == "$newest_version" ]]; then
echo "action.yml already pins Cloudsmith CLI $pinned_version" >&2
exit 0
fi

released_version="$(sed -n 's/^## \[\([0-9]*\.[0-9]*\.[0-9]*\)\].*/\1/p' CHANGELOG.md | head -n 1)"
[[ -n "$released_version" ]] || { echo "no released version in CHANGELOG.md" >&2; exit 1; }
unreleased_changes="$(awk '
/^## \[/ { in_unreleased = ($0 == "## [Unreleased]"); next }
in_unreleased && $0 != "" && $0 != "---"
' CHANGELOG.md)"
IFS=. read -r major minor patch <<< "$released_version"
if [[ -n "$unreleased_changes" ]]; then
action_version="$major.$(( minor + 1 )).0"
else
action_version="$major.$minor.$(( patch + 1 ))"
fi

awk -v cli_version="$cli_version" '
/^ cli-version:/ { in_cli_version = 1 }
in_cli_version && /^ default:/ { sub(/".*"/, "\"" cli_version "\""); in_cli_version = 0 }
{ print }
' action.yml > action.yml.new
mv action.yml.new action.yml

awk -v action_version="$action_version" -v cli_version="$cli_version" -v today="$(date -u +%Y-%m-%d)" '
inserted && $0 != "" { print "" }
{ inserted = 0; print }
previous == "## [Unreleased]" && $0 == "---" {
inserted = 1
print ""
print "## [" action_version "] - " today
print "---"
print "### Changed"
print ""
print "- Pin the default `cli-version` to Cloudsmith CLI " cli_version "."
}
{ previous = $0 }
' CHANGELOG.md > CHANGELOG.md.new
mv CHANGELOG.md.new CHANGELOG.md

echo "$action_version"
Loading
Loading