Skip to content

Commit 125042e

Browse files
author
Ludovic TOURMAN
committed
Rework getWorkflowRunId()
1 parent 00dba38 commit 125042e

File tree

3 files changed

+133
-110
lines changed

3 files changed

+133
-110
lines changed

README.md

Lines changed: 69 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,77 +11,94 @@ For details of the `workflow_dispatch` even see [this blog post introducing this
1111

1212
*Note 2.* If you want to reference the target workflow by ID, you will need to list them with the following REST API call `curl https://api.github.com/repos/{{owner}}/{{repo}}/actions/workflows -H "Authorization: token {{pat-token}}"`
1313

14-
_This action is a fork of `benc-uk/workflow-dispatch` to add support for waiting for workflow completion._
14+
*This action is a fork of `benc-uk/workflow-dispatch` to add support for waiting for workflow completion.*
1515

1616
## Inputs
17+
1718
### `workflow`
19+
1820
> **Required.** The name or the filename or ID of the workflow to trigger and run.
1921
2022
### `token`
2123

2224
> **Required.** A GitHub access token (PAT) with write access to the repo in question.
23-
>
25+
>
2426
> **NOTE.** The automatically provided token e.g. `${{ secrets.GITHUB_TOKEN }}` can not be used, GitHub prevents this token from being able to fire the `workflow_dispatch` and `repository_dispatch` event. [The reasons are explained in the docs](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#triggering-new-workflows-using-a-personal-access-token).
2527
> The solution is to manually create a PAT and store it as a secret e.g. `${{ secrets.PERSONAL_TOKEN }}`
2628
2729
### `inputs`
30+
2831
> **Optional.** The inputs to pass to the workflow (if any are configured), this must be a JSON encoded string, e.g. `{ "myInput": "foobar" }`.
2932
>
3033
> All values must be strings (even if they are used as booleans or numbers in the triggered workflow). The triggered workflow should use `fromJson` function to get the right type
3134
3235
### `ref`
36+
3337
> **Optional.** The Git reference used with the triggered workflow run. The reference can be a branch, tag, or a commit SHA. If omitted the context ref of the triggering workflow is used. If you want to trigger on pull requests and run the target workflow in the context of the pull request branch, set the ref to `${{ github.event.pull_request.head.ref }}`
3438
3539
### `repo`
40+
3641
> **Optional.** The default behavior is to trigger workflows in the same repo as the triggering workflow, if you wish to trigger in another GitHub repo "externally", then provide the owner + repo name with slash between them e.g. `microsoft/vscode`
3742
3843
### `run-name` (since 3.0.0)
44+
3945
> **Optional.** The default behavior is to get the remote run ID based on the latest workflow name and date, if you have multiple of the same workflow running at the same time it can point to an incorrect run id.
40-
> You can specify the run name to fetch the run ID based on the actual run name.
46+
> To prevent from this, you can specify a unique run name to fetch the concerned run ID. It will also requires you to set that same value as an input for your remote workflow (See the [corresponding example](#invoke-workflow-with-a-unique-run-name-since-300))
4147
4248
### `wait-for-completion`
49+
4350
> **Optional.** If `true`, this action will actively poll the workflow run to get the result of the triggered workflow. It is enabled by default. If the triggered workflow fails due to either `failure`, `timed_out` or `cancelled` then the step that has triggered the other workflow will be marked as failed too.
4451
4552
### `wait-for-completion-timeout`
53+
4654
> **Optional.** The time to wait to mark triggered workflow has timed out. The time must be suffixed by the time unit e.g. `10m`. Time unit can be `s` for seconds, `m` for minutes and `h` for hours. It has no effect if `wait-for-completion` is `false`. Default is `1h`
4755
4856
### `wait-for-completion-interval`
57+
4958
> **Optional.** The time to wait between two polls for getting run status. The time must be suffixed by the time unit e.g. `10m`. Time unit can be `s` for seconds, `m` for minutes and `h` for hours. It has no effect if `wait-for-completion` is `false`. Default is `1m`.
50-
>
59+
>
5160
> **/!\ Do not use a value that is too small to avoid `API Rate limit exceeded`**
5261
5362
### `display-workflow-run-url`
63+
5464
> **Optional.** If `true`, it displays in logs the URL of the triggered workflow. It is useful to follow the progress of the triggered workflow. It is enabled by default.
5565
5666
### `display-workflow-run-url-timeout`
67+
5768
> **Optional.** The time to wait for getting the workflow run URL. If the timeout is reached, it doesn't fail and continues. Displaying the workflow URL is just for information purpose. The time must be suffixed by the time unit e.g. `10m`. Time unit can be `s` for seconds, `m` for minutes and `h` for hours. It has no effect if `display-workflow-run-url` is `false`. Default is `10m`
5869
5970
### `display-workflow-run-url-interval`
71+
6072
> **Optional.** The time to wait between two polls for getting workflow run URL. The time must be suffixed by the time unit e.g. `10m`. Time unit can be `s` for seconds, `m` for minutes and `h` for hours. It has no effect if `display-workflow-run-url` is `false`. Default is `1m`.
61-
>
73+
>
6274
> **/!\ Do not use a value that is too small to avoid `API Rate limit exceeded`**
6375
6476
### `workflow-logs`
77+
6578
> **Optional.** Indicate what to do with logs of the triggered workflow:
66-
>
79+
>
6780
> * `print`: Retrieve the logs for each job of the triggered workflow and print into the logs of the job that triggered the workflow.
6881
> * `ignore`: Do not retrieve log of triggered workflow at all (default).
69-
>
70-
> Only available when `wait-for-completion` is `true`.
71-
>
82+
>
83+
> Only available when `wait-for-completion` is `true`.
84+
>
7285
> Default is `ignore`.
7386
74-
7587
## Outputs
88+
7689
### `workflow-url`
90+
7791
> The URL of the workflow run that has been triggered. It may be undefined if the URL couldn't be retrieved (timeout reached) or if `wait-for-completion` and `display-workflow-run-url` are > both `false`
7892
7993
### `workflow-conclusion`
94+
8095
> The result of the triggered workflow. May be one of `success`, `failure`, `cancelled`, `timed_out`, `skipped`, `neutral`, `action_required`. The step in your workflow will fail if the triggered workflow completes with `failure`, `cancelled` or `timed_out`. Other workflow conlusion are considered success.
8196
> Only available if `wait-for-completion` is `true`
8297
83-
8498
## Example usage
99+
100+
### Invoke workflow without inputs. Wait for result
101+
85102
```yaml
86103
- name: Invoke workflow without inputs. Wait for result
87104
uses: aurelien-baudet/workflow-dispatch@v2
@@ -90,6 +107,8 @@ _This action is a fork of `benc-uk/workflow-dispatch` to add support for waiting
90107
token: ${{ secrets.PERSONAL_TOKEN }}
91108
```
92109
110+
### Invoke workflow without inputs. Don't wait for result
111+
93112
```yaml
94113
- name: Invoke workflow without inputs. Don't wait for result
95114
uses: aurelien-baudet/workflow-dispatch@v2
@@ -99,6 +118,8 @@ _This action is a fork of `benc-uk/workflow-dispatch` to add support for waiting
99118
wait-for-completion: false
100119
```
101120
121+
### Invoke workflow with inputs
122+
102123
```yaml
103124
- name: Invoke workflow with inputs
104125
uses: aurelien-baudet/workflow-dispatch@v2
@@ -108,6 +129,8 @@ _This action is a fork of `benc-uk/workflow-dispatch` to add support for waiting
108129
inputs: '{ "message": "blah blah", "debug": true }'
109130
```
110131
132+
### Invoke workflow in another repo with inputs
133+
111134
```yaml
112135
- name: Invoke workflow in another repo with inputs
113136
uses: aurelien-baudet/workflow-dispatch@v2
@@ -118,6 +141,8 @@ _This action is a fork of `benc-uk/workflow-dispatch` to add support for waiting
118141
inputs: '{ "message": "blah blah", "debug": true }'
119142
```
120143
144+
### Invoke workflow and handle result
145+
121146
```yaml
122147
- name: Invoke workflow and handle result
123148
id: trigger-step
@@ -130,6 +155,38 @@ _This action is a fork of `benc-uk/workflow-dispatch` to add support for waiting
130155
run: echo "Another Workflow conclusion: ${{ steps.trigger-step.outputs.workflow-conclusion }}"
131156
```
132157
158+
### Invoke workflow with a unique run name (since 3.0.0)
159+
160+
```yaml
161+
- name: Invoke workflow and handle result
162+
id: trigger-step
163+
uses: aurelien-baudet/workflow-dispatch@v3
164+
env:
165+
RUN_NAME: ${{ github.repository }}/actions/runs/${{ github.run_id }}
166+
with:
167+
run-name: ${{ env.RUN_NAME }}
168+
workflow: Another Workflow
169+
token: ${{ secrets.PERSONAL_TOKEN }}
170+
inputs: >-
171+
{
172+
"run-name": "${{ env.RUN_NAME }}"
173+
}
174+
```
175+
176+
:warning: In you remote workflow, you will need to forward and use the `run-name` input (See [GitHub Action run-name](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#run-name))
177+
178+
```yaml
179+
name: Another Workflow
180+
run-name: ${{ inputs.run-name }}
181+
182+
on:
183+
workflow_dispatch:
184+
inputs:
185+
run-name:
186+
description: 'The distinct run name used to retrieve the run ID. Defaults to the workflow name'
187+
type: string
188+
required: false
189+
```
133190

134191
## Contributions
135192

@@ -139,4 +196,4 @@ Thanks to:
139196
* [rui-ferreira](https://github.com/rui-ferreira)
140197
* [robbertvdg](https://github.com/robbertvdg)
141198
* [samit2040](https://github.com/samit2040)
142-
* [jonas-schievink](https://github.com/jonas-schievink)
199+
* [jonas-schievink](https://github.com/jonas-schievink)

dist/index.js

Lines changed: 27 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -10092,13 +10092,36 @@ class WorkflowHandler {
1009210092
return this.workflowRunId;
1009310093
}
1009410094
try {
10095-
core.debug('Get workflow run id');
10095+
const workflowId = yield this.getWorkflowId();
10096+
const response = yield this.octokit.rest.actions.listWorkflowRuns({
10097+
owner: this.owner,
10098+
repo: this.repo,
10099+
workflow_id: workflowId,
10100+
event: 'workflow_dispatch',
10101+
branch: this.ref,
10102+
created: `>=${new Date(this.triggerDate).toISOString()}`
10103+
});
10104+
(0, debug_1.debug)('List Workflow Runs', response);
10105+
let runs = response.data.workflow_runs;
1009610106
if (this.runName) {
10097-
this.workflowRunId = yield this.findWorklowRunIdFromRunName(this.runName);
10107+
runs = response.data.workflow_runs
10108+
.filter((r) => r.name == this.runName);
1009810109
}
10099-
else {
10100-
this.workflowRunId = yield this.findWorkflowRunIdFromFirstRunOfSameWorkflowId();
10110+
if (runs.length == 0) {
10111+
throw new Error('Run not found');
10112+
}
10113+
if (runs.length > 1) {
10114+
core.warning(`Found ${runs.length} runs. Using the last one.`);
10115+
(0, debug_1.debug)(`Filtered Workflow Runs (after trigger date: ${new Date(this.triggerDate).toISOString()})`, runs.map((r) => ({
10116+
id: r.id,
10117+
name: r.name,
10118+
created_at: r.created_at,
10119+
triggerDate: new Date(this.triggerDate).toISOString(),
10120+
created_at_ts: new Date(r.created_at).valueOf(),
10121+
triggerDateTs: this.triggerDate
10122+
})));
1010110123
}
10124+
this.workflowRunId = runs[0].id;
1010210125
return this.workflowRunId;
1010310126
}
1010410127
catch (error) {
@@ -10107,47 +10130,6 @@ class WorkflowHandler {
1010710130
}
1010810131
});
1010910132
}
10110-
findWorkflowRunIdFromFirstRunOfSameWorkflowId() {
10111-
return __awaiter(this, void 0, void 0, function* () {
10112-
const workflowId = yield this.getWorkflowId();
10113-
const response = yield this.octokit.rest.actions.listWorkflowRuns({
10114-
owner: this.owner,
10115-
repo: this.repo,
10116-
workflow_id: workflowId,
10117-
event: 'workflow_dispatch'
10118-
});
10119-
(0, debug_1.debug)('List Workflow Runs', response);
10120-
const runs = response.data.workflow_runs
10121-
.filter((r) => new Date(r.created_at).setMilliseconds(0) >= this.triggerDate);
10122-
(0, debug_1.debug)(`Filtered Workflow Runs (after trigger date: ${new Date(this.triggerDate).toISOString()})`, runs.map((r) => ({
10123-
id: r.id,
10124-
name: r.name,
10125-
created_at: r.creatd_at,
10126-
triggerDate: new Date(this.triggerDate).toISOString(),
10127-
created_at_ts: new Date(r.created_at).valueOf(),
10128-
triggerDateTs: this.triggerDate
10129-
})));
10130-
if (runs.length == 0) {
10131-
throw new Error('Run not found');
10132-
}
10133-
return runs[0].id;
10134-
});
10135-
}
10136-
findWorklowRunIdFromRunName(runName) {
10137-
return __awaiter(this, void 0, void 0, function* () {
10138-
const result = yield this.octokit.rest.checks.listForRef({
10139-
check_name: runName,
10140-
owner: this.owner,
10141-
repo: this.repo,
10142-
ref: this.ref,
10143-
filter: 'latest'
10144-
});
10145-
if (result.length == 0) {
10146-
throw new Error('Run not found');
10147-
}
10148-
return result.check_runs[0].id;
10149-
});
10150-
}
1015110133
getWorkflowId() {
1015210134
return __awaiter(this, void 0, void 0, function* () {
1015310135
if (this.workflowId) {

src/workflow-handler.ts

Lines changed: 37 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ const ofConclusion = (conclusion: string | null): WorkflowRunConclusion => {
3636
}
3737

3838
export interface WorkflowRunResult {
39-
url: string,
40-
status: WorkflowRunStatus,
39+
url: string,
40+
status: WorkflowRunStatus,
4141
conclusion: WorkflowRunConclusion
4242
}
4343

@@ -127,64 +127,48 @@ export class WorkflowHandler {
127127
return this.workflowRunId;
128128
}
129129
try {
130-
core.debug('Get workflow run id');
130+
const workflowId = await this.getWorkflowId();
131+
132+
const response = await this.octokit.rest.actions.listWorkflowRuns({
133+
owner: this.owner,
134+
repo: this.repo,
135+
workflow_id: workflowId,
136+
event: 'workflow_dispatch',
137+
branch: this.ref,
138+
created: `>=${new Date(this.triggerDate).toISOString()}`
139+
});
140+
141+
debug('List Workflow Runs', response);
142+
143+
let runs = response.data.workflow_runs;
131144
if (this.runName) {
132-
this.workflowRunId = await this.findWorklowRunIdFromRunName(this.runName);
133-
} else {
134-
this.workflowRunId = await this.findWorkflowRunIdFromFirstRunOfSameWorkflowId();
145+
runs = response.data.workflow_runs
146+
.filter((r: any) => r.name == this.runName)
147+
}
148+
149+
if (runs.length == 0) {
150+
throw new Error('Run not found');
151+
}
152+
153+
if (runs.length > 1) {
154+
core.warning(`Found ${runs.length} runs. Using the last one.`);
155+
debug(`Filtered Workflow Runs (after trigger date: ${new Date(this.triggerDate).toISOString()})`, runs.map((r: any) => ({
156+
id: r.id,
157+
name: r.name,
158+
created_at: r.created_at,
159+
triggerDate: new Date(this.triggerDate).toISOString(),
160+
created_at_ts: new Date(r.created_at).valueOf(),
161+
triggerDateTs: this.triggerDate
162+
})));
135163
}
136164

165+
this.workflowRunId = runs[0].id as number;
166+
137167
return this.workflowRunId;
138168
} catch (error) {
139169
debug('Get workflow run id error', error);
140170
throw error;
141171
}
142-
143-
}
144-
145-
private async findWorkflowRunIdFromFirstRunOfSameWorkflowId(): Promise<number> {
146-
const workflowId = await this.getWorkflowId();
147-
148-
const response = await this.octokit.rest.actions.listWorkflowRuns({
149-
owner: this.owner,
150-
repo: this.repo,
151-
workflow_id: workflowId,
152-
event: 'workflow_dispatch'
153-
});
154-
155-
debug('List Workflow Runs', response);
156-
const runs = response.data.workflow_runs
157-
.filter((r: any) => new Date(r.created_at).setMilliseconds(0) >= this.triggerDate);
158-
debug(`Filtered Workflow Runs (after trigger date: ${new Date(this.triggerDate).toISOString()})`, runs.map((r: any) => ({
159-
id: r.id,
160-
name: r.name,
161-
created_at: r.creatd_at,
162-
triggerDate: new Date(this.triggerDate).toISOString(),
163-
created_at_ts: new Date(r.created_at).valueOf(),
164-
triggerDateTs: this.triggerDate
165-
})));
166-
167-
if (runs.length == 0) {
168-
throw new Error('Run not found');
169-
}
170-
171-
return runs[0].id as number;
172-
}
173-
174-
private async findWorklowRunIdFromRunName(runName: string): Promise<number> {
175-
const result = await this.octokit.rest.checks.listForRef({
176-
check_name: runName,
177-
owner: this.owner,
178-
repo: this.repo,
179-
ref: this.ref,
180-
filter: 'latest'
181-
});
182-
183-
if (result.length == 0) {
184-
throw new Error('Run not found');
185-
}
186-
187-
return result.check_runs[0].id as number;
188172
}
189173

190174
private async getWorkflowId(): Promise<number | string> {
@@ -198,7 +182,7 @@ export class WorkflowHandler {
198182
}
199183
try {
200184
const workflowsResp = await this.octokit.rest.actions.listRepoWorkflows({
201-
owner: this.owner,
185+
owner: this.owner,
202186
repo: this.repo
203187
});
204188
const workflows = workflowsResp.data.workflows;

0 commit comments

Comments
 (0)