Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/hold.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Fails while a pull request has the do-not-merge/hold label (set with /hold).
# Labels set by the triage bot don't start workflows, so after /hold or /unhold
# the bot re-runs this workflow (see hack/triage/run.js); that is why the label
# is read from the API rather than from the event payload.

name: hold

on:
pull_request:
types: [opened, reopened, synchronize, labeled, unlabeled]

permissions: {}

jobs:
hold:
runs-on: ubuntu-latest
permissions:
pull-requests: read
steps:
- name: Fail while the pull request is on hold
env:
GH_TOKEN: ${{ github.token }}
PR: ${{ github.event.pull_request.number }}
run: |
labels=$(gh api "repos/${GITHUB_REPOSITORY}/issues/${PR}/labels" --jq '.[].name')
if grep -qx 'do-not-merge/hold' <<<"$labels"; then
echo "::error::This pull request is on hold. Comment /unhold to release it."
exit 1
fi
69 changes: 69 additions & 0 deletions .github/workflows/triage-commands.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Prow-style slash commands for issues and PRs: /triage accepted, /kind bug, /assign,
# and on PRs /lgtm, /approve, /hold, /retest, /cc, ...
# See documentation/triage-commands.md for the command list.
#
# Security: both events run in the context of the default branch, and the job only
# checks out hack/triage from it. Pull request code is never checked out or run;
# commands are read from the comment text only.

name: triage-commands

on:
issues:
types: [opened]
issue_comment:
types: [created]

# Explicitly disable all default GITHUB_TOKEN permissions at the workflow level.
# Each job then declares only the minimal required permissions.
permissions: {}

jobs:
label-new-issue:
if: github.event_name == 'issues'
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
steps:
- name: Checkout triage scripts
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 #v7.0.1
with:
sparse-checkout: hack/triage
persist-credentials: false

- name: Add needs-triage label
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const { labelNewIssue } = require('./hack/triage/run.js')
await labelNewIssue({ github, context })

commands:
if: >-
github.event_name == 'issue_comment' &&
github.event.comment.user.type != 'Bot' &&
contains(github.event.comment.body, '/')
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
pull-requests: write
# /retest re-runs failed workflow runs of a pull request.
actions: write
# No concurrency group: GitHub keeps only one pending run per group and
# cancels the others, which silently drops commands from quick comments.
# Each run reads the current labels instead.
steps:
- name: Checkout triage scripts
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 #v7.0.1
with:
sparse-checkout: hack/triage
persist-credentials: false

- name: Apply slash commands
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const { run } = require('./hack/triage/run.js')
await run({ github, context, core })
29 changes: 29 additions & 0 deletions .github/workflows/triage-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Unit tests for the triage bot in hack/triage. They only use Node's built-in
# test runner, so no dependencies are installed.

name: triage-tests

on:
push:
paths:
- 'hack/triage/**'
- '.github/workflows/triage-tests.yml'
pull_request:
paths:
- 'hack/triage/**'
- '.github/workflows/triage-tests.yml'

permissions:
contents: read

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 #v7.0.1
with:
persist-credentials: false

