A small GitHub Actions experiment for controlling environment promotion through a GitHub Issue.
The main idea is simple: a release is identified by a single commit SHA, automatically deployed to TEST, and then promoted through STAGE and PROD from a release issue.
Instead of selecting a new source revision for each environment, the same commit SHA is promoted forward.
I wanted to experiment with a deployment flow that is:
- easy to follow
- auditable
- explicit about what version is being promoted
- reusable across environments
- controlled without requiring a separate deployment UI
The release issue acts as both the control surface and a lightweight audit trail.
flowchart TD
A[Push to main] --> B[Deploy commit to TEST]
B --> C[Create release issue]
C --> D{Promote to STAGE?}
D -->|Checkbox selected| E[Deploy same SHA to STAGE]
E --> F[Mark STAGE as completed]
F --> G{Promote to PROD?}
G -->|Checkbox selected| H[Deploy same SHA to PROD]
H --> I[Mark PROD as completed]
I --> J[Close release issue]
A release issue starts roughly like this:
## 🚀 Release <commit-sha>
Commit: <commit-sha>
### Promotion
- ✅ TEST
- [ ] STAGE
- 🚫 PROD
After STAGE is selected, the workflow marks it as deploying:
- ✅ TEST
- 🔁 STAGE
- 🚫 PROD
When the deployment completes successfully, STAGE is marked as done and PROD becomes available:
- ✅ TEST
- ✅ STAGE
- [ ] PROD
The issue is automatically closed after all environments have been promoted.
Triggered by a push to main.
It:
- deploys the new commit to TEST
- creates a release issue
- stores the commit SHA in the release issue labels
- exposes STAGE as the next available promotion target
Triggered when the release issue is edited.
It:
- detects the selected environment
- reads the release SHA
- marks the environment as deploying
- invokes the reusable deployment workflow
- marks the deployment as completed
- unlocks the next environment
- closes the issue when the promotion chain is finished
Reusable deployment workflow shared by the automatic TEST deployment and manually controlled environment promotions.
Inputs:
environment:
sha:
The current repository intentionally contains only placeholder deployment logic.
In a real environment this would typically include steps such as:
Cloud authentication
↓
Build or retrieve artifact
↓
Push image
↓
Deploy with Helm / Kubernetes
↓
Health checks
The commit SHA is captured when the release is created and passed through the promotion workflow.
This keeps the promoted source revision explicit and consistent across TEST, STAGE and PROD.
Environment-specific promotion logic calls the same deployment workflow instead of maintaining separate TEST, STAGE and PROD pipelines.
This keeps the actual deployment mechanism in one place while allowing the release orchestration to remain separate from deployment implementation.
The next environment is locked until the previous one has completed.
A typical release therefore moves through:
TEST → STAGE → PROD
rather than allowing environments to be promoted independently.
The release issue provides a simple human-readable interface for controlling promotion without introducing a separate deployment UI.
The issue also shows:
- which commit is being released
- which environments have completed
- which environment is currently deploying
- which environment is available next
This makes the release state visible directly next to the source repository.
The issue workflow controls when and where a release is promoted.
The reusable deployment workflow controls how that version is deployed.
Keeping these responsibilities separate makes it possible to replace the placeholder deployment implementation without changing the promotion model.
After a merge to main:
Push to main
│
▼
Automatic TEST deployment
│
▼
Release issue created
│
▼
✅ TEST
☐ STAGE
🚫 PROD
The user selects STAGE:
✅ TEST
🔁 STAGE
🚫 PROD
After a successful deployment:
✅ TEST
✅ STAGE
☐ PROD
The user selects PROD:
✅ TEST
✅ STAGE
🔁 PROD
After PROD completes:
✅ TEST
✅ STAGE
✅ PROD
The release issue is then automatically closed.
Warning
This is an experimental proof of concept, not a production-ready deployment solution.
I built it to explore an idea: using GitHub Issues as a lightweight control surface for promoting the same release through multiple environments.
Security hardening, failure scenarios and production deployment details are intentionally out of scope.
.github/
└── workflows/
├── release-on-main.yaml
├── issue-promotion.yml
└── deploy-reusable.yaml
The repository separates release orchestration from the reusable deployment workflow.
The main areas of focus are:
- release orchestration
- reusable workflows
- sequential environment promotion
- human-controlled production promotion
- automation of release state
The deployment implementation is intentionally kept minimal so the repository can focus on the orchestration and promotion model.