Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 

Repository files navigation

SolidWorx Actions

Shared GitHub Actions and reusable workflows, used across SolidWorx projects and the open source repositories they depend on.

Everything here is referenced at @main. There are no release tags: a change lands on main and every repository picks it up on its next run. That trades the admin of tagging for the risk that a breaking change reaches every consumer at once, so treat main as something that always has to work — the test suite below is what makes that reasonable.

The repository has to stay public. GitHub only allows a private repository's actions and workflows to be reused inside the same organisation, and these are consumed from other organisations as well.

What's here

Action Purpose
pr-milestone Put a pull request on the open milestone of the branch it targets

Each one ships as both a composite action, at SolidWorx/actions/<name>@main, and a reusable workflow, at SolidWorx/actions/.github/workflows/<name>.yml@main. Use the reusable workflow unless you need to compose the step into a job you already have — it carries the trigger conditions and concurrency settings that would otherwise be copied into every repository.

Reusable workflows have to sit directly in .github/workflows/; GitHub does not support subdirectories for them. Composite actions have no such restriction, which is why the two live in different places.

pr-milestone

Assigns the milestone a pull request belongs to, based on the branch it targets, so that a milestone always lists everything that will go into that release.

The milestone is looked up, not calculated. Every open milestone is mapped back to the branch it would be cut from, and the one that maps to the pull request's base branch wins. Nothing here invents a version number.

Conventions it assumes

Check all three before adding this to a repository. The action is not useful without them and will fail loudly rather than guess.

  1. Release branches are named X.x or X.Y.x2.x, 1.7.x, 1.6.x. Pull requests targeting anything else are left alone.
  2. Milestone titles are bare versions2.0.0, 1.7.8. No v prefix, no extra words.
  3. Exactly one milestone is open per release line. 2.0.0 and 2.1.0 must not be open at the same time; once 2.0.0 closes, the next one is 2.1.0 for 2.x or 2.0.1 for a new 2.0.x branch.

A milestone maps to a branch by trying the more specific branch first and falling back to the major one — the same rule a release script applies in reverse when it works out which branch to cut a closed milestone from:

Milestone Tries Resolves to
1.7.8 1.7.x, then 1.x 1.7.x when that branch exists
2.0.0 2.0.x, then 2.x 2.x when there is no 2.0.x branch
1.8.0 1.8.x, then 1.x 1.x when there is no 1.8.x branch

Add it to a repository

Create .github/workflows/milestone.yml:

name: Milestone

on:
  pull_request_target:
    types: [opened, reopened, edited]

jobs:
  milestone:
    uses: SolidWorx/actions/.github/workflows/pr-milestone.yml@main
    permissions:
      contents: read
      issues: write
      pull-requests: write

That is the whole integration. Three things about it are deliberate:

  • pull_request_target, not pull_request. A pull request opened from a fork gets a read-only token under pull_request and could never be assigned a milestone. This is safe here because nothing from the pull request is checked out or executed — the token is only used for the API call.
  • The permissions are granted by the caller. A reusable workflow can only narrow what it was given, so the block above is required; without it the assignment fails with a 403.
  • No actions/checkout. The runner fetches the action's own files, so the consuming repository is never cloned.

To assign milestones on demand as well — useful for catching up open pull requests after opening a new milestone — add a dispatch trigger:

on:
  pull_request_target:
    types: [opened, reopened, edited]
  workflow_dispatch:
    inputs:
      pr:
        description: "Pull request to put on its branch's milestone."
        required: true
        type: string

jobs:
  milestone:
    uses: SolidWorx/actions/.github/workflows/pr-milestone.yml@main
    with:
      pr: ${{ inputs.pr }}
    permissions:
      contents: read
      issues: write
      pull-requests: write

Using the action directly

When the step has to go into a job you already have:

- name: Assign milestone
  uses: SolidWorx/actions/pr-milestone@main
  with:
    pr: ${{ github.event.pull_request.number }}
Input Default Description
pr required Number of the pull request to put on a milestone
repository github.repository Repository the pull request belongs to, as owner/name
token github.token Token able to read milestones and write pull requests
dry-run false Resolve the milestone and report it without assigning it

Going this route means supplying the trigger conditions yourself. In particular, an edited event fires for title and body changes too, so gate the job on the base branch actually having changed or a milestone set by hand gets overwritten on every description tweak:

if: github.event.action != 'edited' || github.event.changes.base.ref.from != null

What it does in each case

Situation Result
Base branch has one open milestone Assigned, replacing whatever was there
Pull request is already on that milestone Nothing, no API call
Base branch is not a release branch Nothing, logged as a notice
Release branch has no open milestone Fails the check
Release branch has more than one open milestone Fails the check

The last two are failures rather than silent skips because both mean the repository's milestones need attention: the first release cannot be cut, and the second makes the branch ambiguous.

Running it by hand

The script underneath is standalone and takes a --dry-run, which is the quickest way to confirm the conventions hold in a repository before wiring the workflow up:

$ gh auth login
$ pr-milestone/pr-milestone --repo Payum/Payum --branch 2.x
2.x -> 2.0.0 (#2)
$ pr-milestone/pr-milestone --repo Payum/Payum 1053 --dry-run
Would put pull request #1053 on 2.0.0 (#2)

--branch resolves and reports without touching the pull request, so it works as a check of the mapping on its own. --repo defaults to GITHUB_REPOSITORY under Actions and to origin otherwise, which is why it is needed when running from a clone of this repository.

Adding an action to this repository

<name>/
├── action.yml            composite action
├── <name>                the implementation
└── test                  executable, exits non-zero on failure
.github/workflows/
└── <name>.yml            reusable workflow wrapping the action
  • The composite action reaches its own files through $GITHUB_ACTION_PATH, so consumers never need actions/checkout.
  • A reusable workflow referencing an action from this repository must use the full SolidWorx/actions/<name>@main path. A relative ./<name> resolves against the calling repository, not this one.
  • Do not declare permissions in a reusable workflow. It can only narrow what the caller granted, and fails outright against a caller that granted less. Document what the caller has to grant instead.
  • test is picked up automatically by CI — no workflow changes needed. Stub the network at the CLI boundary, the way pr-milestone/test puts a fake gh on PATH and has it record calls instead of making them.

Testing

$ ./pr-milestone/test
ok - a minor branch resolves to its open milestone
...
13 passed, 0 failed

CI runs actionlint, shellcheck over every executable bash script, and each action's test. Since consumers track main, a red build means every repository using these workflows is one merge away from breaking.

About

Re-usable Github actions for common workflows

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages