Await the completion of a foreign repository Workflow Run given the Run ID.
This Action exists as a workaround for the issue where you cannot await the completion of a dispatched action.
This action requires being able to get the run ID from a dispatched action, see Getting the Run ID.
Should a remote workflow run fail, this action will attempt to output which step failed, with a link to the workflow run itself.
Dispatching a run and identifying the run it created are separate problems. Either of these solves the latter:
| Source | Yields |
|---|---|
gh workflow run |
The run URL on stdout, the ID being its last path segment |
return-dispatch |
run_id and run_url step outputs |
Taking the ID from the gh CLI (>=2.87.0) looks like this:
- name: Dispatch an action and get the run ID
id: dispatch
env:
GH_TOKEN: ${{ secrets.TOKEN }}
run: |
run_url=$(gh workflow run automation-test.yml --repo repository-owner/repository-name --ref target_branch)
if [ -z "$run_url" ]; then
echo "Dispatch returned no run details"
exit 1
fi
echo "run_id=${run_url##*/}" >> "$GITHUB_OUTPUT"With the run ID in hand, include await-remote-run as described below.
steps:
- name: Dispatch an action and get the run ID
uses: codex-/return-dispatch@v4
id: return_dispatch
with:
token: ${{ secrets.TOKEN }} # Note this is NOT GITHUB_TOKEN but a PAT
ref: target_branch # or refs/heads/target_branch
repo: repository-name
owner: repository-owner
workflow: automation-test.yml
- name: Await Run ID ${{ steps.return_dispatch.outputs.run_id }}
uses: Codex-/await-remote-run@v3
with:
token: ${{ github.token }}
repo: repository-name
owner: repository-owner
run_id: ${{ steps.return_dispatch.outputs.run_id }}
run_timeout_seconds: 300 # Optional
cancel_timeout_seconds: 240 # Optional
poll_interval_ms: 5000 # OptionalSet jobs to await named jobs within the run rather than the run itself, one name per
line. This suits a remote run whose later jobs you don't need to gate on, such as
awaiting build while its deploy continues.
- name: Await the remote build
uses: Codex-/await-remote-run@v3
with:
token: ${{ github.token }}
repo: repository-name
owner: repository-owner
run_id: ${{ steps.return_dispatch.outputs.run_id }}
jobs: |
buildThe action resolves once every listed job has concluded with success, leaving the rest
of the run in flight. Any other conclusion, skipped included, fails the action
immediately without awaiting the remaining jobs. With cancel_timeout_seconds set, this
failure also requests cancellation of the run, which can no longer succeed. A run whose
awaited jobs all succeeded is never cancelled.
Names must match the name GitHub reports, which is not always the workflow's job key:
| Remote workflow | Name to use |
|---|---|
build: with a name: set |
the name: value |
build: using strategy.matrix |
build (ubuntu-latest, 20) |
build: calling a reusable workflow |
build / inner-job-name |
The list is split on newlines only, as a matrix job carries commas in its name.
Jobs appear as they become eligible, so one still blocked on needs is absent rather
than pending. The action keeps awaiting a name it cannot yet see, failing only once the
run concludes without it. That failure lists every job the run did produce, which is the
quickest way to spot a name that never matched.
Giving up on a remote run leaves it running, which is a problem if your workflow tears down something that run depends on, such as a test environment.
Set cancel_timeout_seconds to request cancellation once that much time has elapsed. It must be less than run_timeout_seconds, the difference being how long this action keeps polling to observe the resulting cancelled conclusion. Cancellation is asynchronous, so the remote run may take some time to wind down.
- name: Await Run ID ${{ steps.return_dispatch.outputs.run_id }}
uses: Codex-/await-remote-run@v3
with:
token: ${{ secrets.TOKEN }} # Cancelling is a write, so this cannot be GITHUB_TOKEN
repo: repository-name
owner: repository-owner
run_id: ${{ steps.return_dispatch.outputs.run_id }}
run_timeout_seconds: 300
cancel_timeout_seconds: 240Awaiting a run only reads it, so GITHUB_TOKEN is enough for a public remote repository. A private one needs a Personal Access Token (PAT), as GITHUB_TOKEN can only access the repository containing the workflow.
Cancelling a run is a write, and GITHUB_TOKEN cannot be granted Actions write on another repository, so cancel_timeout_seconds always needs a PAT.
One of the following, depending on the token type:
- Fine-grained PAT, GitHub App, or
GITHUB_TOKEN:Actionsrepository permission, read- write is additionally required when using
cancel_timeout_seconds
- write is additionally required when using
- Classic PAT or OAuth token:
reposcoperepo:public_repomay be enough for a public repository
For the sake of transparency please note that this action uses the following API calls:
- Get a workflow run
- GET
/repos/{owner}/{repo}/actions/runs/{run_id} Actions: read
- GET
- List jobs for a workflow run
- GET
/repos/{owner}/{repo}/actions/runs/{run_id}/jobs Actions: read
- GET
- Cancel a workflow run, only if using
cancel_timeout_seconds- POST
/repos/{owner}/{repo}/actions/runs/{run_id}/cancel Actions: write
- POST
For more information please see api.ts.
If you want to use the result of a Workflow Run from a remote repository to complete a check locally, i.e. you have automated tests on another repository and don't want the local checks to pass if the remote fails.