The conceptualization and implementation of a "dry run" within GitHub Actions is a critical safety mechanism for software engineers and DevOps architects. In the context of Continuous Integration and Continuous Deployment (CI/CD), a dry run serves as a non-destructive simulation of a workflow's execution. Its primary purpose is to validate that the logic, permissions, and external API calls are correctly configured without actually committing permanent changes to the production environment, deleting data, or publishing software releases. By simulating the outcome of a job, developers can avoid the "commit-fix-commit" cycle, which often pollutes git histories with trivial "fix" or "test" commits that provide no value to the codebase but create noise in the version control system.
The necessity of dry runs becomes apparent when dealing with high-risk operations, such as the automated deletion of repository history, the deployment of WordPress plugins, or the triggering of semantic versioning releases. Without a simulation layer, a misconfigured YAML file could lead to catastrophic data loss or the accidental publication of a beta version of a product to a stable production channel. Achieving a true dry run in GitHub Actions often requires a combination of specific action inputs, environment variable manipulation, and the use of third-party local execution tools like act.
Local Workflow Simulation with the Act Tool
One of the most efficient methods to perform a dry run of a GitHub Action is to move the execution environment from the cloud to the local developer machine. This is achieved using act, a tool that allows users to run their GitHub Actions workflows locally.
The implementation of act requires a specific technical environment. The prerequisite for using this tool is having Docker installed and running on the local machine, as act leverages containers to mimic the GitHub runner environment. It is important to note that act currently only supports Linux containers; Windows or Mac environments are not supported for the runner execution itself, although the tool can be installed on these operating systems to manage the containers.
To initiate the setup of act, the user should download the binary from the official releases page on GitHub or clone the repository. A critical first step in the local dry run process is executing the command act --dryrun. This specific command does not execute the workflow but instead creates the default configuration file located at $HOME/.actrc.
The .actrc file defines the mapping between the GitHub runner labels and the Docker images used to simulate them. The standard default entries include:
| Runner Label | Docker Image |
|---|---|
| ubuntu-latest | ghcr.io/catthehacker/ubuntu:act-latest |
| ubuntu-20.04 | ghcr.io/catthehacker/ubuntu:act-20.04 |
| ubuntu-18.04 | ghcr.io/catthehacker/ubuntu:act-18.04 |
When executing workflows locally, developers can use a variety of CLI options to refine the simulation. For instance, to list workflows and verify the configuration without running them, the following command is used:
act --dryrun --workflows .github\workflows\test-ci.yml --verbose --list
For a more comprehensive simulation that includes sensitive data and environment-specific variables, act allows the use of external files. This prevents the leakage of secrets into the command history. A developer can create a .secrets file and an .env file, then call them during execution:
act --env-file github-actions\run-github-actions-workflows-locally-with-act.env --secret-file github-actions\run-github-actions-workflow-locally-with-act.secrets --workflows .github\workflows\test-ci.yml --verbose --list
To simulate a specific job within a larger workflow, the --job flag is utilized:
act --env-file github-actions\run-github-actions-workflows-locally-with-act.env --secret-file github-actions\run-github-actions-workflow-locally-with-act.secrets --workflows .github\workflows\test-ci.yml --verbose --job prep
Furthermore, simulating specific GitHub events, such as a push event, can be done by appending the event name to the command:
act --env-file github-actions\run-github-actions-workflows-locally-with-act.env --secret-file github-actions\run-github-actions-workflow-locally-with-act.secrets --workflows .github\workflows\test-ci.yml --verbose push
Simulating Semantic Releases and Versioning
Implementing a dry run for semantic-release presents a unique challenge because the tool is designed to detect if it is running in a CI environment. In many cases, simply passing a --dry-run flag is insufficient to trick the system into a full simulation without attempting certain publishing actions.
To create a robust "Release - Dry Run" workflow, the configuration must be meticulously crafted. The workflow should typically trigger on pull_request events for specific branches such as main, beta, alpha, or version branches like +.x.
A critical component of this simulation is the requirement for contents: write permissions. Even during a dry run, semantic-release needs to verify that the Git push permissions are valid. Without this, the simulation may fail before it even begins the dry run logic.
The technical process for simulating a new feature release involves the following steps:
- Use
actions/checkoutwithfetch-depth: 0. This is a mandatory requirement forsemantic-releaseto analyze the commit history and determine the next version number. - Set the
refto${{ github.head_ref }}. This ensures that the dry run simulates a release based on the source branch of the pull request rather than the merge commit. - Configure the Git identity locally within the runner to allow the simulation of a commit. This involves setting the user name to
github-actions[bot]and the email to41898282+github-actions[bot]@users.noreply.github.com. - Execute a dummy commit to trigger the versioning logic:
git commit --no-verify --allow-empty -m 'feat: simulate new feature'.
The final execution of the release simulation requires an intentional bypass of the CI detection mechanism. The GITHUB_ACTIONS environment variable must be unset to trick semantic-release into thinking it is not in a CI environment, as the --no-ci flag alone does not provide enough coverage. The command is structured as follows:
bash
unset GITHUB_ACTIONS
npx --no-install semantic-release --dry-run --no-ci --branches "${GITHUB_HEAD_REF}"
This approach allows the developer to see exactly what the next version would be and which changelogs would be generated without actually tagging the repository or publishing to a registry.
Non-Destructive Cleanup and Maintenance Dry Runs
Maintaining a clean repository often involves deleting old GitHub Actions runs. Because the deletion of run history is an irreversible action, the use of a dry-run mode is strongly advised.
The yanovation/delete-old-actions action provides a mechanism to simulate the deletion process. When dry-run is set to true, the action will only list the runs that are slated for deletion without actually removing them from the GitHub database.
The configuration for a simulated cleanup workflow typically includes:
- A scheduled trigger using a cron expression (e.g.,
0 0 * * *for daily execution). - The
days-agoparameter, which defines the threshold for deletion. - The
keep-latestparameter, which allows the user to preserve a specific number of the most recent runs (e.g., keeping the last 5 runs) regardless of their age.
The implementation of the dry run in a YAML configuration looks like this:
yaml
- uses: yanovation/delete-old-actions@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
days-ago: 30
dry-run: true
keep-latest: 5
Authentication for these maintenance tasks can be handled in three ways:
- Using the default
${{ secrets.GITHUB_TOKEN }}, which requires providing write permissions at the repository or organization level. - Using a GitHub App for more granular security. This involves generating a token via
actions/create-github-app-token@v1using anAPP_IDandAPP_PRIVATE_KEY. - Utilizing a Personal Access Token (PAT) with the least amount of privilege required for the task.
Dry Run Capabilities in Third-Party Deployment Actions
Beyond general utility and release tools, specific deployment actions often integrate DRY_RUN modes to prevent accidental deployments of code to production servers. A notable example is the 10up deploy action used for WordPress plugin deployments.
The 10up/action-wordpress-plugin-deploy action officially supports a DRY_RUN mode. This allows developers to test the deployment logic—ensuring that the files are correctly packaged and the target environment is reachable—without actually overwriting the live plugin files on the WordPress site.
The implementation in the workflow file is straightforward:
yaml
- name: WordPress Plugin Deploy
uses: 10up/action-wordpress-plugin-deploy@stable
with:
dry-run: true
This layer of protection is essential in WordPress environments where a failed deployment can lead to the "White Screen of Death" or critical site errors, making the dry run a mandatory step in the testing phase of the pipeline.
Technical Summary of Dry Run Implementations
The following table provides a comparative analysis of the different dry run methods discussed in this documentation.
| Tool/Action | Primary Mechanism | Key Configuration/Flag | Risk Mitigated |
|---|---|---|---|
act |
Local Containerization | --dryrun |
CI resource waste, Git history pollution |
semantic-release |
Env Variable Manipulation | unset GITHUB_ACTIONS |
Accidental version tagging/publishing |
yanovation/delete-old-actions |
Action Input | dry-run: true |
Irreversible loss of run history |
10up/action-wordpress-plugin-deploy |
Action Input | dry-run: true |
Production site downtime/corruption |
Conclusion
The implementation of dry runs within GitHub Actions is not a monolithic feature but a collection of strategies ranging from local environment simulation to specific flag-based overrides in third-party actions. The transition from a standard execution to a simulated one is the difference between a stable, predictable deployment pipeline and one prone to catastrophic failure.
For local testing, act provides an indispensable layer of isolation, allowing the developer to iterate on YAML syntax and logic without pushing dozens of "test" commits to the remote repository. For release management, the combination of unset GITHUB_ACTIONS and the --dry-run flag in semantic-release ensures that the automated versioning logic is sound before any permanent tags are applied. For maintenance and deployment, such as with yanovation or 10up actions, the dry-run: true input serves as a final sanity check.
Ultimately, the goal of any dry run is to provide a "read-only" view of a "write-heavy" process. By leveraging these tools and techniques, organizations can maintain high velocity in their delivery pipelines while ensuring that the blast radius of a configuration error is kept to zero. The rigor applied to the simulation phase directly correlates to the reliability of the production release.