- name: Run triage tests
run: node --test hack/triage/test/*.test.js
8 changes: 6 additions & 2 deletions .github/workflows/welcome-new-users.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ jobs:
Welcome to the Microcks community! 💖

Thanks and congrats 🎉 for opening your first issue here! Be sure to follow the issue template or please update it accordingly.


🏷️ A maintainer will triage it soon. If you'd like to work on it, please wait for the `triage/accepted` label before opening a pull request. See the [triage commands](https://github.com/microcks/microcks-cli/blob/master/documentation/triage-commands.md).

📢 If you're using Microcks in your organization, please [add your company name to this list](https://github.com/microcks/.github/blob/main/ADOPTERS.md). 🙏 It really helps the project to gain momentum and credibility. It's a small contribution back to the project with a big impact.

If you need to know why and how to add yourself to the list, please read the blog post ["Join the Microcks Adopters list and Empower the vibrant open source Community 🙌"](https://microcks.io/blog/join-adopters-list/)
Expand Down Expand Up @@ -60,7 +62,9 @@ jobs:
Welcome to the Microcks community! 💖

Thanks and congrats 🎉 for opening your first pull request here! Be sure to follow the pull request template or please update it accordingly.


🏷️ Please link the issue this fixes; we review pull requests for issues labelled `triage/accepted` first. See the [triage commands](https://github.com/microcks/microcks-cli/blob/master/documentation/triage-commands.md).

Hope you have a great time there!

welcome-pr-merged:
Expand Down
72 changes: 72 additions & 0 deletions documentation/triage-commands.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Triage commands

Issues and pull requests in this repository can be triaged with Prow-style slash commands, similar to Kubernetes. Write the command at the start of a line in a comment. You can put several commands in one comment, one per line. The bot reacts with 👍 when the commands are applied, and replies if one could not be applied.

## Triage flow

1. Every new issue gets the `needs-triage` label.
2. A maintainer or contributor checks it and comments `/triage accepted`, or `/triage needs-information` if more details are needed from the reporter.
3. Once an issue has `triage/accepted`, anyone can open a pull request that references it. Issues are not assigned: the first complete pull request is accepted. If one is already open, please collaborate there instead of opening another.

Please wait for `triage/accepted` before starting work. It avoids spending time on a fix or feature that the maintainers would not merge.

## Commands for everyone

| Command | Effect |
| --- | --- |
| `/close`, `/reopen` | Closes or reopens an issue or pull request you opened. You can only reopen it if you closed it yourself; if a maintainer closed it, ask them. |

## Commands for contributors and maintainers

Contributors are people who already have commits in this repository. They can help triage issues and pull requests opened by others, but not their own.

| Command | Effect |
| --- | --- |
| `/triage accepted` | Adds `triage/accepted` and removes `needs-triage`. |
| `/triage needs-information` | Adds `triage/needs-information` and removes `needs-triage`. |
| `/kind bug\|feature\|enhancement\|task\|question` | Adds the matching `kind/*` label. |
| `/area cli\|connectors\|build\|docs\|packaging` | Adds the matching `component/*` label. |
| `/platform windows\|linux\|macos` | Adds the matching `platform/*` label. |
| `/good-first-issue` | Adds `good first issue`. On issues, needs `triage/accepted` first. |
| `/help` | Adds `help wanted`. On issues, needs `triage/accepted` first. |

## Commands for maintainers

Maintainers are people with write access to this repository. They can use every command above, including on their own issues, and the following ones to correct or manage triage.

| Command | Effect |
| --- | --- |
| `/remove-triage` | Removes the `triage/*` labels and adds `needs-triage` back. |
| `/remove-kind`, `/remove-area`, `/remove-platform` | Removes the matching label, for example `/remove-kind bug`. |
| `/remove-good-first-issue`, `/remove-help` | Removes `good first issue` or `help wanted`. |
| `/keep-open` | Adds `keep-open`, so the stale bot skips the item. `/remove-keep-open` removes it. |
| `/assign [@user]`, `/unassign [@user]` | Assigns or unassigns yourself or someone else, for example for mentorship work. GitHub only lets you assign people who have commented on the issue or have access to the repository. |
| `/close`, `/reopen` | Closes or reopens any issue or pull request. `/reopen` also removes the `status/*` label. |
| `/close duplicate\|wontfix\|invalid` | Closes with a reason and adds the matching `status/*` label. On issues it also sets GitHub's close reason (duplicate or not planned). |
| `/priority critical-urgent\|important-soon\|important-longterm\|backlog` | Sets the `priority/*` label, replacing any other priority. `/remove-priority` removes it. |
| `/milestone <title>` | Sets an open GitHub milestone, for example `/milestone 1.0.3`. `/milestone clear` or `/remove-milestone` removes it. |

## Pull request commands

These commands only work in pull request comments. `lgtm`, `approved` and `do-not-merge/hold` are review signals for maintainers: merging still needs an approving GitHub review from a code owner.

| Command | Who | Effect |
| --- | --- | --- |
| `/lgtm` | Contributors and maintainers, not on their own pull request | Adds `lgtm`. |
| `/approve` | Maintainers, not on their own pull request | Adds `approved`. |
| `/remove-lgtm` (`/lgtm cancel`), `/remove-approve` (`/approve cancel`) | Maintainers | Removes `lgtm` or `approved`. |
| `/hold` | Contributors, maintainers and the author | Adds `do-not-merge/hold`. The `hold` check fails while the label is set. |
| `/unhold` (`/hold cancel`) | Maintainers | Removes `do-not-merge/hold`. |
| `/retest` | Maintainers and the author | Re-runs the failed checks on the latest commit. Re-running from the Actions tab needs write access, so this lets contributors retry a flaky check (for example a network error during `go mod download`) without pushing an empty commit. |
| `/cc @user`, `/uncc @user` | Contributors, maintainers and the author | Requests or removes a review from someone. |

Commands inside code blocks, quoted lines (`> /kind bug`) and HTML comments are ignored, and unknown commands are ignored silently. If a command can't be applied, the bot reacts with 😕 and explains why, once per person and issue.

## Example

```text
/triage accepted
/kind bug
/area connectors
/good-first-issue
```
65 changes: 65 additions & 0 deletions hack/triage/parse.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright The Microcks Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// @ts-check

// Reads slash commands from comment text.

const MAX_COMMANDS = 10;

/**
* @typedef {object} Command
* @property {string} name command name without the slash, lowercased
* @property {string[]} args arguments, with a leading "@" removed
*/

/**
* Extracts slash commands from a comment body. Commands must start a line;
* lines inside fenced code blocks and quoted lines ("> /kind bug") are
* ignored so that quoting a previous comment does not re-run it.
*
* @param {string | null | undefined} body
* @returns {Command[]}
*/
function parseCommands(body) {
const commands = [];
let inFence = false;
// GitHub doesn't render HTML comments, so commands inside them would run
// without reviewers seeing them. An unclosed comment hides the rest.
const visible = String(body || '').replace(/<!--[\s\S]*?(-->|$)/g, '');
for (const raw of visible.split(/\r?\n/)) {
const line = raw.trim();
if (line.startsWith('```') || line.startsWith('~~~')) {
inFence = !inFence;
continue;
}
if (inFence || !line.startsWith('/')) {
continue;
}
const [head, ...args] = line.split(/\s+/);
const name = head.slice(1).toLowerCase();
if (!/^[a-z][a-z-]*$/.test(name)) {
continue;
}
commands.push({ name, args: args.map((a) => a.replace(/^@/, '')).filter(Boolean) });
if (commands.length >= MAX_COMMANDS) {
break;
}
}
return commands;
}

module.exports = { parseCommands };
Loading
Loading