Skip to content

feat(ci): overhaul CI/CD with smart detection & optimized caching #1

feat(ci): overhaul CI/CD with smart detection & optimized caching

feat(ci): overhaul CI/CD with smart detection & optimized caching #1

Workflow file for this run

# .github/workflows/_publish.yml
name: _publish
on:
workflow_call:
inputs:
dry_run:
type: boolean
required: false
default: false
description: "Run in dry-run mode"
permissions:
contents: read
packages: write
id-token: write
concurrency:
group: publish-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
env:
IGGY_CI_BUILD: true
jobs:
parse:
name: Parse tag
runs-on: ubuntu-latest
outputs:
matched: ${{ steps.p.outputs.matched }}
version: ${{ steps.p.outputs.version }}
targets: ${{ steps.p.outputs.targets }}
valid: ${{ steps.p.outputs.valid }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Load publish config
id: config
run: |
if ! command -v yq &> /dev/null; then
wget -qO /tmp/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64
chmod +x /tmp/yq
sudo mv /tmp/yq /usr/local/bin/yq
fi
# NOTE: this now reads the `.publish` root from config
echo "publish_config=$(yq -o=json -I=0 '.publish' .github/config/publish.yml | jq -c)" >> $GITHUB_OUTPUT
- name: Parse tag and determine targets
id: p
uses: actions/github-script@v7
with:
script: |
const ref = context.ref;
const tag = ref.split('/').pop();
core.info(`Processing tag: ${tag}`);
let config = {};
try {
config = JSON.parse(`${{ steps.config.outputs.publish_config }}`) || {};
} catch (e) {
core.setFailed('Invalid publish configuration');
core.setOutput('valid', 'false');
return;
}
for (const [name, cfg] of Object.entries(config)) {
const re = new RegExp(cfg.tag_pattern);
const m = tag.match(re);
if (!m) continue;
const version = (m[1] || '').trim();
if (!version) {
core.setFailed(`Matched ${name} but failed to extract version from tag using capture group 1`);
core.setOutput('valid', 'false');
return;
}
core.info(`✓ Matched: ${name}, Version: ${version}`);
core.setOutput('matched', name);
core.setOutput('version', version);
core.setOutput('targets', JSON.stringify(cfg.targets || []));
core.setOutput('valid', 'true');
return;
}
core.setFailed(`Tag ${tag} didn't match any publish pattern`);
core.setOutput('valid', 'false');
publish:
name: Publish ${{ matrix.target.type }}
needs: parse
if: needs.parse.outputs.valid == 'true'
runs-on: ubuntu-latest
environment: release
strategy:
fail-fast: false
matrix:
target: ${{ fromJson(needs.parse.outputs.targets) }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Publish (Docker)
if: matrix.target.type == 'docker-buildx'
uses: ./.github/actions/docker-buildx
with:
component: ${{ matrix.target.component || '' }}
image: ${{ matrix.target.image || '' }}
dockerfile:${{ matrix.target.dockerfile || '' }}

Check failure on line 109 in .github/workflows/_publish.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/_publish.yml

Invalid workflow file

You have an error in your yaml syntax on line 109
version: ${{ needs.parse.outputs.version }}
push: ${{ !inputs.dry_run }}
- name: Publish (Rust crates)
if: matrix.target.type == 'rust'
uses: ./.github/actions/rust
with:
task: publish
package: ${{ matrix.target.package }}
version: ${{ needs.parse.outputs.version }}
dry_run: ${{ inputs.dry_run }}
- name: Publish (Python)
if: matrix.target.type == 'python-maturin'
uses: ./.github/actions/python-maturin
with:
task: publish
version: ${{ needs.parse.outputs.version }}
dry_run: ${{ inputs.dry_run }}
- name: Publish (Node)
if: matrix.target.type == 'node-npm'
uses: ./.github/actions/node-npm
with:
task: publish
version: ${{ needs.parse.outputs.version }}
dry_run: ${{ inputs.dry_run }}
- name: Publish (Java)
if: matrix.target.type == 'java-gradle'
uses: ./.github/actions/java-gradle
with:
task: publish
version: ${{ needs.parse.outputs.version }}
dry_run: ${{ inputs.dry_run }}
- name: Publish (C#)
if: matrix.target.type == 'csharp-dotnet'
uses: ./.github/actions/csharp-dotnet
with:
task: publish
version: ${{ needs.parse.outputs.version }}
dry_run: ${{ inputs.dry_run }}
- name: Publish (Go)
if: matrix.target.type == 'go'
run: |
echo "New go tag detected: v${{ needs.parse.outputs.version }} (no publish action required)"
env:
# Rust
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
# Docker Hub
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
# PyPI
PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
# npm
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
# Nexus
NEXUS_USER: ${{ secrets.NEXUS_USER }}
NEXUS_PASSWORD: ${{ secrets.NEXUS_PW }}
# NuGet
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
summary:
name: Publish Summary
needs: [parse, publish]
if: always()
runs-on: ubuntu-latest
steps:
- name: Summary
run: |
echo "# 📦 Publish Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ needs.parse.outputs.valid }}" != "true" ]; then
echo "❌ Invalid tag - no matching publish pattern" >> $GITHUB_STEP_SUMMARY
exit 1
fi
echo "- **Component**: ${{ needs.parse.outputs.matched }}" >> $GITHUB_STEP_SUMMARY
echo "- **Version**: ${{ needs.parse.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "- **Status**: ${{ needs.publish.result }}" >> $GITHUB_STEP_SUMMARY
- name: Create issue on failure
if: failure() && !inputs.dry_run
uses: actions/github-script@v7
with:
script: |
const tag = context.ref.replace('refs/tags/', '');
await github.rest.issues.create({
...context.repo,
title: `Publish failed for ${tag}`,
body: `Failed to publish tag \`${tag}\`\n\n[View run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})`,
labels: ['ci', 'publish-failure', 'automated']
});