The automation of software delivery pipelines often reaches a critical juncture where human judgment is required before proceeding to high-stakes environments. While continuous integration and continuous deployment (CI/CD) strive for total automation, the reality of enterprise governance requires a "human-in-the-loop" mechanism to validate releases. In the GitHub ecosystem, this is achieved through two primary modalities: the native workflow_dispatch event for manual triggering and the implementation of manual approval gates via specialized actions for mid-workflow pauses.
Manual Triggering via workflow_dispatch
GitHub provides a native mechanism to initiate workflows manually through the workflow_dispatch event. This feature transforms a static automation script into an on-demand tool that can be executed by a user via the GitHub user interface.
The primary utility of workflow_dispatch is the ability to trigger a run from the Actions tab, where a "Run workflow" button becomes available. This allows developers to choose the specific branch upon which the workflow should be executed, providing flexibility for testing features or deploying specific hotfixes from non-default branches.
A critical component of this trigger is the support for optional inputs. These inputs are defined within the workflow YAML and are rendered as form elements in the GitHub UI, allowing the operator to pass parameters into the workflow at runtime.
The syntax for defining these inputs is as follows:
yaml
on:
workflow_dispatch:
inputs:
logLevel:
description: 'Log level'
required: true
default: 'warning'
tags:
description: 'Test scenario tags'
Once the workflow is triggered, these inputs are accessible through the github.event context. This allows the job to dynamically adjust its behavior based on the user's selection. For instance, a job can print these inputs using the following configuration:
yaml
jobs:
printInputs:
runs-on: ubuntu-latest
steps:
- run: |
echo "Log level: ${{ github.event.inputs.logLevel }}"
echo "Tags: ${{ github.event.inputs.tags }}"
This capability is essential for tasks such as manual database migrations, targeted smoke tests, or triggering specific deployment versions where a fully automated trigger (like a push or pull request) would be too frequent or risky.
Troubleshooting the Missing Run Workflow Button
Despite the implementation of the workflow_dispatch event, users frequently encounter an issue where the "Run workflow" button does not appear in the Actions tab. This is a common point of friction, particularly in private repositories or when modifying existing workflows.
One common cause of this invisibility is the navigation path within the Actions tab. Users often select "All workflows" and expect to see the button there; however, the button only appears after the user has clicked on the specific name of the workflow they wish to run.
Other reported issues include:
- Workflow files that are not recognized by GitHub despite correct syntax.
- Issues where the workflow does not appear in the list at all, even after renaming the YAML file (e.g., to
generate_license_activation.yaml) or merging it into the base branch. - Problems occurring specifically in existing repositories versus new repositories, where new repos function correctly with all event combinations but older repos do not display the manual trigger.
For users facing these issues, the lack of an explicit error message from GitHub regarding syntax errors in the workflow_dispatch configuration can make debugging difficult. The general recommendation is to ensure the workflow file is present on the default branch for the trigger to be recognized in the UI.
Implementing Mid-Workflow Manual Approvals
While workflow_dispatch handles the start of a workflow, many pipelines require a pause in the middle of a process—such as after a build succeeds but before a production deployment begins. GitHub natively supports this through "Environments," but this functionality is restricted to GitHub Enterprise for private repositories.
To circumvent this limitation, third-party solutions like the manual-approval action provide a way to require manual sign-off from one or more approvers without needing GitHub Enterprise or the use of environments. This is particularly valuable for teams operating on private repositories who need a free, accessible method to gate their deployments.
The manual-approval action functions by pausing the workflow and creating a GitHub issue in the repository. This issue serves as the notification and the interface for approval.
Approval Logic and Keywords
The action monitors the created issue for specific keywords provided by the designated approvers. The process is governed by a strict keyword system:
- Approval keywords: "approve", "approved", "lgtm", "yes"
- Denied keywords: "deny", "denied", "no"
These keywords are case-insensitive and allow for optional punctuation, specifically periods or exclamation marks.
The logic for continuing or terminating the workflow is as follows:
- Success: The workflow continues only after all designated approvers have responded with an approved keyword.
- Failure: If any single approver responds with a denied keyword, the workflow exits immediately with a failed status.
Regardless of whether the outcome is an approval or a denial, the manual-approval action will automatically close the initial GitHub issue to maintain repository cleanliness.
Configuration and Usage
To integrate this manual gate into a pipeline, the action is called within a job step. It requires a GitHub token and a list of approvers.
yaml
steps:
- uses: trstringer/manual-approval@v1
with:
secret: ${{ github.TOKEN }}
approvers: user1,user2,org-team1
minimum-approvals: 1
issue-title: "Deploying v1.3.5 to prod from staging"
issue-body: "Please approve or deny the deployment of version"
Since version v1.10.0, the handling of issue content has been refined to avoid overwriting the main issue description. The issue-body and issue-body-file-path are now added as comments on the issue. Furthermore, the issue-title is now used exactly as provided in the input, removing previous behaviors where the title was wrapped in predefined strings.
Technical Specifications and Constraints
The manual-approval action has specific operational requirements and limitations that must be considered during architectural planning.
Runner Compatibility
The action is not universal across all operating systems. It is designed specifically for Linux-based environments.
| Runner Type | Architecture | Support Status |
|---|---|---|
| Linux/amd64 | 64-bit Intel/AMD (x86_64) | Supported |
| Linux/arm64 | 64-bit ARM (Apple M1) | Supported |
| Linux/arm/v8 | 64-bit ARM | Supported |
| Windows/amd64 | 64-bit Windows | Unsupported |
| Non-Linux | Any | Unsupported |
Timeout and Cost Implications
A critical operational detail is the timeout period. Because the action pauses the workflow to wait for a human response, the workflow remains "in progress." All GitHub Actions workflows are subject to a maximum timeout of 35 days. If the approvers do not respond within this window, the workflow will automatically time out and fail.
Additionally, users must be aware of usage costs. Since the action keeps the workflow active while waiting for approval, this can consume action minutes depending on the runner and the billing model of the account.
Development and Testing of Manual Approval Actions
For developers wishing to modify or test the manual-approval action, a specific build and release cycle is required to ensure stability.
Testing with Dev Branches
To test a new version of the action, one must point the uses directive to a specific development branch instead of a tagged release.
yaml
- name: Wait for approval
uses: your-github-user/manual-approval@your-dev-branch
with:
secret: ${{ secrets.GITHUB_TOKEN }}
approvers: trstringer
Building and Pushing Images
The action utilizes Docker images for its execution. The process for updating the image involves:
- Building and pushing the image to a registry (e.g., GHCR):
VERSION=1.7.1-rc.1 make IMAGE_REPO=ghcr.io/trstringer/manual-approval-test push - Modifying the
action.yamlto point to the test image:
image: docker://ghcr.io/trstringer/manual-approval-test:1.7.0-rc.1
Release Management
Once the testing phase is complete, the following sequence is used to promote the changes to production:
- Create a release branch and update
action.yamlto the new image. - Merge the PR into the default branch.
- Sync local repository:
git checkout main && git fetch origin && git merge origin main - Update tags to point to the new version:
git tag -d v1 && git push --delete origin v1
git tag v1.7.0 && git tag v1 && git push origin --tags - Finalize by creating the official GitHub project release.
Comparative Analysis: Native vs. Third-Party Manual Gates
The choice between using native GitHub Environment approvals and the manual-approval action depends on the organizational tier and specific requirements.
| Feature | GitHub Native Environments | manual-approval Action |
|---|---|---|
| Availability (Private Repos) | GitHub Enterprise Only | Free / All Tiers |
| Implementation Method | Environment Settings UI | YAML Workflow Step |
| Notification Method | GitHub Notifications | GitHub Issue Creation |
| Approval Interface | Native Approval Button | Issue Comments (Keywords) |
| Timeout | Standard Workflow Timeout | Standard Workflow Timeout |
| Complexity | Low (UI Based) | Medium (YAML Based) |
Conclusion
The orchestration of manual interventions within GitHub Actions requires a nuanced understanding of both the workflow_dispatch event and the external mechanisms used to create approval gates. While workflow_dispatch provides a robust method for triggering workflows on-demand with customizable inputs, its invisibility in certain repository contexts remains a point of frustration for many users.
For the critical need of mid-workflow approvals, the manual-approval action fills a significant gap for users of private repositories who lack access to GitHub Enterprise. By utilizing a system of issue-based keyword monitoring ("approve", "deny"), it creates a verifiable audit trail of who authorized a deployment and when. However, the architectural cost is a heightened awareness of the 35-day workflow timeout and the potential for increased consumption of action minutes.
The transition to version v1.10.0 of the manual approval action, which moves body content to comments and cleans up issue titles, demonstrates a move toward better integration with the GitHub Issue API, reducing noise and improving the clarity of the approval process. Ultimately, the choice of implementation depends on whether the user prioritizes the seamless UI integration of Enterprise environments or the flexibility and cost-effectiveness of an issue-driven approval system.