Strategic Management of Draft Pull Requests in GitHub Actions

The integration of draft pull requests into the GitHub Actions ecosystem represents a significant shift in how development teams manage continuous integration (CI) and continuous deployment (CD) pipelines. A draft pull request serves as a temporary state, signaling that work is in progress and not yet ready for review or merging. While this workflow enhances developer flexibility, it introduces complexities regarding billing, workflow triggering, and automated state management. Understanding the nuances of how GitHub Actions interacts with draft pull requests is essential for optimizing cost, maintaining repository hygiene, and ensuring that automated workflows execute only when necessary.

Billing Implications of Draft Pull Requests

One of the most critical considerations for organizations utilizing GitHub Actions is the financial impact of workflow execution. GitHub Actions billing is calculated based on the total time workflows spend running, with usage rounded up to the nearest whole minute. This billing model creates a specific scenario when dealing with draft pull requests: even if a job within a workflow is configured to skip execution because the pull request is in a draft state, the workflow itself still initiates.

According to GitHub billing policies, any time spent during this initialization phase counts towards the account's usage. Consequently, workflows triggered by draft pull requests incur charges, even if the actual job logic is bypassed. This is because the workflow runner is allocated and initialized before the conditional checks (such as if: github.event.pull_request.draft == false) are evaluated. There is currently no account-level setting that allows users to completely disable actions for draft pull requests to avoid these charges. Teams must recognize that the mere act of opening or synchronizing a draft pull request will trigger the workflow runner, resulting in a minimum charge of one minute of compute time per workflow run, regardless of whether the job performs any substantive work.

Automated Conversion to Draft State

To mitigate the issues associated with billing and to enforce strict quality gates, many teams employ custom GitHub Actions to automatically manage the state of pull requests. One common strategy is to force all newly opened pull requests into a draft state immediately upon creation. This ensures that no CI/CD jobs run until the developer explicitly marks the pull request as ready for review. The voiceflow/draft-pr action is a widely used tool for this purpose. It converts the current or a specified pull request into a draft state.

When implementing this action, it is crucial to use the correct authentication token. The GITHUB_TOKEN provided by the workflow environment is typically sufficient for modifying the state of pull requests within the same repository. The action requires the pull-request-node-id to identify the specific pull request, though it automatically applies to the current pull request when triggered by a pull_request event. For scenarios where a different pull request needs to be targeted, the node ID can be retrieved using the GitHub CLI command gh pr view $PR --json id --jq .id, where $PR represents the number, URL, or branch of the target pull request.

A typical workflow configuration for this approach involves triggering on the opened event of a pull request. The job checks if the pull request is not already a draft (if: github.event.pull_request.draft == false) and then invokes the action to mark it as such. This pattern ensures that developers cannot accidentally trigger expensive CI pipelines with incomplete code.

yaml name: Draft on Open on: pull_request: types: [ opened ] jobs: mark-as-draft: name: Mark as draft if: github.event.pull_request.draft == false runs-on: ubuntu-latest steps: - name: Mark as draft uses: voiceflow/draft-pr@latest with: token: ${{ secrets.GITHUB_TOKEN }}

Conditional Draft Conversion Based on Workflow Status

Another sophisticated approach to managing draft pull requests is to automatically revert a pull request to a draft state if associated workflows fail or are still running. This ensures that only pull requests with passing checks are marked as ready for review. The yu-iskw/convert-to-draft-action facilitates this behavior by monitoring the status of workflows and updating the pull request state accordingly.

This action accepts several configuration inputs to tailor its behavior. The GITHUB_TOKEN is required for authentication. Optionally, the action can be configured to leave a comment on the pull request when it is converted to a draft, providing transparency to the developer. The leave_comment flag defaults to 1 (enabled), and the comment_body can be customized to explain why the pull request was reverted to a draft state, such as indicating that workflows failed or were still running.

The workflow triggering this action is typically configured to run on multiple pull request events, including opened, synchronize, reopened, ready_for_review, review_requested, and auto_merge_enabled. To optimize resource usage and prevent unnecessary workflow runs, a concurrency setting can be implemented. This setting groups workflows by pull request number and cancels in-progress runs if a new one is triggered. This is particularly useful for synchronize events, which occur frequently as developers push new commits.

