| .forgejo/workflows | ||
| tests | ||
| .editorconfig | ||
| .gitignore | ||
| action.yml | ||
| cascading-pr-lib.sh | ||
| cascading-pr.sh | ||
| forgejo-curl.sh | ||
| LICENSE | ||
| README.md | ||
| renovate.json | ||
Create and synchronize a PR in a dependent repository
Description
If repository A depends on repository B, cascadinging-pr can be used
by a workflow in repository B to trigger the CI on repository A and
verify it passes when using a modified version of repository B. This
modified version could be a pull request, a branch or a reference.
In the simplest case cascading-pr runs a workflow in destination-repo
that uses origin-ref and blocks until it completes.
As an example, when a tag is set in Forgejo and builds a new release,
it is concluded by a call to cascading-pr that runs
end-to-end tests on
the newly built release to verify it works as expected.
When used in a workflow triggered by a PR event in origin-repo,
cascading-pr will create, update and close a matching PR in the
destination-repo. When the PR is updated, cascading-pr will
update the matching PR. It waits for the workflow triggered by these
updates in destination-repo to complete. If fails, cascading-pr,
also fails.
As an example, when a PR is created in
forgejo/runner, a
matching PR is created in
actions/setup-forgejo
with the proposed change and cascading-pr waits until the CI in
actions/setup-forgejo is successful.
The update script is expected to be found in origin-repo and is
given the following arguments:
- A directory path in which the
destination-branchofdestination-repo(or a fork) is checked-out. - The path to a JSON file describing the pull request in
destination-repo. - A directory path in which the head of
origin-repois checked-out at:- if
origin-pris specified, the head branch oforigin-pr - otherwise
origin-ref
- if
- Information about the
origin-repo- if
origin-pris specified, the path to a JSON file desccribing the pull request inorigin-repo - otherwise
origin-ref
- if
If changes are found in the destination repository directory after
the update script runs, they will be pushed as a new commit in the
PR in the destination-repo.
origin-token is used when accessing origin-repo and needs the
read:user, read:repository and write:issue scopes.
destination-token is used to push the branch that contains an
update to destination-repo (or destination-fork-repo) and open a
pull request. It needs the read:user, write:repository and
write:issue scopes.
It is recommended that a dedicated user is used to create
destination-token and that destination-fork-repo is always used
unless the users who are able to create pull requests are trusted.
When the PR in the destination-repo is from a forked repository,
the update script is run from the default branch of
destination-repo instead of the head of the PR which is a branch
in destination-fork-repo. The PR author must not be trusted and it
is imperative that the update script never runs anything found in
the head branch of the PR.
If the fork of the destination repository is specified and it does not exist, it is created.
Inputs
| parameter | description | required | default |
|---|---|---|---|
| origin-url | URL of the Forgejo instance where the PR that triggers the action is located (e.g. https://code.forgejo.org) | true |
|
| origin-repo | the repository in which the PR was created | true |
|
| origin-token | a token with write permission on origin-repo | true |
|
| origin-pr | number of the PR in {orign-repo}, mutually exclusive with {origin-ref} | false |
|
| origin-ref | reference in {orign-repo}, mutually exclusive with {origin-pr} | false |
|
| destination-url | URL of the Forgejo instance where the cascading PR is created or updated (e.g. https://code.forgejo.org) | true |
|
| destination-repo | the repository in which the cascading PR is created or updated | true |
|
| destination-fork-repo | the fork of {destination-repo} in which the {destination-branch} will be created or updated | false |
|
| destination-branch | the base branch of the destination repository for the cascading PR | true |
|
| destination-token | a token with write permission on destination-repo | true |
|
| update | path to the script to update the content of the cascading PR | true |
|
| wait-iteration | number of seconds to wait before verifying for the status of the destination pull request (timeout after 100 iterations) | true |
36 |
| prefix | prefix of the branch from which the cascading PR is created on {destination-repo} or {destination-fork-repo} (default to {origin-repo}) | false |
|
| close | if true the cascading PR will be closed and the branch deleted when (i) the {origin-pr} is merged or (ii) when the cascading PR status is success if {origin-ref} is set | false |
false |
| verbose | if true print verbose information | false |
false |
| debug | if true print debug information | false |
false |
Forgejo dependencies
The Forgejo repositories that depend on each other are
linked with workflows using cascading-pr as follows.
flowchart TD
lxc-helper(lxc-helper) --> runner(runner)
runner --> setup-forgejo(setup-forgejo)
setup-forgejo --> e2e(end-to-end)
forgejo-curl(forgejo-curl.sh) --> setup-forgejo
forgejo(forgejo) --> e2e
click lxc-helper "https://code.forgejo.org/forgejo/lxc-helpers/src/branch/main/.forgejo/workflows/cascade-runner.yml"
click runner "https://code.forgejo.org/forgejo/runner/src/branch/main/.forgejo/workflows/cascade-setup-forgejo.yml"
click setup-forgejo "https://code.forgejo.org/actions/setup-forgejo/src/branch/main/.forgejo/workflows/cascade-end-to-end.yml"
click e2e "https://code.forgejo.org/actions/end-to-end"
click forgejo-curl "https://code.forgejo.org/forgejo/forgejo-curl/src/branch/main/.forgejo/workflows/cascade-setup-forgejo.yml"
click forgejo "https://codeberg.org/forgejo/forgejo/src/branch/forgejo/.forgejo/workflows/cascade-setup-end-to-end.yml"
Example workflow
on:
pull_request:
types:
- opened
- synchronize
- closed
jobs:
test:
runs-on: docker
steps:
- uses: actions/checkout@v4
- uses: actions/cascading-pr@v1
with:
origin-url: https://code.forgejo.org
origin-repo: forgejo/lxc-helpers
origin-token: ${{ secrets.ORIGIN_TOKEN }}
origin-pr: ${{ github.event.pull_request.number }}
destination-url: https://code.forgejo.org
destination-repo: forgejo/act
destination-branch: main
destination-token: ${{ secrets.DESTINATION_TOKEN }}
update: ./upgrade-lxc-helpers
Pull requests from forked repositories
When cascading-pr runs as a consequence of pull request from a
forked repository, the workflow must be triggered by a pull_request_target
event otherwise it will not have access to secrets.
Prevent privilege escalation
When cascading-pr runs as a consequence of a pull request from a
repository forked from orgin-repo, it should create a pull request
from a forked repository of destination-repo by specifying the
destination-fork-repo.
If the destination-fork-repo repository does not exist, it will be
created as a fork of the destination-repo repository, using
destination-token.
Hacking
The test environment consists of the following (all users password is admin1234)
- A forgejo instance with a runner
- An unprivileged user user1
- The repository user1/originrepo
- contains a pull_request workflow using cascading-pr that targets user2/destinationrepo
- contains a script that will modify user2/destinationrepo
- a branch1 at the same commit as main
- The repository user1/cascading-pr with the action under test
- An unprivileged user user2
- The repository user2/destinationrepo
git clone https://code.forgejo.org/actions/setup-forgejo
export PATH=$(pwd)/setup-forgejo:$PATH
git clone https://code.forgejo.org/actions/cascading-pr
export PATH=$(pwd)/cascading-pr:$PATH
cd cascading-pr
export DIR=/tmp/forgejo-for-cascading-pr
forgejo-curl.sh logout
forgejo-runner.sh teardown
forgejo-binary.sh teardown
forgejo-binary.sh setup root admin1234 https://codeberg.org/forgejo/forgejo/releases/download/v11.0.3/forgejo-11.0.3-linux-amd64
FORGEJO_RUNNER_CONFIG=$(pwd)/tests/runner-config.yaml forgejo-runner.sh setup
url=$(cat $DIR/forgejo-url)
firefox $url
The test for a successful run of the cascading-pr action consists of:
- creating a PR from branch1 to main
- wait for the commit status until it is successful
testing an update on the action
- run
tests/run.sh --debugonce so all is in place - commit changes to the files that are in the cascading-pr action (action.yml, cascading-pr.sh etc.)
- push the modified action to
user1/cascading-pr - visit $url/user1/originrepo/actions/runs/1 and click re-run
interactive debugging
Following the steps below recreate the same environment as the integration workflow locally. It is helpful for forensic analysis when something does not run as expected and the errors displayed are unclear.
To help with the development loop all steps are idempotent and
running tests/run.sh --debug multiple times must succeed.
Individual steps can be run independendely by using the name of the function. For instance:
tests/run.sh --debug create_pull_requestwill only call thecreate_pull_requestfunction found intests/run.shto (re)create the pull request inuser1/originrepo../cascading-pr.sh --debug --origin-url ... upsert_branchwill only call theupsert_branchfunction found incascading-pr.sh.
logging
If --debug is used a full debug log is displayed, very complete and
very verbose. Otherwise it is stashed in a temporary file and only
displayed if an error happens.
If all goes well, the runner logs are not displayed even with --debug. They
can be looked at in the web UI.
directories
The tests/run.sh script stores all its files in
/tmp/cascading-pr-test. The temporary directories created by
cascading-pr.sh are disposed of when the script ends.
snippets for copy/pasting
tests/run.sh --debug
tests/run.sh --debug no_change_no_cascade_pr
./cascading-pr.sh --debug --origin-url "$url" --origin-repo "user1/originrepo" --origin-token "$(cat /tmp/cascading-pr-test/user1/repo-token)" --origin-pr 1 --destination-url "$url" --destination-repo "user2/destinationrepo" --destination-token "$(cat /tmp/cascading-pr-test/user2/repo-token)" --destination-branch "main" --update "upgraded" run
Update the README
With https://github.com/npalm/action-docs action-docs --update-readme