Skip to content

Releasing from any CI

A marketplace release is three steps the CLI gives you primitives for: build with release gates, produce checksums, publish a tagged release. Every CI system runs the same three commands. The wrappers below differ only in syntax.

This is the source of truth. Every wrapper on this page is a shell-script translation of these lines.

Terminal window
set -euo pipefail
VERSION="${VERSION:?VERSION must be set, e.g. v1.2.3}"
apm pack --check-versions --check-clean --json > pack-report.json
for f in build/*.tar.gz .claude-plugin/marketplace.json; do
[ -f "$f" ] || continue
sha256sum "$f" > "${f}.sha256"
done
gh release create "$VERSION" \
build/*.tar.gz \
build/*.tar.gz.sha256 \
.claude-plugin/marketplace.json \
.claude-plugin/marketplace.json.sha256 \
--title "$VERSION" \
--notes-file CHANGELOG.md

What each command does:

  • apm pack --check-versions --check-clean --json runs the pack with the release gates enabled. --check-versions fails if per-package versions disagree with marketplace.versioning.strategy. --check-clean fails if the on-disk marketplace.json does not match what a fresh pack would produce. --json writes a machine-readable summary to stdout; human logs go to stderr.
  • sha256sum produces one sidecar per artifact. Consumers verify with sha256sum -c <file>.sha256.
  • gh release create uploads the bundle, the marketplace artifact, and the sidecars under one tag. Use whichever release API your forge exposes; the file set is what matters.

Authenticate gh with a token that has contents: write on the repo. Substitute the equivalent verb for non-GitHub forges (glab release create, az repos, REST upload).

name: release
on:
push:
tags: ["v*"]
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: microsoft/apm-action@v1
with:
mode: release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

microsoft/apm-action@v1 with mode: release is a convenience wrapper for the canonical sequence above. It installs the CLI, runs apm pack --check-versions --check-clean --json, generates the sidecars, and calls gh release create against the pushed tag. Use it when you want one less script to maintain; use the raw run: form below when you need to customise any step.

- uses: actions/setup-python@v5
with: { python-version: "3.12" }
- run: pip install apm-cli
- run: |
apm pack --check-versions --check-clean --json > pack-report.json
for f in build/*.tar.gz .claude-plugin/marketplace.json; do
[ -f "$f" ] || continue
sha256sum "$f" > "${f}.sha256"
done
gh release create "${GITHUB_REF_NAME}" \
build/*.tar.gz build/*.tar.gz.sha256 \
.claude-plugin/marketplace.json* \
--title "${GITHUB_REF_NAME}" --notes-file CHANGELOG.md
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
release:
stage: release
image: python:3.12
rules:
- if: '$CI_COMMIT_TAG =~ /^v/'
script:
- pip install apm-cli
- apm pack --check-versions --check-clean --json > pack-report.json
- |
for f in build/*.tar.gz .claude-plugin/marketplace.json; do
[ -f "$f" ] || continue
sha256sum "$f" > "${f}.sha256"
done
- |
glab release create "$CI_COMMIT_TAG" \
build/*.tar.gz build/*.tar.gz.sha256 \
.claude-plugin/marketplace.json* \
--notes-file CHANGELOG.md
pipeline {
agent any
stages {
stage('release') {
when { tag pattern: "v.*", comparator: "REGEXP" }
steps {
sh '''
pip install apm-cli
apm pack --check-versions --check-clean --json > pack-report.json
for f in build/*.tar.gz .claude-plugin/marketplace.json; do
[ -f "$f" ] || continue
sha256sum "$f" > "${f}.sha256"
done
gh release create "${TAG_NAME}" \
build/*.tar.gz build/*.tar.gz.sha256 \
.claude-plugin/marketplace.json* \
--notes-file CHANGELOG.md
'''
}
}
}
}
trigger:
tags:
include: [refs/tags/v*]
pool: { vmImage: ubuntu-latest }
steps:
- task: UsePythonVersion@0
inputs: { versionSpec: "3.12" }
- script: pip install apm-cli
- script: apm pack --check-versions --check-clean --json > pack-report.json
- script: |
for f in build/*.tar.gz .claude-plugin/marketplace.json; do
[ -f "$f" ] || continue
sha256sum "$f" > "${f}.sha256"
done
- script: |
gh release create "$(Build.SourceBranchName)" \
build/*.tar.gz build/*.tar.gz.sha256 \
.claude-plugin/marketplace.json* \
--notes-file CHANGELOG.md
env:
GH_TOKEN: $(GITHUB_TOKEN)

apm pack exit codes you will see in CI:

CodeGateMeaning and fix
0-Pack succeeded; ship the artifacts.
1runtimeBuild or network error. Inspect the JSON report; rerun.
2schemaapm.yml is invalid. Fix the manifest before tagging.
3--check-versionsPer-package versions disagree with marketplace.versioning.strategy. See Versioning strategies.
4--check-cleanCommitted marketplace.json does not match a fresh pack. Run apm pack locally, commit the diff, re-tag.

The gates never write to disk — they only refuse to release. Recover by running the same apm pack locally without --check-*, inspecting the diff, and pushing a clean tag.