Files
zzet--gortex/.github/workflows/publish-claude-plugin.yml
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

187 lines
7.2 KiB
YAML

# publish-claude-plugin syncs the generated marketplace bundle from
# this repo to gortexhq/claude-plugin on every gortex release.
#
# How it works:
# 1. Checkout gortex at the released tag
# 2. Regenerate the bundle via `make claude-plugin`
# 3. Checkout gortexhq/claude-plugin into a sibling directory
# 4. rsync the regenerated bundle into the publish-target checkout
# 5. If git status is empty (bundle unchanged vs current HEAD of the
# publish target) — exit 0, no push, no marketplace notification
# 6. Otherwise commit + push + tag
#
# The "skip when unchanged" step is what gates marketplace update
# notifications on real content changes. A gortex bug-fix release that
# doesn't touch internal/agents/claudecode/content.go produces no diff
# in the regenerated bundle, so the publish target is not updated and
# marketplace users are not pinged.
#
# Auth: CLAUDE_PLUGIN_TOKEN is a fine-grained PAT scoped to
# gortexhq/claude-plugin with `contents: write`. Mirrors the
# HOMEBREW_TAP_TOKEN pattern used by .goreleaser.yml's homebrew_casks
# block — same trust profile.
name: publish-claude-plugin
on:
release:
types: [published]
workflow_dispatch:
inputs:
ref:
description: "Gortex tag (or branch) to publish from. Required for manual runs."
required: true
type: string
permissions:
contents: read
concurrency:
# Serialise publishes; two concurrent runs against the same target
# repo would race on the push.
group: publish-claude-plugin
cancel-in-progress: false
jobs:
publish:
runs-on: ubuntu-latest
env:
PLUGIN_REPO: gortexhq/claude-plugin
# Branch on the publish target repo to push to. Plugin repo is
# single-branch by design; tags drive provenance.
PLUGIN_BRANCH: main
steps:
- name: Resolve gortex ref
id: resolve
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
REF="${{ inputs.ref }}"
else
REF="${{ github.ref_name }}"
fi
if [ -z "$REF" ]; then
echo "::error::could not resolve gortex ref to publish from"
exit 1
fi
echo "ref=$REF" >> "$GITHUB_OUTPUT"
echo "Publishing from gortex ref: $REF"
- name: Checkout gortex
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: ${{ steps.resolve.outputs.ref }}
path: gortex
- name: Set up Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
with:
go-version-file: gortex/go.mod
cache: true
cache-dependency-path: gortex/go.sum
- name: Regenerate plugin bundle
working-directory: gortex
run: make claude-plugin
- name: Checkout publish target
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
repository: ${{ env.PLUGIN_REPO }}
ref: ${{ env.PLUGIN_BRANCH }}
path: plugin-repo
token: ${{ secrets.CLAUDE_PLUGIN_TOKEN }}
# Need full history so the tag-already-exists check works
# against historical tags, not just HEAD.
fetch-depth: 0
- name: Sync bundle into publish target
run: |
# rsync replaces the publish target's tracked content with
# the freshly-regenerated bundle. --delete removes files that
# no longer exist in the source (e.g. a removed skill). The
# --exclude entries protect repo-level files we don't manage
# from the gortex side: .git/, .github/ (publish target may
# carry its own readme-only CI), and a top-level README/LICENSE
# if the publish target maintains its own.
rsync -av --delete \
--exclude='.git/' \
--exclude='.github/' \
gortex/claude-plugin/ \
plugin-repo/
- name: Detect content changes
id: diff
working-directory: plugin-repo
run: |
git add -A
if git diff --cached --quiet; then
echo "changed=false" >> "$GITHUB_OUTPUT"
echo "No content changes vs ${{ env.PLUGIN_REPO }}@${{ env.PLUGIN_BRANCH }}; nothing to publish"
else
echo "changed=true" >> "$GITHUB_OUTPUT"
echo "Detected content changes:"
git diff --cached --stat
fi
- name: Commit and push
if: steps.diff.outputs.changed == 'true'
working-directory: plugin-repo
env:
GORTEX_REF: ${{ steps.resolve.outputs.ref }}
run: |
git config user.name "gortex-bot"
git config user.email "bot@gortex.dev"
git commit -m "Sync from gortex ${GORTEX_REF}"
# Fully-qualified refspec — fails loudly on any future name
# collision instead of pushing the wrong ref ambiguously.
git push origin "refs/heads/${{ env.PLUGIN_BRANCH }}:refs/heads/${{ env.PLUGIN_BRANCH }}"
- name: Tag publish target with gortex version
if: steps.diff.outputs.changed == 'true'
working-directory: plugin-repo
env:
GORTEX_REF: ${{ steps.resolve.outputs.ref }}
run: |
# Tag the publish target with the gortex release tag that
# produced the content. Useful for provenance — a marketplace
# user can cross-reference the plugin version against the
# gortex release that built it.
#
# Three guards:
# 1. Skip when the gortex ref isn't a release tag.
# workflow_dispatch is allowed to take a branch (e.g.
# "main") for testing, but tagging the publish target
# with a branch name would collide with its own branches
# of the same name and fail the push with "src refspec
# matches more than one".
# 2. Skip silently if the tag already exists in the publish
# target — re-runs against the same gortex tag that
# produced no content change should be no-ops, not
# half-pushed states.
# 3. Use fully-qualified refspecs on the push so a future
# collision (branch and tag with the same name in the
# publish target) fails loudly rather than ambiguously.
if [[ ! "${GORTEX_REF}" =~ ^v[0-9] ]]; then
echo "Ref '${GORTEX_REF}' is not a release tag (does not match ^v[0-9]); skipping publish-target tag"
exit 0
fi
if git rev-parse --verify "refs/tags/${GORTEX_REF}" >/dev/null 2>&1; then
echo "Tag ${GORTEX_REF} already exists in ${{ env.PLUGIN_REPO }}; skipping"
exit 0
fi
git tag -a "${GORTEX_REF}" -m "Plugin bundle from gortex ${GORTEX_REF}"
git push origin "refs/tags/${GORTEX_REF}:refs/tags/${GORTEX_REF}"
- name: Summary
if: always()
run: |
{
echo "### Publish summary"
echo ""
echo "- Source ref: \`${{ steps.resolve.outputs.ref }}\`"
echo "- Target repo: \`${{ env.PLUGIN_REPO }}\`"
echo "- Content changed: \`${{ steps.diff.outputs.changed }}\`"
} >> "$GITHUB_STEP_SUMMARY"