Promotion
Promotion workflows deploy releases to staging and production environments. This guide covers the promotion model, the manifest dispatch mechanism, and setting up promotion workflows.
Prerequisites
Before using promotion workflows, ensure you have:
- A GitHub release with a
digest.txtartifact from your build workflow - GitHub tag for the version you want to promote (required for staging and production)
- Repository secrets configured:
UPDATE_MANIFEST_TOKEN - Repository variables configured:
PLATFORM_DISPATCH_URL
The UPDATE_MANIFEST_TOKEN and PLATFORM_DISPATCH_URL are provisioned by the Ybor platform. If promotions are failing, contact your Admin or DevOps team to verify the configuration.
What You'll Learn
- The environment promotion model (dev → stg → prd)
- How manifest dispatch triggers deployments
- Setting up promotion workflows
- Tracking promotions in GitHub releases
Promotion Model
The platform uses a staged promotion model:
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Dev │ ──► │ Staging │ ──► │ Production │
│ │ │ │ │ │
│ Automatic │ │ Manual │ │ Manual │
│ on merge │ │ promotion │ │ promotion │
└─────────────┘ └─────────────┘ └─────────────┘
| Environment | Trigger | Purpose |
|---|---|---|
| Dev | Automatic on merge to main | Continuous integration testing |
| Staging | Manual workflow dispatch | Pre-production validation |
| Production | Manual workflow dispatch | Live traffic |
How Promotion Works
- Build creates a container image and records its digest in a GitHub release
- Promote downloads the digest and dispatches an update to the platform repository
- Platform updates Kubernetes manifests with the new image digest
- ArgoCD detects the manifest change and deploys the new version
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Release │ │ Promote │ │ Platform │ │ ArgoCD │
│ │ │ Workflow │ │ Repo │ │ │
│ digest.txt │───►│ dispatch │───►│ manifests │───►│ deploy │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
The Manifest Dispatch Action
The platform-application-manifest-dispatch action is the key integration point. It sends a repository dispatch event to the platform repository, which updates the Kubernetes manifests.
- uses: p6m-actions/platform-application-manifest-dispatch@v1
with:
repository: ${{ github.repository }}
image-name: my-service
directory-name: my-service
environment: stg
digest: ${{ steps.get-digest.outputs.digest }}
update-manifest-token: ${{ secrets.UPDATE_MANIFEST_TOKEN }}
platform-dispatch-url: ${{ vars.PLATFORM_DISPATCH_URL }}
Inputs
| Input | Description | Required |
|---|---|---|
repository | Source repository (owner/repo format) | Yes |
image-name | Name of the Docker image | Yes |
directory-name | Directory in platform repo (.platform/kubernetes/<directory-name>) | Yes |
environment | Target environment: dev, stg, or prd | Yes |
digest | Docker image digest (sha256:...) | Yes |
update-manifest-token | Token for platform dispatch API | Yes |
platform-dispatch-url | URL of platform dispatch endpoint | Yes |
What Gets Updated
The dispatch updates the application's Kustomize overlay for the target environment:
.platform/kubernetes/my-service/
├── base/
│ └── kustomization.yaml
└── overlays/
├── dev/
│ └── kustomization.yaml ← digest updated here
├── stg/
│ └── kustomization.yaml ← or here
└── prd/
└── kustomization.yaml ← or here
These Kubernetes manifests typically live in your application repository under .platform/kubernetes/, but may also be in a dedicated platform repository depending on your organization's setup.
Promotion Workflow
- Key Steps
- Complete Workflow
name: Promote
on:
workflow_dispatch:
inputs:
environment:
description: 'Target environment'
required: true
type: choice
options:
- stg
- prd
tag:
description: 'Release tag to promote (e.g., v1.2.3)'
required: true
type: string
jobs:
promote:
runs-on: ubuntu-latest
steps:
# Download digest from release
- name: Download digest
uses: actions/download-artifact@v4
with:
name: digest
github-token: ${{ secrets.GITHUB_TOKEN }}
repository: ${{ github.repository }}
run-id: # from release
# Dispatch to platform
- name: Update manifest
uses: p6m-actions/platform-application-manifest-dispatch@v1
with:
environment: ${{ inputs.environment }}
digest: ${{ steps.digest.outputs.value }}
# ... other inputs
name: Promote
on:
workflow_dispatch:
inputs:
environment:
description: 'Target environment'
required: true
type: choice
options:
- stg
- prd
tag:
description: 'Release tag to promote (e.g., v1.2.3)'
required: true
type: string
jobs:
promote:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Get release info
id: release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Get the release by tag
release_id=$(gh api repos/${{ github.repository }}/releases/tags/${{ inputs.tag }} --jq '.id')
echo "release-id=$release_id" >> $GITHUB_OUTPUT
- name: Download digest artifact
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Download digest.txt from release assets
gh release download ${{ inputs.tag }} --pattern 'digest.txt' --dir .
- name: Read digest
id: digest
run: |
digest=$(cat digest.txt)
echo "value=$digest" >> $GITHUB_OUTPUT
echo "Promoting image with digest: $digest"
- name: Update application manifest
uses: p6m-actions/platform-application-manifest-dispatch@v1
with:
repository: ${{ github.repository }}
image-name: my-service
directory-name: my-service
environment: ${{ inputs.environment }}
digest: ${{ steps.digest.outputs.value }}
update-manifest-token: ${{ secrets.UPDATE_MANIFEST_TOKEN }}
platform-dispatch-url: ${{ vars.PLATFORM_DISPATCH_URL }}
- name: Update release notes
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Get current release body
current_body=$(gh api repos/${{ github.repository }}/releases/tags/${{ inputs.tag }} --jq '.body')
# Append promotion info
timestamp=$(date -u +"%Y-%m-%d %H:%M:%S UTC")
new_body="${current_body}
---
## Promotions
| Environment | Promoted By | Timestamp |
|-------------|-------------|-----------|
| ${{ inputs.environment }} | @${{ github.actor }} | ${timestamp} |"
# Update the release
gh api repos/${{ github.repository }}/releases/tags/${{ inputs.tag }} \
-X PATCH \
-f body="$new_body"
- name: Summary
run: |
echo "## Promotion Complete" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Tag:** ${{ inputs.tag }}" >> $GITHUB_STEP_SUMMARY
echo "**Environment:** ${{ inputs.environment }}" >> $GITHUB_STEP_SUMMARY
echo "**Digest:** ${{ steps.digest.outputs.value }}" >> $GITHUB_STEP_SUMMARY
Environment Protection
Use GitHub environments to add approval requirements for production:
- Go to repository Settings → Environments
- Create environments:
stg,prd - For
prd, add required reviewers
jobs:
promote:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }} # Triggers approval for prd
When promoting to prd, designated reviewers must approve before the workflow runs.
Automatic Dev Deployment
Dev deployments happen automatically after successful builds on main:
# In build.yml
deploy-dev:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: p6m-actions/platform-application-manifest-dispatch@v1
with:
environment: dev
digest: ${{ needs.build.outputs.digest }}
# ... other inputs
This ensures every merge to main is immediately deployed to dev for testing.
Tracking Promotions
Update GitHub releases to record promotion history:
- name: Update release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh api repos/${{ github.repository }}/releases/tags/${{ inputs.tag }} \
-X PATCH \
-f body="$(cat <<EOF
... existing body ...
## Promotions
- **${{ inputs.environment }}**: Promoted by @${{ github.actor }} at $(date -u)
EOF
)"
This creates an audit trail of when and by whom each version was promoted.
Rollback
To rollback, promote a previous version:
- Find the previous working release tag (e.g.,
v1.2.2) - Run the promote workflow with that tag
- The previous image digest will be deployed
Since digests are immutable, you're guaranteed to deploy the exact same image.
Connection to Deployments
After promotion:
- Platform repo manifests are updated with the new digest
- ArgoCD detects the change
- ArgoCD syncs the new version to the cluster
See Deployments for details on:
- How ArgoCD manages deployments
- Verifying deployment status
- Troubleshooting deployment issues
Best Practices
Test in Staging First
Always promote to staging before production. Staging should mirror production as closely as possible.
Document Promotion Decisions
Use the release notes to document why a version was promoted:
- name: Record promotion reason
run: |
echo "Promoted to ${{ inputs.environment }}: ${{ inputs.reason }}"
Monitor After Promotion
After promoting to production:
- Watch application metrics
- Check error rates
- Be ready to rollback if issues arise
Required Secrets and Variables
| Name | Type | Description |
|---|---|---|
UPDATE_MANIFEST_TOKEN | Secret | Token for platform dispatch API |
PLATFORM_DISPATCH_URL | Variable | URL of platform dispatch endpoint |
GITHUB_TOKEN | Secret | Automatic; used for release access |
Related
- CI/CD Overview — Build pipeline architecture
- Versioning — Creating releases to promote
- Deployments — What happens after promotion
- Platform Dispatch Action — Detailed dispatch documentation