v5 (#431)
* feat: support yml or yaml (#427) test: support yml or yaml chore: lint * Fix getting permissions for the contributors who are a part of the team (#424) * Fix getActorPermission to handle team-based permissions * Use 'user.permissions' object to return permission * Add RepoPermission type * Make new build * feat: update runtime to node 24 * fix: eslint-plugin dep * fix: remove unused type * docs: update whats new --------- Co-authored-by: Patrick Lee Scott <[email protected]> Co-authored-by: Volodymyr Zotov <[email protected]>
This commit is contained in:
co-authored by
Patrick Lee Scott
Volodymyr Zotov
parent
9a73d036b8
commit
e1b4e266bc
@@ -17,7 +17,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 20.x
|
node-version-file: package.json
|
||||||
cache: npm
|
cache: npm
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: npm run build
|
- run: npm run build
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
name: Hello yaml Command
|
||||||
|
on:
|
||||||
|
repository_dispatch:
|
||||||
|
types: [hello-yaml-local-command]
|
||||||
|
jobs:
|
||||||
|
helloYaml:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Add reaction
|
||||||
|
uses: peter-evans/create-or-update-comment@v4
|
||||||
|
with:
|
||||||
|
comment-id: ${{ github.event.client_payload.github.payload.comment.id }}
|
||||||
|
reactions: hooray
|
||||||
|
|
||||||
|
- name: Create URL to the run output
|
||||||
|
id: vars
|
||||||
|
run: echo "run-url=https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Create comment
|
||||||
|
uses: peter-evans/create-or-update-comment@v4
|
||||||
|
with:
|
||||||
|
issue-number: ${{ github.event.client_payload.github.payload.issue.number }}
|
||||||
|
body: |
|
||||||
|
Hello @${{ github.event.client_payload.github.actor }}!
|
||||||
|
|
||||||
|
This command was in a workflow file with the `.yaml` extension.
|
||||||
|
|
||||||
|
[Click here to see the command run output][1]
|
||||||
|
|
||||||
|
[1]: ${{ steps.vars.outputs.run-url }}
|
||||||
@@ -19,6 +19,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
token: ${{ secrets.REPO_ACCESS_TOKEN }}
|
token: ${{ secrets.REPO_ACCESS_TOKEN }}
|
||||||
commands: |
|
commands: |
|
||||||
|
hello-yaml-local
|
||||||
hello-world-local
|
hello-world-local
|
||||||
ping-local
|
ping-local
|
||||||
permission: none
|
permission: none
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ on:
|
|||||||
type: choice
|
type: choice
|
||||||
description: The major version tag to update
|
description: The major version tag to update
|
||||||
options:
|
options:
|
||||||
- v4
|
- v5
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
tag:
|
tag:
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Slash Command Dispatch
|
- name: Slash Command Dispatch
|
||||||
uses: peter-evans/slash-command-dispatch@v4
|
uses: peter-evans/slash-command-dispatch@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
commands: |
|
commands: |
|
||||||
@@ -102,7 +102,7 @@ You can use a [PAT](https://docs.github.com/en/github/authenticating-to-github/c
|
|||||||
|
|
||||||
```yml
|
```yml
|
||||||
- name: Slash Command Dispatch
|
- name: Slash Command Dispatch
|
||||||
uses: peter-evans/slash-command-dispatch@v4
|
uses: peter-evans/slash-command-dispatch@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
reaction-token: ${{ secrets.PAT }}
|
reaction-token: ${{ secrets.PAT }}
|
||||||
@@ -178,7 +178,7 @@ It will also contain any static arguments if configured.
|
|||||||
|
|
||||||
To demonstrate, take the following configuration as an example.
|
To demonstrate, take the following configuration as an example.
|
||||||
```yml
|
```yml
|
||||||
- uses: peter-evans/slash-command-dispatch@v4
|
- uses: peter-evans/slash-command-dispatch@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
commands: |
|
commands: |
|
||||||
@@ -248,7 +248,7 @@ The simplest response is to add a :tada: reaction to the comment.
|
|||||||
|
|
||||||
```yml
|
```yml
|
||||||
- name: Add reaction
|
- name: Add reaction
|
||||||
uses: peter-evans/create-or-update-comment@v4
|
uses: peter-evans/create-or-update-comment@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
||||||
@@ -264,7 +264,7 @@ Another option is to reply with a new comment containing a link to the run outpu
|
|||||||
run: echo "run-url=https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" >> $GITHUB_OUTPUT
|
run: echo "run-url=https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Create comment
|
- name: Create comment
|
||||||
uses: peter-evans/create-or-update-comment@v4
|
uses: peter-evans/create-or-update-comment@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
||||||
|
|||||||
+1
-1
@@ -41,7 +41,7 @@ outputs:
|
|||||||
error-message:
|
error-message:
|
||||||
description: 'Validation errors when using `workflow` dispatch.'
|
description: 'Validation errors when using `workflow` dispatch.'
|
||||||
runs:
|
runs:
|
||||||
using: 'node20'
|
using: 'node24'
|
||||||
main: 'dist/index.js'
|
main: 'dist/index.js'
|
||||||
branding:
|
branding:
|
||||||
icon: 'target'
|
icon: 'target'
|
||||||
|
|||||||
Vendored
+50
-18
@@ -293,24 +293,41 @@ class GitHubHelper {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
getActorPermission(repo, actor) {
|
getActorPermission(repo, actor) {
|
||||||
|
var _a;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
// https://docs.github.com/en/graphql/reference/enums#repositorypermission
|
// Use the REST API approach which can detect both direct and team-based permissions
|
||||||
// https://docs.github.com/en/graphql/reference/objects#repositorycollaboratoredge
|
// This is more reliable than the GraphQL approach for team permissions and works better with default GITHUB_TOKEN
|
||||||
// Returns 'READ', 'TRIAGE', 'WRITE', 'MAINTAIN', 'ADMIN'
|
try {
|
||||||
const query = `query CollaboratorPermission($owner: String!, $repo: String!, $collaborator: String) {
|
const { data: collaboratorPermission } = yield this.octokit.rest.repos.getCollaboratorPermissionLevel(Object.assign(Object.assign({}, repo), { username: actor }));
|
||||||
repository(owner:$owner, name:$repo) {
|
const permissions = (_a = collaboratorPermission.user) === null || _a === void 0 ? void 0 : _a.permissions;
|
||||||
collaborators(login: $collaborator) {
|
core.debug(`REST API collaborator permission: ${(0, util_1.inspect)(permissions)}`);
|
||||||
edges {
|
// Use the detailed permissions object to get the highest permission level
|
||||||
permission
|
if (permissions) {
|
||||||
}
|
// Check permissions in order of highest to lowest
|
||||||
}
|
if (permissions.admin) {
|
||||||
}
|
return 'admin';
|
||||||
}`;
|
}
|
||||||
const collaboratorPermission = yield this.octokit.graphql(query, Object.assign(Object.assign({}, repo), { collaborator: actor }));
|
else if (permissions.maintain) {
|
||||||
core.debug(`CollaboratorPermission: ${(0, util_1.inspect)(collaboratorPermission.repository.collaborators.edges)}`);
|
return 'maintain';
|
||||||
return collaboratorPermission.repository.collaborators.edges.length > 0
|
}
|
||||||
? collaboratorPermission.repository.collaborators.edges[0].permission.toLowerCase()
|
else if (permissions.push) {
|
||||||
: 'none';
|
return 'write';
|
||||||
|
}
|
||||||
|
else if (permissions.triage) {
|
||||||
|
core.debug(`User ${actor} has triage permission via REST API`);
|
||||||
|
return 'triage';
|
||||||
|
}
|
||||||
|
else if (permissions.pull) {
|
||||||
|
core.debug(`User ${actor} has read permission via REST API`);
|
||||||
|
return 'read';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 'none';
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
core.debug(`REST API permission check failed: ${utils.getErrorMessage(error)}`);
|
||||||
|
return 'none';
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
tryAddReaction(repo, commentId, reaction) {
|
tryAddReaction(repo, commentId, reaction) {
|
||||||
@@ -350,7 +367,8 @@ class GitHubHelper {
|
|||||||
}
|
}
|
||||||
createWorkflowDispatch(cmd, clientPayload) {
|
createWorkflowDispatch(cmd, clientPayload) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const workflow = `${cmd.command}${cmd.event_type_suffix}.yml`;
|
const workflowName = `${cmd.command}${cmd.event_type_suffix}`;
|
||||||
|
const workflow = yield this.getWorkflow(cmd.repository, workflowName);
|
||||||
const slashCommand = clientPayload.slash_command;
|
const slashCommand = clientPayload.slash_command;
|
||||||
const ref = slashCommand.args.named.ref
|
const ref = slashCommand.args.named.ref
|
||||||
? slashCommand.args.named.ref
|
? slashCommand.args.named.ref
|
||||||
@@ -370,6 +388,20 @@ class GitHubHelper {
|
|||||||
core.info(`Command '${cmd.command}' dispatched to workflow '${workflow}' in '${cmd.repository}'`);
|
core.info(`Command '${cmd.command}' dispatched to workflow '${workflow}' in '${cmd.repository}'`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
getWorkflow(repository, workflowName) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
core.debug(`Getting workflow ${workflowName} for repository ${repository}`);
|
||||||
|
const { data: workflows } = yield this.octokit.rest.actions.listRepoWorkflows(Object.assign({}, this.parseRepository(repository)));
|
||||||
|
for (const workflow of workflows.workflows) {
|
||||||
|
if (workflow.path === `${workflowName}.yml` ||
|
||||||
|
workflow.path === `${workflowName}.yaml`) {
|
||||||
|
core.debug(`Selecting workflow file ${workflow.path}`);
|
||||||
|
return workflow.path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error(`Workflow ${workflowName} not found`);
|
||||||
|
});
|
||||||
|
}
|
||||||
getDefaultBranch(repository) {
|
getDefaultBranch(repository) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const { data: repo } = yield this.octokit.rest.repos.get(Object.assign({}, this.parseRepository(repository)));
|
const { data: repo } = yield this.octokit.rest.repos.get(Object.assign({}, this.parseRepository(repository)));
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ For example, the following basic configuration means that all commands must have
|
|||||||
|
|
||||||
```yml
|
```yml
|
||||||
- name: Slash Command Dispatch
|
- name: Slash Command Dispatch
|
||||||
uses: peter-evans/slash-command-dispatch@v4
|
uses: peter-evans/slash-command-dispatch@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
commands: |
|
commands: |
|
||||||
@@ -38,7 +38,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Slash Command Dispatch
|
- name: Slash Command Dispatch
|
||||||
uses: peter-evans/slash-command-dispatch@v4
|
uses: peter-evans/slash-command-dispatch@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
config: >
|
config: >
|
||||||
@@ -84,7 +84,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Slash Command Dispatch
|
- name: Slash Command Dispatch
|
||||||
uses: peter-evans/slash-command-dispatch@v4
|
uses: peter-evans/slash-command-dispatch@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
config-from-file: .github/slash-command-dispatch.json
|
config-from-file: .github/slash-command-dispatch.json
|
||||||
|
|||||||
+7
-7
@@ -50,7 +50,7 @@ jobs:
|
|||||||
|
|
||||||
# Add reaction to the comment
|
# Add reaction to the comment
|
||||||
- name: Add reaction
|
- name: Add reaction
|
||||||
uses: peter-evans/create-or-update-comment@v4
|
uses: peter-evans/create-or-update-comment@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
||||||
@@ -111,7 +111,7 @@ jobs:
|
|||||||
|
|
||||||
# Add reaction to the comment
|
# Add reaction to the comment
|
||||||
- name: Add reaction
|
- name: Add reaction
|
||||||
uses: peter-evans/create-or-update-comment@v4
|
uses: peter-evans/create-or-update-comment@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
||||||
@@ -158,7 +158,7 @@ jobs:
|
|||||||
git push
|
git push
|
||||||
|
|
||||||
- name: Add reaction
|
- name: Add reaction
|
||||||
uses: peter-evans/create-or-update-comment@v4
|
uses: peter-evans/create-or-update-comment@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
||||||
@@ -204,7 +204,7 @@ jobs:
|
|||||||
git push --force-with-lease
|
git push --force-with-lease
|
||||||
|
|
||||||
- name: Update comment
|
- name: Update comment
|
||||||
uses: peter-evans/create-or-update-comment@v4
|
uses: peter-evans/create-or-update-comment@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
||||||
@@ -218,7 +218,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Update comment
|
- name: Update comment
|
||||||
uses: peter-evans/create-or-update-comment@v4
|
uses: peter-evans/create-or-update-comment@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
||||||
@@ -279,7 +279,7 @@ jobs:
|
|||||||
git push
|
git push
|
||||||
|
|
||||||
- name: Add reaction
|
- name: Add reaction
|
||||||
uses: peter-evans/create-or-update-comment@v4
|
uses: peter-evans/create-or-update-comment@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
||||||
@@ -301,7 +301,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Update comment
|
- name: Update comment
|
||||||
uses: peter-evans/create-or-update-comment@v4
|
uses: peter-evans/create-or-update-comment@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
|
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
|
||||||
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ Follow this guide to get started with a working `/example` command.
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Add reaction
|
- name: Add reaction
|
||||||
uses: peter-evans/create-or-update-comment@v4
|
uses: peter-evans/create-or-update-comment@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
||||||
@@ -56,7 +56,7 @@ Command processing setup is complete! Now we need to setup command dispatch for
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Slash Command Dispatch
|
- name: Slash Command Dispatch
|
||||||
uses: peter-evans/slash-command-dispatch@v4
|
uses: peter-evans/slash-command-dispatch@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
commands: example
|
commands: example
|
||||||
|
|||||||
@@ -1,3 +1,15 @@
|
|||||||
|
## Updating from `v4` to `v5`
|
||||||
|
|
||||||
|
### Breaking changes
|
||||||
|
|
||||||
|
- If using self-hosted runners or GitHub Enterprise Server, there are minimum requirements for `v5` to run. See "What's new" below for details.
|
||||||
|
### What's new
|
||||||
|
|
||||||
|
- Updated runtime to Node.js 24
|
||||||
|
- The action now requires a minimum version of [v2.327.1](https://github.com/actions/runner/releases/tag/v2.327.1) for the Actions runner. Update self-hosted runners to v2.327.1 or later to ensure compatibility.
|
||||||
|
- The `.yaml` extension is now supported for dispatch type `workflow`.
|
||||||
|
- A change has been made to fetching permissions for contributors. Hopefully this will resolve some issues with fetching permissions for contributors that are part of a team.
|
||||||
|
|
||||||
## Updating from `v3` to `v4`
|
## Updating from `v3` to `v4`
|
||||||
|
|
||||||
### Breaking changes
|
### Breaking changes
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ There are significant differences in the action's behaviour when using `workflow
|
|||||||
|
|
||||||
It is important to name the `workflow_dispatch` event workflow correctly since the action targets the workflow based on its filename.
|
It is important to name the `workflow_dispatch` event workflow correctly since the action targets the workflow based on its filename.
|
||||||
The target filename is a combination of the command name and the `event-type-suffix`.
|
The target filename is a combination of the command name and the `event-type-suffix`.
|
||||||
Additionally, the file extension must be `.yml`.
|
The file extensions `.yml` and `.yaml` are supported.
|
||||||
|
|
||||||
For the following example configuration, the target workflows are:
|
For the following example configuration, the target workflows are:
|
||||||
- `deploy-command.yml`
|
- `deploy-command.yml`
|
||||||
@@ -36,7 +36,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Slash Command Dispatch
|
- name: Slash Command Dispatch
|
||||||
uses: peter-evans/slash-command-dispatch@v4
|
uses: peter-evans/slash-command-dispatch@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
commands: |
|
commands: |
|
||||||
@@ -85,7 +85,7 @@ The simplest response is to add a :tada: reaction to the comment.
|
|||||||
|
|
||||||
```yml
|
```yml
|
||||||
- name: Add reaction
|
- name: Add reaction
|
||||||
uses: peter-evans/create-or-update-comment@v4
|
uses: peter-evans/create-or-update-comment@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
repository: ${{ github.event.inputs.repository }}
|
repository: ${{ github.event.inputs.repository }}
|
||||||
@@ -107,7 +107,7 @@ The `error-message` output can be used to provide feedback to the user as follow
|
|||||||
```yml
|
```yml
|
||||||
- name: Slash Command Dispatch
|
- name: Slash Command Dispatch
|
||||||
id: scd
|
id: scd
|
||||||
uses: peter-evans/slash-command-dispatch@v4
|
uses: peter-evans/slash-command-dispatch@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
commands: |
|
commands: |
|
||||||
@@ -118,7 +118,7 @@ The `error-message` output can be used to provide feedback to the user as follow
|
|||||||
|
|
||||||
- name: Edit comment with error message
|
- name: Edit comment with error message
|
||||||
if: steps.scd.outputs.error-message
|
if: steps.scd.outputs.error-message
|
||||||
uses: peter-evans/create-or-update-comment@v4
|
uses: peter-evans/create-or-update-comment@v5
|
||||||
with:
|
with:
|
||||||
comment-id: ${{ github.event.comment.id }}
|
comment-id: ${{ github.event.comment.id }}
|
||||||
body: |
|
body: |
|
||||||
|
|||||||
Generated
+461
-536
File diff suppressed because it is too large
Load Diff
+5
-1
@@ -1,9 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "slash-command-dispatch",
|
"name": "slash-command-dispatch",
|
||||||
"version": "4.0.0",
|
"version": "5.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Facilitates 'ChatOps' by creating dispatch events for slash commands",
|
"description": "Facilitates 'ChatOps' by creating dispatch events for slash commands",
|
||||||
"main": "lib/main.js",
|
"main": "lib/main.js",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=24.4.0"
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc && ncc build",
|
"build": "tsc && ncc build",
|
||||||
"format": "prettier --write '**/*.ts'",
|
"format": "prettier --write '**/*.ts'",
|
||||||
@@ -39,6 +42,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^27.0.3",
|
"@types/jest": "^27.0.3",
|
||||||
"@types/node": "^16.18.126",
|
"@types/node": "^16.18.126",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||||
"@typescript-eslint/parser": "^5.62.0",
|
"@typescript-eslint/parser": "^5.62.0",
|
||||||
"@vercel/ncc": "^0.38.4",
|
"@vercel/ncc": "^0.38.4",
|
||||||
"eslint": "^8.57.1",
|
"eslint": "^8.57.1",
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ export function configIsValid(config: Command[]): string | null {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function actorHasPermission(
|
export function actorHasPermission(
|
||||||
actorPermission: string,
|
actorPermission: utils.RepoPermission,
|
||||||
commandPermission: string
|
commandPermission: string
|
||||||
): boolean {
|
): boolean {
|
||||||
const permissionLevels = Object.freeze({
|
const permissionLevels = Object.freeze({
|
||||||
|
|||||||
+63
-37
@@ -25,18 +25,6 @@ interface Repository {
|
|||||||
repo: string
|
repo: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type CollaboratorPermission = {
|
|
||||||
repository: {
|
|
||||||
collaborators: {
|
|
||||||
edges: [
|
|
||||||
{
|
|
||||||
permission: string
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class GitHubHelper {
|
export class GitHubHelper {
|
||||||
private octokit: InstanceType<typeof Octokit>
|
private octokit: InstanceType<typeof Octokit>
|
||||||
|
|
||||||
@@ -55,32 +43,47 @@ export class GitHubHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getActorPermission(repo: Repository, actor: string): Promise<string> {
|
async getActorPermission(
|
||||||
// https://docs.github.com/en/graphql/reference/enums#repositorypermission
|
repo: Repository,
|
||||||
// https://docs.github.com/en/graphql/reference/objects#repositorycollaboratoredge
|
actor: string
|
||||||
// Returns 'READ', 'TRIAGE', 'WRITE', 'MAINTAIN', 'ADMIN'
|
): Promise<utils.RepoPermission> {
|
||||||
const query = `query CollaboratorPermission($owner: String!, $repo: String!, $collaborator: String) {
|
// Use the REST API approach which can detect both direct and team-based permissions
|
||||||
repository(owner:$owner, name:$repo) {
|
// This is more reliable than the GraphQL approach for team permissions and works better with default GITHUB_TOKEN
|
||||||
collaborators(login: $collaborator) {
|
try {
|
||||||
edges {
|
const {data: collaboratorPermission} =
|
||||||
permission
|
await this.octokit.rest.repos.getCollaboratorPermissionLevel({
|
||||||
}
|
...repo,
|
||||||
|
username: actor
|
||||||
|
})
|
||||||
|
|
||||||
|
const permissions = collaboratorPermission.user?.permissions
|
||||||
|
core.debug(`REST API collaborator permission: ${inspect(permissions)}`)
|
||||||
|
|
||||||
|
// Use the detailed permissions object to get the highest permission level
|
||||||
|
if (permissions) {
|
||||||
|
// Check permissions in order of highest to lowest
|
||||||
|
if (permissions.admin) {
|
||||||
|
return 'admin'
|
||||||
|
} else if (permissions.maintain) {
|
||||||
|
return 'maintain'
|
||||||
|
} else if (permissions.push) {
|
||||||
|
return 'write'
|
||||||
|
} else if (permissions.triage) {
|
||||||
|
core.debug(`User ${actor} has triage permission via REST API`)
|
||||||
|
return 'triage'
|
||||||
|
} else if (permissions.pull) {
|
||||||
|
core.debug(`User ${actor} has read permission via REST API`)
|
||||||
|
return 'read'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}`
|
|
||||||
const collaboratorPermission =
|
return 'none'
|
||||||
await this.octokit.graphql<CollaboratorPermission>(query, {
|
} catch (error) {
|
||||||
...repo,
|
core.debug(
|
||||||
collaborator: actor
|
`REST API permission check failed: ${utils.getErrorMessage(error)}`
|
||||||
})
|
)
|
||||||
core.debug(
|
return 'none'
|
||||||
`CollaboratorPermission: ${inspect(
|
}
|
||||||
collaboratorPermission.repository.collaborators.edges
|
|
||||||
)}`
|
|
||||||
)
|
|
||||||
return collaboratorPermission.repository.collaborators.edges.length > 0
|
|
||||||
? collaboratorPermission.repository.collaborators.edges[0].permission.toLowerCase()
|
|
||||||
: 'none'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async tryAddReaction(
|
async tryAddReaction(
|
||||||
@@ -150,7 +153,8 @@ export class GitHubHelper {
|
|||||||
cmd: Command,
|
cmd: Command,
|
||||||
clientPayload: ClientPayload
|
clientPayload: ClientPayload
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const workflow = `${cmd.command}${cmd.event_type_suffix}.yml`
|
const workflowName = `${cmd.command}${cmd.event_type_suffix}`
|
||||||
|
const workflow = await this.getWorkflow(cmd.repository, workflowName)
|
||||||
const slashCommand: SlashCommandPayload = clientPayload.slash_command
|
const slashCommand: SlashCommandPayload = clientPayload.slash_command
|
||||||
const ref = slashCommand.args.named.ref
|
const ref = slashCommand.args.named.ref
|
||||||
? slashCommand.args.named.ref
|
? slashCommand.args.named.ref
|
||||||
@@ -181,6 +185,28 @@ export class GitHubHelper {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async getWorkflow(
|
||||||
|
repository: string,
|
||||||
|
workflowName: string
|
||||||
|
): Promise<string> {
|
||||||
|
core.debug(`Getting workflow ${workflowName} for repository ${repository}`)
|
||||||
|
const {data: workflows} = await this.octokit.rest.actions.listRepoWorkflows(
|
||||||
|
{
|
||||||
|
...this.parseRepository(repository)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
for (const workflow of workflows.workflows) {
|
||||||
|
if (
|
||||||
|
workflow.path === `${workflowName}.yml` ||
|
||||||
|
workflow.path === `${workflowName}.yaml`
|
||||||
|
) {
|
||||||
|
core.debug(`Selecting workflow file ${workflow.path}`)
|
||||||
|
return workflow.path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error(`Workflow ${workflowName} not found`)
|
||||||
|
}
|
||||||
|
|
||||||
private async getDefaultBranch(repository: string): Promise<string> {
|
private async getDefaultBranch(repository: string): Promise<string> {
|
||||||
const {data: repo} = await this.octokit.rest.repos.get({
|
const {data: repo} = await this.octokit.rest.repos.get({
|
||||||
...this.parseRepository(repository)
|
...this.parseRepository(repository)
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
|
|
||||||
|
export type RepoPermission =
|
||||||
|
| 'admin'
|
||||||
|
| 'maintain'
|
||||||
|
| 'write'
|
||||||
|
| 'triage'
|
||||||
|
| 'read'
|
||||||
|
| 'none'
|
||||||
|
|
||||||
export function getInputAsArray(
|
export function getInputAsArray(
|
||||||
name: string,
|
name: string,
|
||||||
options?: core.InputOptions
|
options?: core.InputOptions
|
||||||
|
|||||||
Reference in New Issue
Block a user