yaml name: Convert PR to Draft on: pull_request: types: - opened - synchronize - reopened - ready_for_review - review_requested - auto_merge_enabled concurrency: group: ${{ github.event.pull_request.number }} cancel-in-progress: true jobs: convert_to_draft: runs-on: ubuntu-latest permissions: actions: read contents: read pull-requests: write steps: - name: Checkout repository uses: actions/checkout@v4 - name: Convert PR to Draft uses: yu-iskw/[email protected] with: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" leave_comment: "1" comment_body: | The pull request has been converted to a draft because some workflows failed or are still running. Please get it ready to review after all workflows are passed.

Developers can also implement bypass mechanisms for this automatic conversion. By adding a specific label, such as disable-convert-to-draft, to a pull request, the workflow can be configured to skip the conversion step. This allows senior developers or automated systems to override the draft state when necessary, providing flexibility in the workflow.

Integration with Release Drafting and Automation

The management of pull requests extends beyond their lifecycle in the development phase to their eventual inclusion in releases. Tools like release-drafter leverage pull request metadata to automatically generate release notes. This tool categorizes pull requests based on labels, allowing for organized and informative release notes. For example, pull requests with the label feature can be grouped under a "Features" category, while those with fix or bug labels can be grouped under "Bug Fixes".

The release-drafter action also provides options to exclude specific pull requests from release notes using the exclude-labels option. This is particularly useful for internal changes or documentation updates that do not warrant inclusion in public release notes. Additionally, the tool supports collapsing categories with a high number of pull requests using the collapse-after setting, improving the readability of release notes.

When drafting the first release, the initial-commits-since option can be used to limit the number of scanned commits, ensuring that the release notes are concise and relevant. The action outputs various metadata about the created release, including the release ID, name, tag name, body, and URL. These outputs can be utilized by subsequent actions in the workflow, such as uploading assets to the release using the actions/upload-release-asset action.

yaml categories: - title: "🚀 Features" label: "feature" - title: "🐛 Bug Fixes" labels: - "fix" - "bugfix" - "bug" - title: "⬆️ Dependencies" collapse-after: 3 labels: - "dependencies"

Automated Pull Request Creation and Management

In addition to managing existing pull requests, GitHub Actions can be used to create new pull requests automatically. The peter-evans/create-pull-request action is a powerful tool for this purpose, enabling the automation of routine tasks such as updating documentation, patching configurations, or generating reports. This action allows for detailed configuration of the pull request, including the commit message, author, branch name, title, body, labels, assignees, and reviewers.

When creating a pull request via this action, the draft input can be set to false (default) or true. Setting it to true ensures that the created pull request is immediately marked as a draft, preventing it from being merged accidentally and avoiding the triggering of CI/CD workflows that might be configured to run only on ready-for-review pull requests. This is particularly useful for automated updates that require manual review before merging.

The action also supports the deletion of the source branch after the pull request is merged, keeping the repository clean. Additionally, it allows for the assignment of specific reviewers and teams, ensuring that the appropriate personnel are notified of the changes. The use of a Personal Access Token (PAT) is often required for this action, especially when creating pull requests in external repositories or when additional permissions are needed.

yaml jobs: createPullRequest: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - name: Make changes to pull request run: date +%s > report.txt - name: Create Pull Request id: cpr uses: peter-evans/create-pull-request@v8 with: token: ${{ secrets.PAT }} commit-message: Update report committer: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> author: ${{ github.actor }} <${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com> signoff: false branch: example-patches delete-branch: true title: '[Example] Update report' body: | Update report - Updated with *today's* date - Auto-generated by [create-pull-request][1] [1]: https://github.com/peter-evans/create-pull-request labels: | report automated pr assignees: peter-evans reviewers: peter-evans team-reviewers: | developers qa-team milestone: 1 draft: false

Conclusion

The management of draft pull requests within GitHub Actions is a multifaceted challenge that involves balancing cost, automation, and workflow integrity. While GitHub Actions incurs billing charges for workflows triggered by draft pull requests due to the initialization of the runner, strategic use of third-party actions can mitigate these costs and enhance repository management. By automating the conversion of pull requests to draft state upon creation or upon workflow failure, teams can ensure that only ready-for-review code triggers extensive CI/CD pipelines. Furthermore, the integration of these practices with release drafting and automated pull request creation creates a cohesive and efficient development workflow. Understanding these tools and their configurations allows development teams to optimize their use of GitHub Actions, reducing unnecessary compute costs while maintaining high standards of code quality and release management.

Sources

  1. GitHub Community Discussion on Draft PR Billing
  2. Mark PR as Draft Action
  3. Convert PR to Draft Action
  4. Release Drafter
  5. Create Pull Request Action

Related Posts