2023-10-11 18:09:39 +02:00
Create and synchronize a PR in a dependent repository
2023-10-11 15:39:52 +02:00
2023-10-13 23:38:57 +02:00
<!-- action - docs - description -->
## Description
2024-01-02 18:39:58 +01:00
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 ](https://code.forgejo.org/forgejo/end-to-end/ ) tests on
the newly built release to verify it works as expected.
2023-11-01 21:33:35 +01:00
When used in a workflow triggered by a PR event in `origin-repo` ,
2024-01-02 18:39:58 +01:00
`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.
2023-10-13 23:38:57 +02:00
As an example, when a PR is created in
[`forgejo/runner` ](https://code.forgejo.org/forgejo/runner/ ), a
matching PR is created in
[`actions/setup-forgejo` ](https://code.forgejo.org/actions/setup-forgejo/ )
2024-01-02 18:39:58 +01:00
with the proposed change and `cascading-pr` waits until the CI in
2023-11-01 21:33:35 +01:00
`actions/setup-forgejo` is successful.
2023-10-13 23:38:57 +02:00
2024-01-02 18:39:58 +01:00
The `update` script is expected to be found in `origin-repo` and is
given the following arguments:
2023-10-13 23:38:57 +02:00
2024-01-02 18:39:58 +01:00
* A directory path in which the `destination-branch` of `destination-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-repo` is checked-out at:
* if `origin-pr` is specified, the head branch of `origin-pr`
* otherwise `origin-ref`
* Information about the `origin-repo`
* if `origin-pr` is specified, the path to a JSON file desccribing
the pull request in `origin-repo`
* otherwise `origin-ref`
2023-10-13 23:38:57 +02:00
2024-01-02 18:39:58 +01:00
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` .
2023-10-28 17:40:09 +02:00
2023-11-01 21:33:35 +01:00
`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
2024-01-02 18:39:58 +01:00
update to `destination-repo` (or `destination-fork-repo` ) and open a
pull request. It needs the `read:user` , `write:repository` and
`write:issue` scopes.
2023-11-01 21:33:35 +01:00
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.
2024-01-02 18:39:58 +01:00
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.
2023-11-01 17:47:42 +01:00
If the fork of the destination repository is specified and it does
not exist, it is created.
2023-10-13 23:38:57 +02:00
<!-- action - docs - description -->
<!-- action - docs - inputs -->
## 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` | |
2024-01-02 18:39:58 +01:00
| 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` | |
2023-10-13 23:38:57 +02:00
| 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` | |
2023-11-01 18:40:23 +01:00
| destination-fork-repo | the fork of {destination-repo} in which the {destination-branch} will be created or updated | `false` | |
2023-10-13 23:38:57 +02:00
| 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` | |
2024-01-09 14:49:09 +01:00
| prefix | prefix of the branch from which the cascading PR is created on {destination-repo} or {destination-fork-repo} (default to {origin-repo}) | `false` | |
2024-01-09 19:47:48 +01:00
| close | if true the cascading PR will be closed and the branch deleted when the PR is merged | `false` | false |
2023-10-13 23:38:57 +02:00
| verbose | if true print verbose information | `false` | false |
| debug | if true print debug information | `false` | false |
<!-- action - docs - inputs -->
2023-11-05 00:02:27 +01:00
# Forgejo dependencies
The [Forgejo ](https://codeberg.org/forgejo/forgejo/ ) repositories that depend on each other are
linked with workflows using `cascading-pr` as follows.
```mermaid
flowchart TD
lxc-helper(lxc-helper) --> act(act)
runner --> setup-forgejo(setup-forgejo)
setup-forgejo --> e2e(end-to-end)
forgejo-curl(forgejo-curl.sh) --> setup-forgejo
forgejo(forgejo) --> e2e
2025-07-28 20:33:15 +02:00
click lxc-helper "https://code.forgejo.org/forgejo/lxc-helpers/src/branch/main/.forgejo/workflows/cascade-runner.yml"
2023-11-05 00:02:27 +01:00
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
2023-10-13 23:38:57 +02:00
```yaml
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
2023-11-05 00:02:27 +01:00
destination-repo: forgejo/act
2023-10-13 23:38:57 +02:00
destination-branch: main
destination-token: ${{ secrets.DESTINATION_TOKEN }}
update: ./upgrade-lxc-helpers
```
2023-11-01 17:06:59 +01:00
# 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` .
2023-10-11 15:39:52 +02:00
# Hacking
2023-10-13 15:52:40 +02:00
The test environment consists of the following (all users password is admin1234)
2023-10-13 14:54:56 +02:00
* 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
2023-10-13 15:23:50 +02:00
* a branch1 at the same commit as main
2023-10-13 14:54:56 +02:00
* The repository user1/cascading-pr with the action under test
* An unprivileged user user2
* The repository user2/destinationrepo
2023-10-22 17:25:03 +02:00
```sh
git clone https://code.forgejo.org/actions/setup-forgejo
export PATH=$(pwd)/setup-forgejo:$PATH
git clone https://code.forgejo.org/actions/cascading-pr
2025-07-20 10:02:23 +02:00
export PATH=$(pwd)/cascading-pr:$PATH
2023-10-22 17:25:03 +02:00
cd cascading-pr
2024-01-02 18:39:58 +01:00
export DIR=/tmp/forgejo-for-cascading-pr
2023-10-22 17:25:03 +02:00
forgejo-curl.sh logout
forgejo-runner.sh teardown
2024-01-02 18:39:58 +01:00
forgejo-binary.sh teardown
2025-07-20 10:02:23 +02:00
forgejo-binary.sh setup root admin1234 https://codeberg.org/forgejo/forgejo/releases/download/v11.0.3/forgejo-11.0.3-linux-amd64
2023-10-22 17:25:03 +02:00
FORGEJO_RUNNER_CONFIG=$(pwd)/tests/runner-config.yaml forgejo-runner.sh setup
2024-01-02 18:39:58 +01:00
url=$(cat $DIR/forgejo-url)
2023-10-22 17:25:03 +02:00
firefox $url
```
2023-10-13 15:23:50 +02:00
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
2023-10-13 14:54:56 +02:00
## testing an update on the action
* run `tests/run.sh --debug` once 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
2025-07-20 10:02:23 +02:00
something does not run as expected and the errors displayed are unclear.
2023-10-13 14:54:56 +02:00
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_request` will only call the `create_pull_request`
function found in `tests/run.sh` to (re)create the pull request in `user1/originrepo` .
* `./cascading-pr.sh --debug --origin-url ... upsert_branch` will only call the `upsert_branch`
function found in `cascading-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.
2024-01-09 19:40:09 +01:00
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.
2023-10-13 14:54:56 +02:00
## snippets for copy/pasting
2023-10-11 15:39:52 +02:00
```sh
2023-10-11 16:25:56 +02:00
tests/run.sh --debug
2023-10-22 18:26:56 +02:00
tests/run.sh --debug no_change_no_cascade_pr
2023-10-13 14:54:56 +02:00
./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
2023-10-11 15:39:52 +02:00
```
2023-10-13 23:38:57 +02:00
## Update the README
With https://github.com/npalm/action-docs `action-docs --update-readme`