https://github.com/knowledge-work/command-action
π§ IssueOps commands in GitHub Actions.
https://github.com/knowledge-work/command-action
github-actions issueops
Last synced: 27 days ago
JSON representation
π§ IssueOps commands in GitHub Actions.
- Host: GitHub
- URL: https://github.com/knowledge-work/command-action
- Owner: knowledge-work
- License: apache-2.0
- Created: 2024-08-27T01:58:02.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2026-05-14T13:27:40.000Z (29 days ago)
- Last Synced: 2026-05-14T15:37:34.783Z (29 days ago)
- Topics: github-actions, issueops
- Language: TypeScript
- Homepage:
- Size: 965 KB
- Stars: 7
- Watchers: 8
- Forks: 0
- Open Issues: 43
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Agents: AGENTS.md
Awesome Lists containing this project
README
# :wrench: IssueOps Command Action
IssueOps commands in GitHub Actions.
[![Build][badge-build]][build]
[![Apache-2.0][badge-license]][license]
[![semantic-release: angular][badge-semantic-release]][semantic-release]
`knowledge-work/command-action` is an Action inspired by [github/command](https://github.com/github/command/).
It provides primitive features to assist in implementing IssueOps commands. It parses key-value strings using a dedicated syntax and converts them into a format that can be used in subsequent workflows. These will help in implementing high-level IssueOps commands.
> [!note]
> Currently, a syntax that supports receiving multiple parameters is provided.
## :zap: Getting Started
This section introduces a quick start guide for `knowledge-work/command-action`.
### Usage
Specify the command name to be executed as IssueOps in the `command` option.
```yaml
- id: command
uses: knowledge-work/command-action@v1
with:
command: 'preview'
```
This sets up your custom IssueOps command to interpret comments on Issues and Pull Requests.
Refer to [Inputs](#inbox_tray-inputs) for other options.
### Example
Hereβs a simple workflow example to execute the `.greet` command in IssueOps.
```yaml
name: 'Greet DEMO'
on:
issue_comment:
types: [created]
jobs:
demo:
runs-on: ubuntu-latest
steps:
# Set up the ".greet" command.
- id: command
uses: knowledge-work/command-action@v1
with:
command: 'greet'
# Only run if `steps..outputs.continue` is "true".
# This indicates that `knowledge-work` successfully parsed the command and the subsequent steps should continue.
# IssueOps params are passed through `env:` and referenced as shell variables to avoid
# GitHub Actions expression injection from attacker-controlled comment content.
- name: Greet
if: ${{ steps.command.outputs.continue == 'true' }}
env:
NAME: ${{ fromJSON(steps.command.outputs.params).name }}
run: echo "Hi $NAME !"
# Add other steps necessary for IssueOps...
```
You can invoke the `.greet` command as follows:
```
.greet name="Alice"
```
Refer to [IssueOps Command Syntax](#book-issueops-command-syntax) for more detailed syntax.
## :book: IssueOps Command Syntax
When executing an IssueOps command, it often needs to accept some parameters. This Action parses the parameters using a simple key-value syntax, allowing you to quickly build the scaffolding required for more complex IssueOps commands.
### Overview
An IssueOps command is called in the following format:
```
. =, =, ...
```
`` should consist of the following:
- A string starting with alphanumeric characters or an underscore.
- A string followed by alphanumeric characters, underscores, or hyphens.
The key-value parameters provided are converted into JSON format and made available as `outputs.params`. For example, if the following command is executed:
```
.greet name="Alice", age=20
```
You will get the following `outputs.params`:
```json
{
"name": "Alice",
"age": 20
}
```
### Values
Values that can be specified for parameters include numbers, strings, booleans, and null. Below are examples of each. Refer to [`parse.test.ts`](./src/parse.test.ts) for more detailed specifications.
#### Numbers
Supports common signed and unsigned integers as well as decimals.
```
.command key=123
.command key=+456
.command key=-789
.command key=0.5
```
#### Strings
Strings can use single or double quotes. Escaping is also supported.
```
.command key='value'
.command key="value"
.command key='value \' with escape'
.command key="value \" with escape"
```
Quotes can also be omitted if the string does not contain spaces or commas.
```
.command key=/path/to/file.txt
```
#### Booleans
Supports booleans in JSON format.
```
.command key=true
.command key=false
```
#### null
Supports null in JSON format.
```
.command key=null
```
## :inbox_tray: Inputs
| ID | Required | Default | Description |
| :----------------- | :----------------- | :------------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `command` | :white_check_mark: | n/a | The name of the command to be used in IssueOps, which can be specified as a comma-separated list. |
| `allowed_contexts` | | `issue,pull_request,discussion` | The comment contexts that trigger the IssueOps command, specified as a comma-separated list. Allowed values: `"issue"`, `"pull_request"`, `"discussion"`. |
## :outbox_tray: Outputs
| ID | Description |
| :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `continue` | Indicates whether the IssueOps command was triggered and the workflow should continue with the string `"true"`. If the action did not complete successfully, `"false"` will be used. |
| `params` | The parameters of the triggered IssueOps command, provided as a JSON string. |
| `comment_id` | The ID of the comment that triggered this action. |
| `actor` | The GitHub handle of the actor who executed the IssueOps command. |
| `issue_number` | [Deprecated] The issue number of the comment that triggered this action. Use `number` instead. This output will be removed in the next major release. |
| `number` | The number of the issue, pull request, or discussion that triggered this action. |
| `context` | The context that triggered this action. One of `"issue"`, `"pull_request"`, or `"discussion"`. |
| `command` | The command of the triggered IssueOps command. |
## :bulb: TIPS
A section introducing tips for implementing IssueOps commands.
### Triggering from GitHub Discussions
`command-action` also handles GitHub Discussions when the workflow is triggered by the `discussion_comment` event. The same parsing logic applies β the only differences are that `outputs.context` becomes `"discussion"` and `outputs.issue_number` is not emitted (use `outputs.number` instead).
```yaml
name: 'Greet DEMO (Discussions)'
on:
discussion_comment:
types: [created]
permissions:
contents: read
discussions: write # only required if your follow-up step writes back to the discussion (e.g. reactions via GraphQL)
jobs:
demo:
runs-on: ubuntu-latest
steps:
- id: command
uses: knowledge-work/command-action@v1
with:
command: 'greet'
- if: ${{ steps.command.outputs.continue == 'true' }}
env:
NAME: ${{ fromJSON(steps.command.outputs.params).name }}
run: echo "Hi $NAME !"
```
> [!warning]
> Discussion / Issue / PR comments are attacker-controlled. Pass IssueOps params via `env:` and reference them as shell variables (`"$NAME"`) instead of interpolating `${{ ... }}` directly into a `run:` script. See [GitHub Actions security hardening](https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable) for details.
To restrict the action to discussions only (or to issues / pull requests only), use the [`allowed_contexts`](#inbox_tray-inputs) input β for example `allowed_contexts: 'discussion'`.
### Reacting to the comment
You can use [actions/github-script](https://github.com/actions/github-script) to add a reaction to the comment that triggered the IssueOps command.
```yaml
jobs:
demo:
runs-on: ubuntu-latest
steps:
- id: command
uses: knowledge-work/command-action@v1
with:
command: 'greet'
# A snippet to add a reaction to the comment that triggered the command.
- if: ${{ steps.command.outputs.continue == 'true' }}
name: Reactions
uses: actions/github-script@v7
with:
script: |
await github.rest.reactions.createForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id,
content: 'eyes',
});
# Add other steps necessary for IssueOps...
```
Please note that this action does not provide a reaction feature. However, by leveraging GitHub Action's awesome ecosystem, you can implement highly flexible IssueOps commands.
## :paw_prints: Development
Introducing the steps for developing `command-action`.
### Setup
Using [mise](https://mise.jdx.dev/), activate the versions of Node.js and pnpm written in `.mise.toml`.
```bash
$ mise install
$ pnpm i
```
### E2E (self-dogfood)
The action is validated against real GitHub event payloads via an environment-gated workflow. See [`docs/e2e.md`](./docs/e2e.md) for the comment convention, security model, and required repo settings.
## LICENSE
See [LICENSE][license].
Copyright 2024 Knowledge Work Inc.
[badge-build]: https://img.shields.io/github/actions/workflow/status/knowledge-work/command-action/ci.yaml?style=flat-square
[badge-license]: https://img.shields.io/github/license/knowledge-work/command-action?style=flat-square
[badge-semantic-release]: https://img.shields.io/badge/semantic--release-angular-e10079?logo=semantic-release&style=flat-square
[build]: https://github.com/knowledge-work/command-action/actions/workflows/ci.yaml
[license]: ./LICENSE
[semantic-release]: https://github.com/semantic-release/semantic-release