name: Publish extra packages (deb, scoop, plugin)
on:
workflow_call:
inputs:
plan:
required: true
type: string
workflow_dispatch:
inputs:
tag:
description: Release tag to build packages for (e.g. v0.3.0)
required: true
type: string
jobs:
meta:
runs-on: ubuntu-latest
outputs:
tag: ${{ steps.meta.outputs.tag }}
prerelease: ${{ steps.meta.outputs.prerelease }}
steps:
- id: meta
env:
PLAN: ${{ inputs.plan }}
TAG_INPUT: ${{ inputs.tag }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
if [ -n "$TAG_INPUT" ]; then
tag="$TAG_INPUT"
prerelease=$(gh release view "$tag" --repo "${{ github.repository }}" --json isPrerelease -q .isPrerelease)
else
tag=$(jq -r .announcement_tag <<<"$PLAN")
prerelease=$(jq -r .announcement_is_prerelease <<<"$PLAN")
fi
echo "tag=$tag" >> "$GITHUB_OUTPUT"
echo "prerelease=$prerelease" >> "$GITHUB_OUTPUT"
deb:
needs: meta
if: ${{ needs.meta.outputs.prerelease != 'true' }}
runs-on: ubuntu-latest
permissions:
contents: write
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
arch: amd64
- target: aarch64-unknown-linux-gnu
arch: arm64
steps:
- uses: actions/checkout@v4
- name: Download release archive
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
mkdir dl
gh release download "${{ needs.meta.outputs.tag }}" \
--repo "${{ github.repository }}" \
--pattern "veloci-cli-${{ matrix.target }}.tar.xz" \
--dir dl
- name: Extract binary
run: |
mkdir extracted
# cargo-dist wraps archive contents in a veloci-cli-<target>/ directory.
tar -xJf "dl/veloci-cli-${{ matrix.target }}.tar.xz" -C extracted --strip-components=1
- name: Build .deb
run: |
TAG="${{ needs.meta.outputs.tag }}"
VERSION="${TAG#v}"
./scripts/build-deb.sh veloci "$VERSION" "${{ matrix.arch }}" \
extracted/veloci \
"Command-line interface for Veloci Redactor: redact secrets and PII from text and structured files" \
"https://github.com/phayes/velociredactor" \
extracted
- name: Upload .deb to release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release upload "${{ needs.meta.outputs.tag }}" \
--repo "${{ github.repository }}" \
veloci_*_${{ matrix.arch }}.deb
scoop:
needs: meta
if: ${{ needs.meta.outputs.prerelease != 'true' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Download windows archive + checksum
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
mkdir dl
gh release download "${{ needs.meta.outputs.tag }}" \
--repo "${{ github.repository }}" \
--pattern "veloci-cli-x86_64-pc-windows-msvc.zip*" \
--dir dl
- name: Generate manifest
run: |
TAG="${{ needs.meta.outputs.tag }}"
VERSION="${TAG#v}"
SHA=$(awk '{print $1}' dl/veloci-cli-x86_64-pc-windows-msvc.zip.sha256)
./scripts/gen-scoop-manifest.sh veloci "$VERSION" \
"Command-line interface for Veloci Redactor: redact secrets and PII from text and structured files" \
"https://github.com/phayes/velociredactor" \
"MIT" \
velociredactor "$TAG" \
veloci-cli-x86_64-pc-windows-msvc.zip veloci "$SHA"
- name: Publish to scoop-bucket
env:
GH_TOKEN: ${{ secrets.SCOOP_BUCKET_TOKEN }}
run: |
git clone "https://x-access-token:${GH_TOKEN}@github.com/phayes/scoop-bucket.git" bucket-repo
cp veloci.json bucket-repo/bucket/veloci.json
cd bucket-repo
git config user.email "patrick.d.hayes@gmail.com"
git config user.name "Patrick Hayes"
git add bucket/veloci.json
if git diff --cached --quiet; then
echo "manifest unchanged, nothing to push"
exit 0
fi
git commit -m "veloci ${{ needs.meta.outputs.tag }}"
git push
plugin-winarm64:
needs: meta
if: ${{ needs.meta.outputs.prerelease != 'true' }}
runs-on: windows-11-arm
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: aarch64-pc-windows-msvc
- name: Build aarch64-pc-windows-msvc (plugin only)
run: cargo build --release --locked --package veloci-cli --target aarch64-pc-windows-msvc
env:
RUSTFLAGS: -C strip=symbols
- uses: actions/upload-artifact@v4
with:
name: winarm64-binary
path: target/aarch64-pc-windows-msvc/release/veloci.exe
plugin:
needs: [meta, plugin-winarm64]
if: ${{ needs.meta.outputs.prerelease != 'true' }}
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: winarm64-binary
path: winarm64
- name: Download release archives
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
mkdir dl
for asset in \
veloci-cli-aarch64-apple-darwin.tar.xz \
veloci-cli-x86_64-apple-darwin.tar.xz \
veloci-cli-aarch64-unknown-linux-gnu.tar.xz \
veloci-cli-x86_64-unknown-linux-gnu.tar.xz \
veloci-cli-x86_64-pc-windows-msvc.zip; do
gh release download "${{ needs.meta.outputs.tag }}" \
--repo "${{ github.repository }}" \
--pattern "$asset" \
--dir dl
done
- name: Assemble libexec binaries
shell: bash
run: |
set -euo pipefail
mkdir -p plugin/libexec
for target in aarch64-apple-darwin x86_64-apple-darwin aarch64-unknown-linux-gnu x86_64-unknown-linux-gnu; do
extract="extracted-${target}"
mkdir -p "$extract"
tar -xJf "dl/veloci-cli-${target}.tar.xz" -C "$extract" --strip-components=1
cp "$extract/veloci" "plugin/libexec/veloci-${target}"
done
# Unlike the tarballs, cargo-dist's Windows zip has no wrapping directory.
extract="extracted-x86_64-pc-windows-msvc"
mkdir -p "$extract"
unzip -q "dl/veloci-cli-x86_64-pc-windows-msvc.zip" -d "$extract"
cp "$extract/veloci.exe" "plugin/libexec/veloci-x86_64-pc-windows-msvc.exe"
cp winarm64/veloci.exe "plugin/libexec/veloci-aarch64-pc-windows-msvc.exe"
- name: Assemble plugin
shell: bash
run: |
set -euo pipefail
version="${{ needs.meta.outputs.tag }}"
version="${version#v}"
# Artifacts lose the executable bit; the launcher's is kept by git.
chmod +x plugin/bin/veloci plugin/libexec/*
for target in \
aarch64-apple-darwin x86_64-apple-darwin \
aarch64-unknown-linux-gnu x86_64-unknown-linux-gnu \
aarch64-pc-windows-msvc.exe x86_64-pc-windows-msvc.exe; do
test -f "plugin/libexec/veloci-${target}" || { echo "missing veloci-${target}" >&2; exit 1; }
done
# Claude Code detects updates by plugin.json's version.
jq --arg v "$version" '.version = $v' plugin/.claude-plugin/plugin.json > plugin.json.tmp
mv plugin.json.tmp plugin/.claude-plugin/plugin.json
plugin/bin/veloci --version
- name: Validate plugin
run: npx --yes @anthropic-ai/claude-code plugin validate ./plugin
- name: Package plugin
run: |
set -euo pipefail
mkdir -p dist
(cd plugin && zip -r -X ../dist/veloci-plugin.zip .)
(cd dist && sha256sum veloci-plugin.zip > veloci-plugin.zip.sha256)
- uses: actions/upload-artifact@v4
with:
name: veloci-plugin
path: dist/
plugin-windows:
needs: plugin
strategy:
matrix:
runner: [windows-latest, windows-11-arm]
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/download-artifact@v4
with:
name: veloci-plugin
path: dist
- name: Unpack plugin and write a hook input
shell: pwsh
run: |
Expand-Archive dist/veloci-plugin.zip -DestinationPath plugin
New-Item -ItemType Directory proj | Out-Null
Set-Content proj/.env 'TOKEN=1'
@{
tool_name = 'Read'
tool_input = @{ file_path = '.env' }
cwd = (Resolve-Path proj).Path
} | ConvertTo-Json -Compress | Set-Content hook-input.json
- name: Run the launcher and hook from cmd, without bash
shell: cmd
run: |
set "PATH=%SystemRoot%\System32;%SystemRoot%"
where bash >nul 2>&1 && (echo bash is on PATH & exit /b 1)
set "PATH=%GITHUB_WORKSPACE%\plugin\bin;%PATH%"
call veloci --version || exit /b 1
cd proj
call veloci agent init --protect .env --enforce || exit /b 1
rem The hook's command as hooks.json writes it: an extensionless path.
cmd /d /s /c ""%GITHUB_WORKSPACE%\plugin/bin/veloci" agent hook" < ..\hook-input.json > ..\hook-output.json || exit /b 1
- name: Check the hook denied the read, and run veloci from PowerShell
shell: pwsh
run: |
$decision = (Get-Content hook-output.json | ConvertFrom-Json).hookSpecificOutput.permissionDecision
if ($decision -ne 'deny') { Get-Content hook-output.json; throw "hook did not deny the read" }
$env:PATH = "$env:GITHUB_WORKSPACE\plugin\bin;$env:SystemRoot\System32;$env:SystemRoot"
veloci --version
if ($LASTEXITCODE -ne 0) { throw "veloci exited $LASTEXITCODE" }
plugin-publish:
needs: [meta, plugin, plugin-windows]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@v4
with:
name: veloci-plugin
path: dist
- name: Upload plugin to release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release upload "${{ needs.meta.outputs.tag }}" \
--repo "${{ github.repository }}" \
dist/veloci-plugin.zip dist/veloci-plugin.zip.sha256