Offers to format pull requests with whatever formatter your project is already using, then formats them on demand. πΏ
formatly-on-demand posts a friendly comment when a pull request's files aren't formatted the way your repository formats code.
It doesn't touch the branch until the pull request's author or a maintainer comments /formatly to ask it to.
Then it formats those files with formatly and pushes a single commit.
Add three workflow files to your repository.
.github/workflows/formatly-on-demand-detect.yaml checks each pull request:
name: Formatly on Demand Detect
on:
pull_request: ~
jobs:
detect:
uses: JoshuaKGoldberg/formatly-on-demand/.github/workflows/detect.yaml@v0
with:
install: pnpm install --frozen-lockfile.github/workflows/formatly-on-demand-offer.yaml posts the comment:
name: Formatly on Demand Offer
on:
workflow_run:
types:
- completed
workflows:
- Formatly on Demand Detect
permissions:
actions: read
issues: write
pull-requests: read
jobs:
offer:
uses: JoshuaKGoldberg/formatly-on-demand/.github/workflows/offer.yaml@v0.github/workflows/formatly-on-demand-format.yaml does the formatting when someone asks:
name: Formatly on Demand Format
on:
issue_comment:
types:
- created
permissions:
issues: write
pull-requests: read
jobs:
format:
secrets:
push-token: ${{ secrets.ACCESS_TOKEN }}
uses: JoshuaKGoldberg/formatly-on-demand/.github/workflows/format.yaml@v0
with:
install: pnpm install --frozen-lockfileThe install input is whatever command installs your dependencies, such as npm ci or pnpm install --frozen-lockfile.
Leave it out for repositories that don't need an install step, such as ones formatted by deno fmt.
A workflow's built-in GITHUB_TOKEN can't push to a branch that lives in somebody else's fork.
Formatting pull requests from forks, which is most of them for most open source repositories, needs a token of its own:
- Create a classic personal access token with the public_repo scope, from an account with push access to your repository
- Save it as a repository secret, such as
ACCESS_TOKEN - Pass it as the
push-tokensecret, as in the workflow above
Without that secret, pull requests from forks get a comment explaining that a maintainer will need to format them by hand. Pull requests from branches in your own repository work with no extra setup.
Two GitHub limitations apply to pull requests from forks even with a token:
- The pull request must have Allow edits by maintainers enabled, which is the default.
formatly-on-demandsays so in its comment when it isn't. - Forks owned by organizations can't grant that access at all.
Reusable workflow inputs:
| Input | Default | Description |
|---|---|---|
accept-yes |
true |
Whether a comment of just yes counts as asking for formatting |
allowed-associations |
OWNER,MEMBER,COLLABORATOR |
Who besides the pull request's author may ask for formatting |
command |
/formatly |
Comment text that asks for formatting |
comment-footer |
Custom footer text for comments | |
comment-header |
Custom header text for comments | |
commit-message |
chore: apply formatly formatting |
Message for the formatting commit |
install |
Command that installs dependencies | |
node-version |
lts/* |
Node.js version to run the formatter with |
working-directory |
. |
Directory holding the project to format |
Repositories needing setup that the install input can't express, such as a custom toolchain, can use the action directly instead of these reusable workflows.
See action.yaml for its inputs and the reusable workflows for how they're wired together.
Running your repository's formatter means installing your pull request's dependencies and loading its config and plugins.
That is arbitrary code execution from whoever opened the pull request, so formatly-on-demand never lets it share a job with a token:
- Jobs that check out and run pull request code declare
permissions: {}and reference no secrets. - The job that pushes runs no project code at all: no install, no scripts, no hooks.
It applies a patch with
gitand nothing else. - That patch is validated first: modifications to existing files only, never
.github/workflows, never symlinks, submodules, renames, or paths outside the repository, and never more thanmax-filesfiles ormax-patch-bytesbytes. - Detection results are re-verified against the GitHub API before any comment or push, because the job that produced them ran pull request code.
- Formatting is only ever pushed to the commit it was computed from.
If the branch moves first,
formatly-on-demandstops and says so rather than pushing over new work. - Pushes are never forced.
- Only the pull request's author and the associations in
allowed-associationscan ask for formatting. Comments from anyone else are ignored.
That being said, it is impossible to be 100% confident in all actions' security measures. Please use this action with caution and be safe with potentially malicious external contributors.
See .github/CONTRIBUTING.md, then .github/DEVELOPMENT.md.
Thanks! π
Josh Goldberg β¨ π» π π π€ π π§ π π§ |
π This package was templated with
create-typescript-appusing the Bingo framework.