惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IT之家
IT之家
博客园 - 聂微东
雷峰网
雷峰网
Microsoft Azure Blog
Microsoft Azure Blog
WordPress大学
WordPress大学
Hugging Face - Blog
Hugging Face - Blog
S
SegmentFault 最新的问题
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Tailwind CSS Blog
博客园 - 三生石上(FineUI控件)
V
Visual Studio Blog
博客园 - 司徒正美
爱范儿
爱范儿
月光博客
月光博客
阮一峰的网络日志
阮一峰的网络日志
博客园_首页
博客园 - 【当耐特】
Jina AI
Jina AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
酷 壳 – CoolShell
酷 壳 – CoolShell
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
人人都是产品经理
人人都是产品经理
V
V2EX

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Tag release pipelines without a 400-line GitHub Actions w...
Abhiuday · 2026-06-14 · via DEV Community

Abhiuday

You push v1.2.3 and expect a predictable sequence: tests pass → version is resolved → GitHub Release is created. In practice, teams usually pick one of two painful options:

  1. One giant workflow — every stage in a single YAML file. It works until you need reuse, workflow_call, or different triggers per stage.
  2. workflow_run chains — workflow A triggers workflow B. Passing outputs between runs is awkward, and renaming a workflow breaks the chain silently.

There is a middle path: keep small, focused stage workflows (the ones you already have), declare order and wiring in one pipeline file, and use a single orchestrator step on tag push.

This tutorial uses pipeline-compose-run — available on the GitHub Marketplace — and a copy-paste example you can drop into any repo.

Full example (copy .github/): examples/run-tag-release


What we are building

On git push origin v*:

release.yml          ← one job, one action step
  └─ pipeline.yml    ← declares order + wiring
       ├─ ci.yml
       ├─ stage-version-sync.yml     → exports version
       └─ stage-release-publish.yml  ← receives version

No generated workflow to commit. No manual workflow_run graph.


Step 1 — Entry workflow

Create .github/workflows/release.yml:

name: Release
on:
  push:
    tags: ["v*"]

permissions:
  contents: write
  actions: write

jobs:
  run-pipeline:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: aeswibon/pipeline-compose-run@v0.3.0
        with:
          pipeline_file: .github/pipelines/pipeline.yml
          github_token: ${{ github.token }}

The actions: write permission is required because the action dispatches your stage workflows via workflow_dispatch.


Step 2 — Pipeline file (order only)

Create .github/pipelines/pipeline.yml:

name: pipeline
version: 1
stages:
  - id: ci
    workflow: .github/workflows/ci.yml

  - id: version-sync
    workflow: .github/workflows/stage-version-sync.yml
    needs:
      - ci
    outputs:
      - version

  - id: release-publish
    workflow: .github/workflows/stage-release-publish.yml
    needs:
      - version-sync
    inputs:
      version: ${{ context.version-sync.version }}

This file is the source of truth for order. Stage implementations stay in normal workflow files you can also run manually or reuse via workflow_call.

The ${{ context.version-sync.version }} syntax resolves at runtime from the completed version-sync stage.


Step 3 — Stage workflows

Each stage must include workflow_dispatch. Downstream stages that receive values need matching workflow_dispatch inputs.

CI (.github/workflows/ci.yml)

name: CI
on:
  workflow_dispatch:
  push:
    branches: [master]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - run: echo "Replace with your test/lint commands"

Version sync — export outputs

GitHub’s API does not return job outputs for workflow_dispatch runs. pipeline-compose collects stage outputs from an artifact:

  • Artifact name: pipeline-compose-<stage-id>
  • File: outputs.json with your output keys
name: Version sync
on:
  workflow_dispatch:

jobs:
  version-sync:
    runs-on: ubuntu-latest
    steps:
      - name: Resolve semver from ref
        id: version
        run: |
          ref="${GITHUB_REF}"
          if [[ "$ref" =~ ^refs/tags/v(.+)$ ]]; then
            echo "value=${BASH_REMATCH[1]}" >> "$GITHUB_OUTPUT"
          else
            echo "Expected a version tag ref, got: $ref" >&2
            exit 1
          fi

      - name: Export outputs for pipeline-compose
        if: success()
        env:
          VERSION: ${{ steps.version.outputs.value }}
        run: |
          mkdir -p pipeline-compose
          jq -n --arg version "$VERSION" '{version: $version}' > pipeline-compose/outputs.json

      - uses: actions/upload-artifact@v4
        if: success()
        with:
          name: pipeline-compose-version-sync
          path: pipeline-compose/outputs.json
          retention-days: 1

Note the artifact name matches the stage id: pipeline-compose-version-sync.

Release publish — consume version input

name: Release publish
on:
  workflow_dispatch:
    inputs:
      version:
        description: Semver without v prefix
        type: string
        required: true

permissions:
  contents: write

jobs:
  create-release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 0

      - name: Create release
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          VERSION: ${{ inputs.version }}
        run: |
          tag="v${VERSION}"
          if gh release view "$tag" >/dev/null 2>&1; then
            echo "Release $tag already exists"
            exit 0
          fi
          gh release create "$tag" --title "$tag" --generate-notes


Step 4 — Ship it

git tag v1.0.0 && git push origin v1.0.0

Open Actions → Release in your repo. Stages run in pipeline order; publish receives the version from sync.


Why not other approaches?

Approach Pain point
Monolithic workflow Hard to reuse stages; noisy diffs
workflow_run chains Fragile; outputs don’t flow cleanly
Generated workflow (compile) Works, but you commit generated YAML
pipeline-compose-run Ordered dispatch + context; one pipeline file

If you prefer committing a static graph with native GitHub needs:, see pipeline-compose-compile instead.


Troubleshooting

Symptom Fix
403 on dispatch Add actions: write on the entry job
Publish stage missing version Artifact must be pipeline-compose-version-sync with outputs.json
Stage never runs Add workflow_dispatch to that workflow
Wrong ref in stage Pass ref: to the run action if needed

Try it now

  1. Marketplace: pipeline-compose-run
  2. Copy-paste example: examples/run-tag-release
  3. More examples: pipeline-compose/examples

Part of pipeline-compose. MIT License.