diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..6b8710a7 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +.git diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..669640db --- /dev/null +++ b/.editorconfig @@ -0,0 +1,10 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +tab_width = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.forgejo/prepare-end-to-end/action.yml b/.forgejo/prepare-end-to-end/action.yml new file mode 100644 index 00000000..8ae5cdd8 --- /dev/null +++ b/.forgejo/prepare-end-to-end/action.yml @@ -0,0 +1,41 @@ +inputs: + built: + description: 'True if a source build is available, false otherwise' + +runs: + using: "composite" + steps: + - name: cache S3 binaries + id: S3 + uses: https://data.forgejo.org/actions/cache@v4 + with: + path: | + /usr/local/bin/minio + /usr/local/bin/mc + /usr/local/bin/garage + key: S3 + + - uses: https://data.forgejo.org/actions/setup-forgejo@v3.1.6 + with: + install-only: true + - run: forgejo-binary.sh ensure_user forgejo + - name: inputs context dump for debug + run: | + set -x + cat <> $GITHUB_OUTPUT - - - name: update documentation - if: matrix.info.tests != 'none' && github.ref == 'refs/heads/main' - uses: https://code.forgejo.org/actions/cascading-pr@v1 - with: - origin-url: ${{ env.GITHUB_SERVER_URL }} - origin-repo: ${{ github.repository }} - origin-token: ${{ secrets.CASCADE_DOCS_ORIGIN_TOKEN }} - origin-ref: refs/heads/main - destination-url: https://codeberg.org - destination-fork-repo: ${{ vars.CASCADE_DOCS_DESTINATION_DOER }}/docs - destination-repo: forgejo/docs - destination-branch: ${{ matrix.info.branch || matrix.info.version }} - destination-token: ${{ secrets.CASCADE_DOCS_DESTINATION_TOKEN }} - prefix: ${{ env.GITHUB_REPOSITORY }}-${{ matrix.info.version }} - update: .forgejo/cascading-docs - env: - FORCE_VERSION: "${{ vars.CASCADE_DOCS_FORCE_VERSION }}" - VERSION: "${{ steps.run.outputs.full_version }}" diff --git a/.forgejo/workflows/end-to-end.yml b/.forgejo/workflows/end-to-end.yml new file mode 100644 index 00000000..eab71f76 --- /dev/null +++ b/.forgejo/workflows/end-to-end.yml @@ -0,0 +1,166 @@ +# +# +# https://code.forgejo.org/forgejo/end-to-end/settings/actions +# + +on: + pull_request: + push: + branches: + - 'main' + +enable-email-notifications: true + +jobs: + build: + runs-on: docker + container: + image: 'data.forgejo.org/oci/node:24-trixie' + outputs: + built: "${{ steps.build.outputs.built }}" + forgejo_versions_json: "${{ steps.build.outputs.forgejo_versions_json }}" + steps: + - uses: https://data.forgejo.org/actions/checkout@v4 + - uses: https://data.forgejo.org/actions/setup-go@v5 + with: + go-version: "1.25" + - name: lib/build.sh + id: build + run: | + mkdir $d /tmp/forgejo-upload + touch /tmp/forgejo-upload/PLACEHOLDER + + if ! test -f forgejo/build-from-sources; then + echo forgejo/build-from-sources is not present, do not build any version from source + source lib/lib.sh + echo "forgejo_versions_json=$(node -p "JSON.stringify(process.argv[1].split(' '))" "$RELEASE_NUMBERS")" >> $FORGEJO_OUTPUT + echo "built=no" >> $FORGEJO_OUTPUT + exit 0 + fi + + set -x + # + # SQLite needs gcc to be compiled + # + export DEBIAN_FRONTEND=noninteractive + apt-get update -qq + apt-get -q install -y -qq build-essential + + d=/tmp/forgejo-binaries + + for version in $(cat forgejo/build-from-sources) ; do + lib/build.sh $version $d + forgejo=$d/forgejo-$version-dev + $forgejo --version + mv $forgejo /tmp/forgejo-upload/forgejo-$version + done + + echo "forgejo_versions_json=$(node -p "JSON.stringify(process.argv[1].split(' '))" "$(cat forgejo/build-from-sources)")" >> $FORGEJO_OUTPUT + echo "built=yes" >> $FORGEJO_OUTPUT + + - name: steps context dump for debug + run: | + set -x + cat < /etc/sudoers && \ + echo "forgejo-tests:10000:9999" > /etc/subuid && \ + echo "forgejo-tests:10000:9999" > /etc/subgid && \ + mkdir /srv/forgejo-binaries && \ + chown forgejo-tests:forgejo-tests /srv/forgejo-binaries && \ + apt-get clean && \ + apt-get autoremove --purge && \ + apt-get autoclean + +COPY --chown=1001:1001 . /e2e + +RUN git clone https://code.forgejo.org/actions/setup-forgejo.git /setup-forgejo + +USER forgejo-tests + +WORKDIR /e2e + +ENTRYPOINT /bin/bash diff --git a/README.md b/README.md index 9fefef93..33fcfdbd 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,36 @@ # Forgejo end-to-end tests +- [Forgejo end-to-end tests](#forgejo-end-to-end-tests) + - [Removing legacy tests](#removing-legacy-tests) + - [Hacking](#hacking) + - [Running from locally built binary](#running-from-locally-built-binary) + - [Forgejo](#forgejo) + - [Forgejo runner](#forgejo-runner) + - [Running from locally built container image](#running-from-locally-built-container-image) + - [Running actions tests locally](#running-actions-tests-locally) + - [Running federation tests locally](#running-federation-tests-locally) + - [Federated Mastodon Follow Test](#federated-mastodon-follow-test) + - [Running other tests locally](#running-other-tests-locally) + - [Running tests in Docker/Podman](#running-tests-in-dockerpodman) + A series of tests scenarios and assertions covering [Forgejo](https://codeberg.org/forgejo/forgejo) and the [Forgejo -runner](https://code.forgejo.org/forgejo/runner). They partially rely -on [Forgejo actions](https://code.forgejo.org/actions) developped -specifically for testing such as -[setup-forgejo](https://code.forgejo.org/actions/setup-forgejo). +runner](https://code.forgejo.org/forgejo/runner). They are designed to run using Forgejo releases and development versions compiled from designated repositories. -# Hacking +## Removing legacy tests + +End-to-end tests cover the supported range of releases and when one of +them is EOL, it must be removed as well as the tests that target it +specifically. Otherwise the test suite would grow indefinitely. + +When a release is EOL, a branch is cut with a name following the +pattern `legacy/vX.Y-vA.B`. For instance when `v8.0` is published and +`v1.21` is EOL, the branch `legacy/v8.0-v1.21` is cut. + +## Hacking docker and sudo must be installed with insecure registries allowed in /etc/docker/daemon.json for the IP that will be used for forgejo such @@ -18,111 +38,117 @@ as: ```json { - "insecure-registries": [ "10.80.4.76:3000" ] + "insecure-registries": [ "10.0.0.0/8" ] } -``` +``` Use setup-forgejo from source. The [setup-forgejo](https://code.forgejo.org/actions/setup-forgejo) repository is a [Forgejo -Action](https://forgejo.org/docs/v1.21/user/actions/) which is meant +Action](https://forgejo.org/docs/v7.0/user/actions/) which is meant to be used in workflows. However, it is implemented as shell scripts that can also be used to create Forgejo instances and runners locally. This is convenient for testing and the reason why it needs to be added to the PATH. -For instance, it is a dependency of the `actions/run.sh` script. +For instance, it is a dependency of the `end-to-end.sh` script. ```sh git clone https://code.forgejo.org/actions/setup-forgejo export PATH=$(pwd)/setup-forgejo:$PATH git clone https://code.forgejo.org/forgejo/end-to-end cd end-to-end -export DIR=/tmp/end-to-end -rm -fr /tmp/end-to-end ; sudo rm -fr /srv/example ; sudo mkdir /srv/example ; sudo chown -R $USER /srv/example ``` -Run using Forgejo built from source. +### Running from locally built binary + +Before injecting a manually built binary, make sure a simple test was +run so that the directories are populated. + +#### Forgejo + +From a checkout of https://codeberg.org/forgejo/forgejo/ ```sh -make TAGS='bindata sqlite sqlite_unlock_notify' generate forgejo -cp -a forgejo $DIR/forgejo +make clean-all && make frontend && make TAGS='bindata sqlite sqlite_unlock_notify' generate forgejo +cp -a forgejo /srv/forgejo-binaries/forgejo-11.0 ``` -## Running actions locally +It will be used whenever the version `11.0` is specified in a test. + +#### Forgejo runner + +From a checkout of https://code.forgejo.org/forgejo/runner + +```sh +make --always-make forgejo-runner +cp forgejo-runner /tmp/forgejo-end-to-end/forgejo-runner +``` + +### Running from locally built container image + +```bash +docker buildx build --output=type=docker --tag codeberg.org/forgejo/forgejo:latest . +``` + +## Running actions tests locally To run and debug workflows from `actions/example-*`, from the root of the source directory, with docker and forgejo-curl.sh installed, mimic -what `.forgejo/workflows/actions.yml` does. There may be some manual +what `.forgejo/workflows/end-to-end.yml` does. There may be some manual tweaking (such as creating temporary directories) because the tests run as root in the context of Forgejo Actions and assume they have admin permissions. But they do not need to run as root and must work fine when run as a regular user. -Run one example - ```sh -actions/run.sh https://codeberg.org/forgejo-experimental/forgejo/releases/download/v7.0.0-test/forgejo-7.0.0-test-linux-amd64 v7.0.0-test v7_0 cron # runs actions/example-cron +export FORGEJO_RUNNER_LOGS=/tmp/forgejo-end-to-end/forgejo-runner.log +./end-to-end.sh run dependencies +./end-to-end.sh actions_setup 10.0 +firefox 0.0.0.0:3000 # user root / admin1234 +./end-to-end.sh actions_verify_example echo +./end-to-end.sh actions_teardown ``` -Cleanup. It will teardown Forgejo & the runner and not run them because there is nothing to test. +Note that `with-docker-tcp` requires the docker daemon listens to +tcp://127.0.0.1:2375. See `actions/actions.sh` for how to do that. + +## Running federation tests locally + +To run and debug scenarios from `federation/*`, from the root of +the source directory, mimic what `.forgejo/workflows/end-to-end.yml` does. ```sh -actions/run.sh https://codeberg.org/forgejo-experimental/forgejo/releases/download/v7.0.0-test/forgejo-7.0.0-test-linux-amd64 v7.0.0-test v7_0 none +./end-to-end.sh run dependencies +./end-to-end.sh federation_setup 12.0 +firefox 0.0.0.0:3001 # user root / admin1234 +firefox 0.0.0.0:3002 # user root / admin1234 +firefox 0.0.0.0:3003 # user root / admin1234 +./end-to-end.sh federation_verify_scenario star +./end-to-end.sh federation_verify_scenario gotosocial +./end-to-end.sh federation_verify_scenario mastodon +./end-to-end.sh federation_teardown ``` -Run all examples for v7_0 +## Running other tests locally + +To run and debug tests, from the root of the source directory. + +Run one test. When the test fails the instance can be inspected at http://0.0.0.0:3000 ```sh -actions/run.sh https://codeberg.org/forgejo-experimental/forgejo/releases/download/v7.0.0-test/forgejo-7.0.0-test-linux-amd64 v7.0.0-test v7_0 +./end-to-end.sh test_packages_alpine +./end-to-end.sh test_storage_stable_s3 minio ``` -Run from sources +Cleanup. It will teardown the Forgejo instance. ```sh -make TAGS='bindata sqlite sqlite_unlock_notify' generate forgejo -cp -a forgejo $DIR/forgejo +./end-to-end.sh stop ``` -Remote testing +## Running tests in Docker/Podman -To reduce the runtime the following variables can be set to control -the number of cases run by the -[actions](.forgejo/workflows/actions.yml) tests. If set to -**none** they are not run at all for that version of Forgejo. If -it does not exist, all tests are run. - -* `v7_0_TESTS` -* `V1_21_TESTS` -* `V1_20_TESTS` - -## Running packages locally - -To run and debug package tests, from the root of the source directory. - -Run one test - -```sh -packages/run.sh https://codeberg.org/forgejo-experimental/forgejo/releases/download/v7.0.0-test/forgejo-7.0.0-test-linux-amd64 v7.0.0-test v7_0 alpine # runs packages/alpine.sh -``` - -Cleanup. It will teardown Forgejo and not run them because there is nothing to test. - -```sh -packages/run.sh https://codeberg.org/forgejo-experimental/forgejo/releases/download/v7.0.0-test/forgejo-7.0.0-test-linux-amd64 v7.0.0-test v7_0 none -``` -Run all examples for v7_0 - -```sh -packages/run.sh https://codeberg.org/forgejo-experimental/forgejo/releases/download/v7.0.0-test/forgejo-7.0.0-test-linux-amd64 v7.0.0-test v7_0 -``` - -Remote testing - -To reduce the runtime the following variables can be set to control -the number of cases run by the -[packages test](.forgejo/workflows/packages.yml) tests. If set to -**none** they are not run at all for that version of Forgejo. If -it does not exist, all tests are run. - -* `v7_0_PACKAGES_TESTS` -* `V1_21_PACKAGES_TESTS` +There is an included Dockerfile in which the tests can be run. Building the +conatiner will copy the the entire repo state into the container from which +changes to the tests can be tested. Note: running in podman requires the +`--privileged` flag because this will run podman in podman for some tests. diff --git a/actions/actions.sh b/actions/actions.sh new file mode 100755 index 00000000..0b200824 --- /dev/null +++ b/actions/actions.sh @@ -0,0 +1,189 @@ +# Copyright 2024 The Forgejo Authors +# SPDX-License-Identifier: MIT + +ACTIONS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +function actions_export_variables() { + export HOST_PORT + export url=http://${FORGEJO_USER}:${FORGEJO_PASSWORD}@${HOST_PORT} + export token=$(cat $DOT_FORGEJO_CURL/token) +} + +function actions_verify_feature() { + local feature=$1 + + actions_export_variables + + export FEATURE_DIR=$ACTIONS_DIR/feature-$feature + + echo "============================ RUN feature-$feature ===================" + bash -ex $FEATURE_DIR/run.sh || return 1 +} + +function actions_verify_example() { + local example=$1 + + actions_export_variables + actions_cleanup_example_volume + + export example + export EXAMPLE_DIR=$ACTIONS_DIR/example-$example + + if test -f $EXAMPLE_DIR/setup.sh; then + echo "============================ SETUP example-$example ===================" + bash -ex $EXAMPLE_DIR/setup.sh || return 1 + fi + + if test -f $EXAMPLE_DIR/run.sh; then + echo "============================ RUN example-$example ===================" + bash -ex $EXAMPLE_DIR/run.sh || return 1 + else + forgejo-test-helper.sh run_workflow actions/example-$example $url root example-$example $example $token || return 1 + fi + + if test -f $EXAMPLE_DIR/teardown.sh; then + echo "============================ TEARDOWN example-$example ===================" + bash -ex $EXAMPLE_DIR/teardown.sh || return 1 + fi + + actions_save_contexts $example +} + +function actions_save_contexts() { + local example="$1" + + if test -d /srv/example/$example/contexts; then + mkdir -p /srv/contexts + rsync -av /srv/example/$example/contexts/ /srv/contexts/$example/ + fi +} + +function actions_cleanup_example_volume() { + if test $(id -u) != 0; then + $SUDO chown $(id -u) /srv + fi + + if ! test -d /srv/example; then + mkdir -p /srv/example + return + fi + + $SUDO rm -fr /srv/example/* +} + +function actions_setup() { + local version=$1 + actions_teardown + + reset_forgejo $ACTIONS_DIR/default-app.ini + start_forgejo $version + + export FORGEJO_RUNNER_LOGS=$DIR/forgejo-runner.log + + actions_cleanup_example_volume + export FORGEJO_RUNNER_CONFIG=$ACTIONS_DIR/runner-config.yaml + forgejo-runner.sh setup '' '' http://${HOST_PORT} +} + +function actions_teardown() { + forgejo-curl.sh logout + forgejo-runner.sh teardown + stop_forgejo +} + +function actions_runner_version() { + local runner_version=$($DIR/forgejo-runner --version | sed -n -e 's/forgejo-runner version v//p') + if test -z "$runner_version"; then + $DIR/forgejo-runner --version + echo failed to parse version + false + fi + echo $runner_version +} + +function prepare_dockerd() { + mkdir -p /etc/systemd/system/docker.service.d + cat >/etc/systemd/system/docker.service.d/override.conf <<'EOF' +[Service] +ExecStart= +ExecStart=/usr/sbin/dockerd -H unix:///var/run/docker.sock -H tcp://127.0.0.1:2375 --containerd=/run/containerd/containerd.sock $DOCKER_OPTS +EOF + systemctl daemon-reload + if ! systemctl restart docker.service; then + journalctl --no-pager --unit docker.service + return 1 + fi + netstat -lntp | grep 127.0.0.1:2375 +} + +function test_actions() { + local versions="${1:-$RELEASE_NUMBERS}" + + for version in $versions; do + + actions_setup $version + local runner_version=$(actions_runner_version) + + log_info "Testing actions with Forgejo $version & Forgejo runner $runner_version" + + run actions_verify_example with-docker-tcp + if dpkg --compare-versions $runner_version gt 5.0.2; then + for example in with-docker-host with-docker-socket without-docker-socket; do + run actions_verify_example $example + done + fi + + if dpkg --compare-versions $runner_version gt 10.0.0; then + run actions_verify_example force-rebuild + fi + + if dpkg --compare-versions $version ge 7.0 && dpkg --compare-versions $runner_version gt 3.3.0; then + for example in artifacts-v4; do + run actions_verify_example $example + done + fi + + for example in echo matrix needs workflow-call lxc config-options cache cache-pull-request checkout service container expression local-action docker-action if if-fail push tag push-cancel artifacts pull-request context private-workflow-call create-runner-file; do + run actions_verify_example $example + done + + if dpkg --compare-versions $runner_version ge 6.3.0; then + run actions_verify_example cache-proxy + fi + + if dpkg --compare-versions $runner_version ge 8.0.0; then + run actions_verify_example shell + fi + + if dpkg --compare-versions $version lt 7.1; then + for example in cron; do + run actions_verify_example $example + done + fi + + if dpkg --compare-versions $version ge 7.1; then + for example in automerge post-7-0-schedule; do + run actions_verify_example $example + done + fi + + if dpkg --compare-versions $version ge 8.0; then + for example in workflow-dispatch; do + run actions_verify_example $example + done + fi + + if dpkg --compare-versions $version ge 9.0; then + run actions_verify_example schedule-noncancel + fi + + if dpkg --compare-versions $version ge 14.0; then + run actions_verify_example matrix-dynamic + fi + + if dpkg --compare-versions $version ge 15.0; then + run actions_verify_example workflow-call-expansion + run actions_verify_example id-tokens + fi + done +} diff --git a/forgejo/upgrades/relative-app.ini b/actions/default-app.ini similarity index 50% rename from forgejo/upgrades/relative-app.ini rename to actions/default-app.ini index d53c2917..455262fc 100644 --- a/forgejo/upgrades/relative-app.ini +++ b/actions/default-app.ini @@ -1,19 +1,24 @@ -RUN_MODE = prod -WORK_PATH = ${WORK_PATH} +RUN_MODE = dev +WORK_PATH = forgejo-work-path [server] APP_DATA_PATH = ${WORK_PATH}/data +DOMAIN = ${IP} HTTP_PORT = 3000 SSH_LISTEN_PORT = 2222 LFS_START_SERVER = true +[queue] +TYPE = immediate + [database] DB_TYPE = sqlite3 +PATH = ${WORK_PATH}/forgejo.db [log] MODE = file -LEVEL = debug -ROUTER = file +LEVEL = trace +logger.router.MODE = file [log.file] FILE_NAME = forgejo.log @@ -24,21 +29,7 @@ INSTALL_LOCK = true [repository] ENABLE_PUSH_CREATE_USER = true DEFAULT_PUSH_CREATE_PRIVATE = false +DEFAULT_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki,repo.projects,repo.packages,repo.actions -[attachment] -PATH = relative-attachments - -[lfs] -PATH = relative-lfs - -[avatar] -PATH = relative-avatars - -[repo-avatar] -PATH = relative-repo-avatars - -[repo-archive] -PATH = relative-repo-archive - -[packages] -PATH = relative-packages +[actions] +ENABLED = true diff --git a/actions/example-artifacts-v4/.forgejo/workflows/test.yml b/actions/example-artifacts-v4/.forgejo/workflows/test.yml new file mode 100644 index 00000000..526def6d --- /dev/null +++ b/actions/example-artifacts-v4/.forgejo/workflows/test.yml @@ -0,0 +1,47 @@ +on: [push] +jobs: + upload-many: + runs-on: docker + steps: + - run: mkdir -p artifacts + + - run: touch artifacts/ONE artifacts/TWO + + - uses: https://data.forgejo.org/forgejo/upload-artifact@v4 + with: + name: many-artifacts + path: artifacts/ + + download-many: + needs: [upload-many] + runs-on: docker + steps: + - uses: https://data.forgejo.org/forgejo/download-artifact@v4 + + - run: | + test -f many-artifacts/ONE + test -f many-artifacts/TWO + + upload-one: + runs-on: docker + steps: + - run: mkdir -p path/to/artifact + + - run: echo hello > path/to/artifact/world.txt + + - uses: https://data.forgejo.org/forgejo/upload-artifact@v4 + with: + name: my-artifact + path: path/to/artifact/world.txt + + download-one: + needs: [upload-one] + runs-on: docker + steps: + - run: "! test -f world.txt" + + - uses: https://data.forgejo.org/forgejo/download-artifact@v4 + with: + name: my-artifact + + - run: "test -f world.txt" diff --git a/actions/example-automerge/.forgejo/workflows/test.yml b/actions/example-automerge/.forgejo/workflows/test.yml new file mode 100644 index 00000000..7bb4ce29 --- /dev/null +++ b/actions/example-automerge/.forgejo/workflows/test.yml @@ -0,0 +1,13 @@ +on: + pull_request: + +jobs: + test: + runs-on: docker + container: + image: data.forgejo.org/oci/node:20-bookworm + options: "--volume /srv/example:/srv/example" + + steps: + - run: | + ${{ vars.SCRIPT }} diff --git a/actions/example-automerge/run.sh b/actions/example-automerge/run.sh new file mode 100755 index 00000000..1d48860f --- /dev/null +++ b/actions/example-automerge/run.sh @@ -0,0 +1,108 @@ +TMPDIR=$(mktemp -d) + +trap "rm -fr $TMPDIR" EXIT + +source $EXAMPLE_DIR/../../lib/lib.sh + +api=$url/api/v1 +repo=root/example-automerge +export d=/srv/example/automerge + +function reset_automerge_pr() { + # + # repository with a pull_request event workflow that always succeeds + # + mkdir -p $d + + forgejo-curl.sh api_json -X DELETE $api/repos/$repo >&/dev/null || true + forgejo-test-helper.sh push_workflow actions/example-$example $url root example-$example setup-forgejo $token + + forgejo-curl.sh api_json -X DELETE $api/repos/$repo/actions/variables/SCRIPT >&/dev/null || true + forgejo-curl.sh api_json -X POST --data-raw '{"value":"true"}' $api/repos/$repo/actions/variables/SCRIPT + + ( + cd $d + rm -fr example-automerge + git clone $url/$repo + cd example-automerge + git checkout -b other + git config user.email root@example.com + git config user.name username + touch file-unique-to-the-pr-branch + echo other >>README + git add . + git commit -m 'other change' + git push --force -u origin other + ) + + # + # make sure the runner won't race with the sequence that follows + # + forgejo-runner.sh teardown + # + # create a PR and schedule it for automerge when the workflow succeeds + # + api_pr_delete_all $api $repo + forgejo-curl.sh api_json --data-raw '{"title":"PR title","base":"main","head":"other"}' $api/repos/$repo/pulls >$TMPDIR/pr.json + local pr=$(jq -r .number <$TMPDIR/pr.json) + forgejo-curl.sh api_json --data-raw '{"Do":"merge","merge_when_checks_succeed":true}' $api/repos/$repo/pulls/$pr/merge + if api_pr_is_merged $api $repo $pr; then + echo pull request already merged although it should not be + return 1 + fi +} + +function verify_automerge_on_status_success() { + reset_automerge_pr + local pr=$(jq -r .number <$TMPDIR/pr.json) + # + # run the workflow + # + forgejo-runner.sh run + local sha=$(api_branch_tip $api $repo other) + api_pr_wait_success $api $repo $sha + # + # verify the PR was automerged + # + if ! retry api_pr_is_merged $api $repo $pr; then + echo pull request is not automerged as expected + return 1 + fi +} + +function verify_automerge_on_reviewer_approval() { + reset_automerge_pr + local pr=$(jq -r .number <$TMPDIR/pr.json) + # + # require at least one review for a PR to be merged + # + api_branch_protect $api $repo main + # + # run the workflow + # + forgejo-runner.sh run + local sha=$(api_branch_tip $api $repo other) + api_pr_wait_success $api $repo $sha + # + # approve the PR + # + local username=user1 + api_user_create $api $username $username@example.com + api_user_make_admin $api $username + user_login $username + DOT=$API_TMPDIR/$username api_pr_approve $api $repo $pr + # + # verify the PR was automerged + # + if ! retry api_pr_is_merged $api $repo $pr; then + echo pull request is not automerged as expected + return 1 + fi +} + +function main() { + verify_automerge_on_status_success + verify_automerge_on_reviewer_approval +} + +main diff --git a/actions/example-automerge/setup.sh b/actions/example-automerge/setup.sh new file mode 100755 index 00000000..9476a675 --- /dev/null +++ b/actions/example-automerge/setup.sh @@ -0,0 +1 @@ +mkdir -p /srv/example/automerge diff --git a/actions/example-cache-proxy/getter/.forgejo/workflows/get.yml b/actions/example-cache-proxy/getter/.forgejo/workflows/get.yml new file mode 100644 index 00000000..5dc434dd --- /dev/null +++ b/actions/example-cache-proxy/getter/.forgejo/workflows/get.yml @@ -0,0 +1,25 @@ +on: [push] + +jobs: + build: + runs-on: docker + container: + image: data.forgejo.org/oci/node:20-bookworm + steps: + - name: cache restore + id: cachestep + uses: https://data.forgejo.org/actions/cache/restore@v4 + with: + path: | + /usr/local/bin/something + key: thecoolsecretcachekey + + - name: verify something + run: | + set -x + test SOMETHING = $(cat /usr/local/bin/something) + + - name: cache hit + run: | + set -x + test "${{ steps.cachestep.outputs.cache-hit }}" = true diff --git a/actions/example-cache-proxy/run.sh b/actions/example-cache-proxy/run.sh new file mode 100644 index 00000000..a4b15599 --- /dev/null +++ b/actions/example-cache-proxy/run.sh @@ -0,0 +1,22 @@ +source $EXAMPLE_DIR/../../lib/lib.sh + +api=$url/api/v1 +repostorer=root/example-cache-proxy-storer +repogetter=root/example-cache-proxy-getter + +function main() { + forgejo-curl.sh api_json -X DELETE $api/repos/$repostorer >&/dev/null || true + forgejo-curl.sh api_json -X DELETE $api/repos/$repogetter >&/dev/null || true + + forgejo-test-helper.sh push_workflow actions/example-$example/storer $url root example-$example-storer setup-forgejo $token + local shastorer=$(forgejo-test-helper.sh branch_tip $url $repostorer main) + + forgejo-test-helper.sh wait_success $url $repostorer $shastorer + + forgejo-test-helper.sh push_workflow actions/example-$example/getter $url root example-$example-getter setup-forgejo $token + local shagetter=$(forgejo-test-helper.sh branch_tip $url $repogetter main) + + forgejo-test-helper.sh wait_failure $url $repogetter $shagetter +} + +main diff --git a/actions/example-cache-proxy/runner-config.yaml b/actions/example-cache-proxy/runner-config.yaml new file mode 100644 index 00000000..851c2c2a --- /dev/null +++ b/actions/example-cache-proxy/runner-config.yaml @@ -0,0 +1,29 @@ +log: + level: debug + +runner: + file: .runner + capacity: 1 + env_file: .env + timeout: 3h + insecure: false + fetch_timeout: 5s + fetch_interval: 2s + labels: ["docker:docker://code.forgejo.org/oci/node:20-bookworm"] + +cache: + enabled: true + dir: "/srv/example/cache" + host: "" + port: 0 + +container: + network: "bridge" + privileged: false + options: + workdir_parent: + valid_volumes: ["/srv/example"] + docker_host: "" + +host: + workdir_parent: diff --git a/actions/example-cache-proxy/setup.sh b/actions/example-cache-proxy/setup.sh new file mode 100755 index 00000000..9c1f5adf --- /dev/null +++ b/actions/example-cache-proxy/setup.sh @@ -0,0 +1 @@ +FORGEJO_RUNNER_CONFIG=$EXAMPLE_DIR/runner-config.yaml forgejo-runner.sh reload diff --git a/actions/example-cache-proxy/storer/.forgejo/workflows/store.yml b/actions/example-cache-proxy/storer/.forgejo/workflows/store.yml new file mode 100644 index 00000000..db9b101a --- /dev/null +++ b/actions/example-cache-proxy/storer/.forgejo/workflows/store.yml @@ -0,0 +1,17 @@ +on: [push] + +jobs: + build: + runs-on: docker + container: + image: data.forgejo.org/oci/node:20-bookworm + steps: + - name: create something + run: echo SOMETHING > /usr/local/bin/something + + - name: cache save + uses: https://data.forgejo.org/actions/cache/save@v4 + with: + path: | + /usr/local/bin/something + key: thecoolsecretcachekey diff --git a/actions/example-cache-proxy/teardown.sh b/actions/example-cache-proxy/teardown.sh new file mode 100755 index 00000000..b410c513 --- /dev/null +++ b/actions/example-cache-proxy/teardown.sh @@ -0,0 +1 @@ +forgejo-runner.sh reload diff --git a/actions/example-cache-pull-request/.forgejo/workflows/test.yml b/actions/example-cache-pull-request/.forgejo/workflows/test.yml new file mode 100644 index 00000000..43a96d41 --- /dev/null +++ b/actions/example-cache-pull-request/.forgejo/workflows/test.yml @@ -0,0 +1,96 @@ +on: + pull_request: + types: + - opened + - closed + +jobs: + save-cache: + runs-on: docker + container: + image: data.forgejo.org/oci/node:20-bookworm + steps: + - name: cache restore + id: cachestep1 + uses: https://data.forgejo.org/actions/cache/restore@v4 + with: + path: | + /usr/local/bin/something + key: cachekey-${{ forge.event.pull_request.head.repo.full_name }} + + - name: cache hit + run: | + set -x + test "${{ steps.cachestep1.outputs.cache-hit }}" != true + + - name: create something + run: echo SOMETHING > /usr/local/bin/something + + - name: cache save + uses: https://data.forgejo.org/actions/cache/save@v4 + with: + path: | + /usr/local/bin/something + key: ${{ steps.cachestep1.outputs.cache-primary-key }} + + restore-cache: + runs-on: docker + needs: [save-cache] + container: + image: data.forgejo.org/oci/node:20-bookworm + steps: + - name: cache restore + id: cachestep2 + uses: https://data.forgejo.org/actions/cache/restore@v4 + with: + path: | + /usr/local/bin/something + key: cachekey-${{ forge.event.pull_request.head.repo.full_name }} + + - name: verify something + run: | + set -x + test SOMETHING = $(cat /usr/local/bin/something) + + - name: cache hit + run: | + set -x + test "${{ steps.cachestep2.outputs.cache-hit }}" = true + + test: + runs-on: docker + needs: [restore-cache] + container: + image: data.forgejo.org/oci/node:20-bookworm + options: "--volume /srv/example:/srv/example" + + steps: + - name: setup + shell: bash + run: | + set -x + test $FORGEJO_TOKEN = ${{ env.FORGEJO_TOKEN }} + test $FORGEJO_TOKEN = ${{ forge.token }} + export DEBIAN_FRONTEND=noninteractive ; apt-get -qq update ; apt-get install -y -qq curl git >& /dev/null + curl -sS -o /usr/local/bin/forgejo-curl.sh https://code.forgejo.org/forgejo/forgejo-curl/raw/branch/main/forgejo-curl.sh && chmod +x /usr/local/bin/forgejo-curl.sh + forgejo-curl.sh --token "$FORGEJO_TOKEN" login $FORGEJO_SERVER_URL + forgejo-curl.sh api_json $FORGEJO_SERVER_URL/api/v1/user + + - name: determine if the PR is from a fork + id: forked + run: | + set -x + if test ${{ forge.event.pull_request.base.repo.full_name }} = ${{ forge.event.pull_request.head.repo.full_name }} ; then + echo value=false >> $FORGEJO_OUTPUT + else + echo value=true >> $FORGEJO_OUTPUT + fi + + - name: save event + run: | + set -x + d=/srv/example/cache-pull-request/contexts/${{ forgejo.event.pull_request.head.repo.owner.username }}/$FORGEJO_EVENT_NAME + mkdir -p $d + cat > $d/forgejo-${{ forgejo.event.action }} <<'EOF' + ${{ toJSON(forgejo) }} + EOF diff --git a/actions/example-cache-pull-request/assert-contexts-closed.sh b/actions/example-cache-pull-request/assert-contexts-closed.sh new file mode 100755 index 00000000..4c0f8e27 --- /dev/null +++ b/actions/example-cache-pull-request/assert-contexts-closed.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +set -ex + +c=$d/contexts + +for user in cache-fork-org root; do + test -f $c/$user/pull_request/forgejo-closed +done diff --git a/actions/example-cache-pull-request/assert-contexts-opened.sh b/actions/example-cache-pull-request/assert-contexts-opened.sh new file mode 100755 index 00000000..73fcccda --- /dev/null +++ b/actions/example-cache-pull-request/assert-contexts-opened.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +set -ex + +c=$d/contexts + +for user in cache-fork-org root; do + test -f $c/$user/pull_request/forgejo-opened +done diff --git a/actions/example-cache-pull-request/run.sh b/actions/example-cache-pull-request/run.sh new file mode 100755 index 00000000..85020281 --- /dev/null +++ b/actions/example-cache-pull-request/run.sh @@ -0,0 +1,80 @@ +TMPDIR=$(mktemp -d) + +trap "rm -fr $TMPDIR" EXIT + +api=$url/api/v1 +export d=/srv/example/cache-pull-request + +function main() { + mkdir -p $d + + # + # open a pull request + # - from the same repository + # - from a forked repository + # + forgejo-test-helper.sh push_workflow actions/example-$example $url root example-$example setup-forgejo $token + + forgejo-curl.sh api_json --data-raw '{"username":"cache-fork-org"}' $api/orgs + forgejo-curl.sh api_json --data-raw '{"organization":"cache-fork-org"}' $api/repos/root/example-cache-pull-request/forks + + ( + cd $d + git clone $url/cache-fork-org/example-cache-pull-request fork + cd fork + git config user.email root@example.com + git config user.name username + touch file-unique-to-the-pr-branch + git add . + git commit -m 'fork change' + git push + ) + + forgejo.sh retry forgejo-curl.sh api_json --data-raw '{"title":"PR from fork","base":"main","head":"cache-fork-org:main"}' $api/repos/root/example-cache-pull-request/pulls + + ( + cd $d + git clone $url/root/example-cache-pull-request + cd example-cache-pull-request + git checkout -b other + git config user.email root@example.com + git config user.name username + touch file-unique-to-the-forked-pr + git add . + git commit -m 'other change' + git push --force -u origin other + ) + + forgejo.sh retry forgejo-curl.sh api_json --data-raw '{"title":"PR same repo","base":"main","head":"other"}' $api/repos/root/example-cache-pull-request/pulls + + export RETRY_DELAYS="10 20 60 60 60 60 60" + + # + # wait for the opened event to succeed using the cache on all pull requests + # + if ! forgejo.sh retry $EXAMPLE_DIR/assert-contexts-opened.sh; then + echo "assert-contexts-opened.sh failed; printing related logs and information:" + find $d + sed -e 's/^/[RUNNER LOGS]/' <$FORGEJO_RUNNER_LOGS + return 1 + fi + + # + # merge all pull requests + # + forgejo-curl.sh api_json $api/repos/root/example-cache-pull-request/pulls | jq -r '.[] | .number' | while read pr; do + forgejo-curl.sh api_json --data-raw '{"Do":"merge"}' $api/repos/root/example-cache-pull-request/pulls/$pr/merge + done + + # + # wait for the closed event to succeed using the cache on all pull requests + # + if ! forgejo.sh retry $EXAMPLE_DIR/assert-contexts-closed.sh; then + echo "assert-contexts-closed.sh failed; printing related logs and information:" + find $d + sed -e 's/^/[RUNNER LOGS]/' <$FORGEJO_RUNNER_LOGS + return 1 + fi +} + +main diff --git a/actions/example-cache-pull-request/runner-config.yaml b/actions/example-cache-pull-request/runner-config.yaml new file mode 100644 index 00000000..11818cc5 --- /dev/null +++ b/actions/example-cache-pull-request/runner-config.yaml @@ -0,0 +1,30 @@ + +log: + level: debug + +runner: + file: .runner + capacity: 1 + env_file: .env + timeout: 3h + insecure: false + fetch_timeout: 5s + fetch_interval: 2s + labels: ["docker:docker://code.forgejo.org/oci/node:20-bookworm"] + +cache: + enabled: true + dir: "/srv/example/cache" + host: "" + port: 0 + +container: + network: "bridge" + privileged: false + options: + workdir_parent: + valid_volumes: ["/srv/example"] + docker_host: "" + +host: + workdir_parent: diff --git a/actions/example-cache-pull-request/setup.sh b/actions/example-cache-pull-request/setup.sh new file mode 100755 index 00000000..0fb6d859 --- /dev/null +++ b/actions/example-cache-pull-request/setup.sh @@ -0,0 +1,2 @@ +mkdir -p /srv/example/cache-pull-request +FORGEJO_RUNNER_CONFIG=$EXAMPLE_DIR/runner-config.yaml forgejo-runner.sh reload diff --git a/actions/example-cache-pull-request/teardown.sh b/actions/example-cache-pull-request/teardown.sh new file mode 100755 index 00000000..b410c513 --- /dev/null +++ b/actions/example-cache-pull-request/teardown.sh @@ -0,0 +1 @@ +forgejo-runner.sh reload diff --git a/actions/example-cache/.forgejo/workflows/test.yml b/actions/example-cache/.forgejo/workflows/test.yml new file mode 100644 index 00000000..7acc5c59 --- /dev/null +++ b/actions/example-cache/.forgejo/workflows/test.yml @@ -0,0 +1,54 @@ +on: [push] + +jobs: + save-cache: + runs-on: docker + container: + image: data.forgejo.org/oci/node:20-bookworm + steps: + - name: cache restore + id: cachestep1 + uses: https://data.forgejo.org/actions/cache/restore@v4 + with: + path: | + /usr/local/bin/something + key: cachekey + + - name: cache hit + run: | + set -x + test "${{ steps.cachestep1.outputs.cache-hit }}" != true + + - name: create something + run: echo SOMETHING > /usr/local/bin/something + + - name: cache save + uses: https://data.forgejo.org/actions/cache/save@v4 + with: + path: | + /usr/local/bin/something + key: ${{ steps.cachestep1.outputs.cache-primary-key }} + + restore-cache: + runs-on: docker + needs: [save-cache] + container: + image: data.forgejo.org/oci/node:20-bookworm + steps: + - name: cache restore + id: cachestep2 + uses: https://data.forgejo.org/actions/cache/restore@v4 + with: + path: | + /usr/local/bin/something + key: cachekey + + - name: verify something + run: | + set -x + test SOMETHING = $(cat /usr/local/bin/something) + + - name: cache hit + run: | + set -x + test "${{ steps.cachestep2.outputs.cache-hit }}" = true diff --git a/actions/example-cache/runner-config.yaml b/actions/example-cache/runner-config.yaml new file mode 100644 index 00000000..11818cc5 --- /dev/null +++ b/actions/example-cache/runner-config.yaml @@ -0,0 +1,30 @@ + +log: + level: debug + +runner: + file: .runner + capacity: 1 + env_file: .env + timeout: 3h + insecure: false + fetch_timeout: 5s + fetch_interval: 2s + labels: ["docker:docker://code.forgejo.org/oci/node:20-bookworm"] + +cache: + enabled: true + dir: "/srv/example/cache" + host: "" + port: 0 + +container: + network: "bridge" + privileged: false + options: + workdir_parent: + valid_volumes: ["/srv/example"] + docker_host: "" + +host: + workdir_parent: diff --git a/actions/example-cache/setup.sh b/actions/example-cache/setup.sh new file mode 100755 index 00000000..9c1f5adf --- /dev/null +++ b/actions/example-cache/setup.sh @@ -0,0 +1 @@ +FORGEJO_RUNNER_CONFIG=$EXAMPLE_DIR/runner-config.yaml forgejo-runner.sh reload diff --git a/actions/example-cache/teardown.sh b/actions/example-cache/teardown.sh new file mode 100755 index 00000000..b410c513 --- /dev/null +++ b/actions/example-cache/teardown.sh @@ -0,0 +1 @@ +forgejo-runner.sh reload diff --git a/actions/example-config-options/.forgejo/workflows/test.yml b/actions/example-config-options/.forgejo/workflows/test.yml new file mode 100644 index 00000000..7845e441 --- /dev/null +++ b/actions/example-config-options/.forgejo/workflows/test.yml @@ -0,0 +1,26 @@ +on: [push] + +jobs: + test: + runs-on: docker + container: + options: "--hostname customname" + steps: + - run: | + test -f /srv/example-config-options-volume-valid + - run: | + ! test -w /srv/example-config-options-volume-valid + - run: | + ! test -f /srv/example-config-options-volume-invalid + - run: | + set -x + test "$FROB" = "NITZ" + - run: | + set -x + test "$VAR_FROM_ENV_FILE" = "VALUE_FROM_ENV_FILE" + - run: | + set -x + test "$VAR_FROM_ENV_IN_CONFIG" = "VALUE_FROM_ENV_IN_CONFIG" + - run: | + set -x + test "$(cat /etc/hostname)" = customname diff --git a/actions/example-config-options/env_file b/actions/example-config-options/env_file new file mode 100644 index 00000000..c5b811ba --- /dev/null +++ b/actions/example-config-options/env_file @@ -0,0 +1 @@ +VAR_FROM_ENV_FILE=VALUE_FROM_ENV_FILE diff --git a/actions/example-config-options/runner-config.yaml b/actions/example-config-options/runner-config.yaml new file mode 100644 index 00000000..37b7b0ae --- /dev/null +++ b/actions/example-config-options/runner-config.yaml @@ -0,0 +1,33 @@ + +log: + level: debug + job_level: debug + +runner: + file: .runner + capacity: 1 + envs: + VAR_FROM_ENV_IN_CONFIG: VALUE_FROM_ENV_IN_CONFIG + env_file: env_file + timeout: 3h + insecure: true + fetch_timeout: 5s + fetch_interval: 2s + labels: ["docker:docker://code.forgejo.org/oci/node:20-bookworm"] + +cache: + enabled: false + dir: "" + host: "" + port: 0 + +container: + network: "" + privileged: false + options: "--volume /srv/example-config-options-volume-valid:/srv/example-config-options-volume-valid:ro --volume /srv/example-config-options-volume-invalid:/srv/example-config-options-volume-invalid --env FROB=NITZ" + workdir_parent: + valid_volumes: ["/srv/example-config-options-volume-valid"] + docker_host: "" + +host: + workdir_parent: diff --git a/actions/example-config-options/setup.sh b/actions/example-config-options/setup.sh new file mode 100755 index 00000000..1e62e683 --- /dev/null +++ b/actions/example-config-options/setup.sh @@ -0,0 +1,6 @@ +>/srv/example-config-options-volume-valid +>/srv/example-config-options-volume-invalid +TMPDIR=$(mktemp -d) +cp $EXAMPLE_DIR/runner-config.yaml $EXAMPLE_DIR/env_file $TMPDIR +sed -i -e "s|env_file:.*|env_file: $TMPDIR/env_file|" $TMPDIR/runner-config.yaml +FORGEJO_RUNNER_CONFIG=$TMPDIR/runner-config.yaml forgejo-runner.sh reload diff --git a/actions/example-config-options/teardown.sh b/actions/example-config-options/teardown.sh new file mode 100755 index 00000000..b410c513 --- /dev/null +++ b/actions/example-config-options/teardown.sh @@ -0,0 +1 @@ +forgejo-runner.sh reload diff --git a/actions/example-container/.forgejo/workflows/test.yml b/actions/example-container/.forgejo/workflows/test.yml index 583df87e..ecf04290 100644 --- a/actions/example-container/.forgejo/workflows/test.yml +++ b/actions/example-container/.forgejo/workflows/test.yml @@ -3,6 +3,6 @@ jobs: test: runs-on: docker container: - image: alpine:3.19 + image: data.forgejo.org/oci/alpine:3.23 steps: - run: grep Alpine /etc/os-release diff --git a/actions/example-context/.forgejo/workflows/test.yml b/actions/example-context/.forgejo/workflows/test.yml index a894bfd2..07f80fa9 100644 --- a/actions/example-context/.forgejo/workflows/test.yml +++ b/actions/example-context/.forgejo/workflows/test.yml @@ -4,7 +4,7 @@ jobs: test: runs-on: docker container: - image: code.forgejo.org/oci/node:20-bookworm + image: data.forgejo.org/oci/node:20-bookworm volumes: - /srv/example:/srv/example steps: @@ -15,174 +15,240 @@ jobs: test "$CI" = true test "$CI" = "${{ env.CI }}" - - name: GITHUB_ACTION + - name: FORGEJO_ACTION run: | set -x - echo "$GITHUB_ACTION" | grep -E '^[0-9]+$' - test "$GITHUB_ACTION" = "${{ env.GITHUB_ACTION }}" - test "$GITHUB_ACTION" = "${{ github.ACTION }}" + echo "$FORGEJO_ACTION" | grep -E '^[0-9]+$' + test "$FORGEJO_ACTION" = "${{ env.FORGEJO_ACTION }}" + test "$FORGEJO_ACTION" = "${{ github.ACTION }}" + test "$FORGEJO_ACTION" = "${{ forge.ACTION }}" + test "$FORGEJO_ACTION" = "${{ forgejo.ACTION }}" + test "$FORGEJO_ACTION" = "$GITHUB_ACTION" # See also actions/example-local-action/.forgejo/local-action/action.yml - - name: GITHUB_ACTION_PATH + - name: FORGEJO_ACTION_PATH run: | set -x - test -z "$GITHUB_ACTION_PATH" - test "$GITHUB_ACTION_PATH" = "${{ env.GITHUB_ACTION_PATH }}" - test "$GITHUB_ACTION_PATH" = "${{ github.ACTION_PATH }}" + test -z "$FORGEJO_ACTION_PATH" + test "$FORGEJO_ACTION_PATH" = "${{ env.FORGEJO_ACTION_PATH }}" + test "$FORGEJO_ACTION_PATH" = "${{ github.ACTION_PATH }}" + test "$FORGEJO_ACTION_PATH" = "${{ forge.ACTION_PATH }}" + test "$FORGEJO_ACTION_PATH" = "${{ forgejo.ACTION_PATH }}" + test "$FORGEJO_ACTION_PATH" = "$GITHUB_ACTION_PATH" - name: when running an action - if: ${{ env.GITHUB_ACTIONS }} + if: ${{ env.FORGEJO_ACTIONS }} uses: SELF@main with: input-one: "otherone" - - name: GITHUB_ACTION_REPOSITORY - run: test -f /srv/example/example-context/GITHUB_ACTION_REPOSITORY + - name: FORGEJO_ACTION_REPOSITORY + run: test -f /srv/example/example-context/FORGEJO_ACTION_REPOSITORY - - name: GITHUB_ACTION_PATH - run: test -f /srv/example/example-context/GITHUB_ACTION_PATH + - name: FORGEJO_ACTION_PATH + run: test -f /srv/example/example-context/FORGEJO_ACTION_PATH - - name: GITHUB_ACTIONS + - name: FORGEJO_ACTIONS run: | set -x - test "$GITHUB_ACTIONS" = true - test "$GITHUB_ACTIONS" = "${{ env.GITHUB_ACTIONS }}" + test "$FORGEJO_ACTIONS" = true + test "$FORGEJO_ACTIONS" = "${{ env.FORGEJO_ACTIONS }}" + test "$FORGEJO_ACTIONS" = "$GITHUB_ACTIONS" - - name: GITHUB_ACTOR + - name: FORGEJO_ACTOR run: | set -x - test "$GITHUB_ACTOR" - test "$GITHUB_ACTOR" = "${{ env.GITHUB_ACTOR }}" - test "$GITHUB_ACTOR" = "${{ github.ACTOR }}" + test "$FORGEJO_ACTOR" + test "$FORGEJO_ACTOR" = "${{ env.FORGEJO_ACTOR }}" + test "$FORGEJO_ACTOR" = "${{ github.ACTOR }}" + test "$FORGEJO_ACTOR" = "${{ forge.ACTOR }}" + test "$FORGEJO_ACTOR" = "${{ forgejo.ACTOR }}" + test "$FORGEJO_ACTOR" = "$GITHUB_ACTOR" - - name: GITHUB_API_URL + - name: FORGEJO_API_URL shell: bash run: | set -x - [[ "$GITHUB_API_URL" =~ /api/v1$ ]] - test "$GITHUB_API_URL" = "${{ env.GITHUB_API_URL }}" - test "$GITHUB_API_URL" = "${{ github.API_URL }}" + [[ "$FORGEJO_API_URL" =~ /api/v1$ ]] + test "$FORGEJO_API_URL" = "${{ env.FORGEJO_API_URL }}" + test "$FORGEJO_API_URL" = "${{ github.API_URL }}" + test "$FORGEJO_API_URL" = "${{ forge.API_URL }}" + test "$FORGEJO_API_URL" = "${{ forgejo.API_URL }}" + test "$FORGEJO_API_URL" = "$GITHUB_API_URL" # See also actions/example-pull-request/.forgejo/workflows/test.yml - - name: GITHUB_BASE_REF + - name: FORGEJO_BASE_REF run: | set -x - test -z "$GITHUB_BASE_REF" - test "$GITHUB_BASE_REF" = "${{ env.GITHUB_BASE_REF }}" - test "$GITHUB_BASE_REF" = "${{ github.BASE_REF }}" + test -z "$FORGEJO_BASE_REF" + test "$FORGEJO_BASE_REF" = "${{ env.FORGEJO_BASE_REF }}" + test "$FORGEJO_BASE_REF" = "${{ github.BASE_REF }}" + test "$FORGEJO_BASE_REF" = "${{ forge.BASE_REF }}" + test "$FORGEJO_BASE_REF" = "${{ forgejo.BASE_REF }}" + test "$FORGEJO_BASE_REF" = "$GITHUB_BASE_REF" # See also actions/example-pull-request/.forgejo/workflows/test.yml - - name: GITHUB_HEAD_REF + - name: FORGEJO_HEAD_REF run: | set -x - test -z "$GITHUB_HEAD_REF" - test "$GITHUB_HEAD_REF" = "${{ env.GITHUB_HEAD_REF }}" - test "$GITHUB_HEAD_REF" = "${{ github.HEAD_REF }}" + test -z "$FORGEJO_HEAD_REF" + test "$FORGEJO_HEAD_REF" = "${{ env.FORGEJO_HEAD_REF }}" + test "$FORGEJO_HEAD_REF" = "${{ github.HEAD_REF }}" + test "$FORGEJO_HEAD_REF" = "${{ forge.HEAD_REF }}" + test "$FORGEJO_HEAD_REF" = "${{ forgejo.HEAD_REF }}" + test "$FORGEJO_HEAD_REF" = "$GITHUB_HEAD_REF" - - name: GITHUB_ENV + - name: FORGEJO_ENV run: | set -x - test -f "$GITHUB_ENV" - test "$GITHUB_ENV" = "${{ env.GITHUB_ENV }}" + test -f "$FORGEJO_ENV" + test "$FORGEJO_ENV" = "${{ env.FORGEJO_ENV }}" + test "$FORGEJO_ENV" = "$GITHUB_ENV" - - name: GITHUB_EVENT_NAME + - name: FORGEJO_EVENT_NAME run: | set -x - test "$GITHUB_EVENT_NAME" = push - test "$GITHUB_EVENT_NAME" = "${{ env.GITHUB_EVENT_NAME }}" - test "$GITHUB_EVENT_NAME" = "${{ github.EVENT_NAME }}" + test "$FORGEJO_EVENT_NAME" = push + test "$FORGEJO_EVENT_NAME" = "${{ env.FORGEJO_EVENT_NAME }}" + test "$FORGEJO_EVENT_NAME" = "${{ github.EVENT_NAME }}" + test "$FORGEJO_EVENT_NAME" = "${{ forge.EVENT_NAME }}" + test "$FORGEJO_EVENT_NAME" = "${{ forgejo.EVENT_NAME }}" + test "$FORGEJO_EVENT_NAME" = "$GITHUB_EVENT_NAME" - - name: GITHUB_JOB + - name: FORGEJO_JOB run: | set -x - test "$GITHUB_JOB" = test - test "$GITHUB_JOB" = "${{ env.GITHUB_JOB }}" - test "$GITHUB_JOB" = "${{ github.JOB }}" + test "$FORGEJO_JOB" = test + test "$FORGEJO_JOB" = "${{ env.FORGEJO_JOB }}" + test "$FORGEJO_JOB" = "${{ github.JOB }}" + test "$FORGEJO_JOB" = "${{ forge.JOB }}" + test "$FORGEJO_JOB" = "${{ forgejo.JOB }}" + test "$FORGEJO_JOB" = "$GITHUB_JOB" - - name: GITHUB_OUTPUT + - name: FORGEJO_OUTPUT run: | set -x - test -f "$GITHUB_OUTPUT" - test "$GITHUB_OUTPUT" = "${{ env.GITHUB_OUTPUT }}" + test -f "$FORGEJO_OUTPUT" + test "$FORGEJO_OUTPUT" = "${{ env.FORGEJO_OUTPUT }}" + test "$FORGEJO_OUTPUT" = "$GITHUB_OUTPUT" - - name: GITHUB_PATH + - name: FORGEJO_PATH run: | set -x - test -f "$GITHUB_PATH" - test "$GITHUB_PATH" = "${{ env.GITHUB_PATH }}" + test -f "$FORGEJO_PATH" + test "$FORGEJO_PATH" = "${{ env.FORGEJO_PATH }}" + test "$FORGEJO_PATH" = "$GITHUB_PATH" - - name: GITHUB_REF + - name: FORGEJO_REF shell: bash run: | set -x - [[ "$GITHUB_REF" =~ ^refs/ ]] - test "$GITHUB_REF" = "${{ env.GITHUB_REF }}" - test "$GITHUB_REF" = "${{ github.REF }}" + [[ "$FORGEJO_REF" =~ ^refs/ ]] + test "$FORGEJO_REF" = "${{ env.FORGEJO_REF }}" + test "$FORGEJO_REF" = "${{ github.REF }}" + test "$FORGEJO_REF" = "${{ forge.REF }}" + test "$FORGEJO_REF" = "${{ forgejo.REF }}" + test "$FORGEJO_REF" = "$GITHUB_REF" - - name: GITHUB_REF_NAME + - name: FORGEJO_REF_NAME shell: bash run: | set -x - ! [[ "$GITHUB_REF_NAME" =~ ^refs/ ]] - test "$GITHUB_REF_NAME" = "${{ env.GITHUB_REF_NAME }}" - test "$GITHUB_REF_NAME" = "${{ github.REF_NAME }}" + ! [[ "$FORGEJO_REF_NAME" =~ ^refs/ ]] + test "$FORGEJO_REF_NAME" = "${{ env.FORGEJO_REF_NAME }}" + test "$FORGEJO_REF_NAME" = "${{ github.REF_NAME }}" + test "$FORGEJO_REF_NAME" = "${{ forge.REF_NAME }}" + test "$FORGEJO_REF_NAME" = "${{ forgejo.REF_NAME }}" + test "$FORGEJO_REF_NAME" = "$GITHUB_REF_NAME" - - name: GITHUB_REPOSITORY + - name: FORGEJO_REPOSITORY run: | set -x - test "$GITHUB_REPOSITORY" = root/example-context - test "$GITHUB_REPOSITORY" = "${{ env.GITHUB_REPOSITORY }}" - test "$GITHUB_REPOSITORY" = "${{ github.REPOSITORY }}" + test "$FORGEJO_REPOSITORY" = root/example-context + test "$FORGEJO_REPOSITORY" = "${{ env.FORGEJO_REPOSITORY }}" + test "$FORGEJO_REPOSITORY" = "${{ github.REPOSITORY }}" + test "$FORGEJO_REPOSITORY" = "${{ forge.REPOSITORY }}" + test "$FORGEJO_REPOSITORY" = "${{ forgejo.REPOSITORY }}" + test "$FORGEJO_REPOSITORY" = "$GITHUB_REPOSITORY" - - name: GITHUB_REPOSITORY_OWNER + - name: FORGEJO_REPOSITORY_OWNER run: | set -x - test "$GITHUB_REPOSITORY_OWNER" = root - test "$GITHUB_REPOSITORY_OWNER" = "${{ env.GITHUB_REPOSITORY_OWNER }}" - test "$GITHUB_REPOSITORY_OWNER" = "${{ github.REPOSITORY_OWNER }}" + test "$FORGEJO_REPOSITORY_OWNER" = root + test "$FORGEJO_REPOSITORY_OWNER" = "${{ env.FORGEJO_REPOSITORY_OWNER }}" + test "$FORGEJO_REPOSITORY_OWNER" = "${{ github.REPOSITORY_OWNER }}" + test "$FORGEJO_REPOSITORY_OWNER" = "${{ forge.REPOSITORY_OWNER }}" + test "$FORGEJO_REPOSITORY_OWNER" = "${{ forgejo.REPOSITORY_OWNER }}" + test "$FORGEJO_REPOSITORY_OWNER" = "$GITHUB_REPOSITORY_OWNER" - - name: GITHUB_RUN_NUMBER + - name: FORGEJO_RUN_NUMBER run: | set -x - echo "$GITHUB_RUN_NUMBER" | grep -E '^[0-9]+$' - test "$GITHUB_RUN_NUMBER" = "${{ env.GITHUB_RUN_NUMBER }}" - test "$GITHUB_RUN_NUMBER" = "${{ github.RUN_NUMBER }}" + echo "$FORGEJO_RUN_NUMBER" | grep -E '^[0-9]+$' + test "$FORGEJO_RUN_NUMBER" = "${{ env.FORGEJO_RUN_NUMBER }}" + test "$FORGEJO_RUN_NUMBER" = "${{ github.RUN_NUMBER }}" + test "$FORGEJO_RUN_NUMBER" = "${{ forge.RUN_NUMBER }}" + test "$FORGEJO_RUN_NUMBER" = "${{ forgejo.RUN_NUMBER }}" + test "$FORGEJO_RUN_NUMBER" = "$GITHUB_RUN_NUMBER" - - name: GITHUB_SERVER_URL + - name: FORGEJO_RUN_ID + run: | + set -x + echo "$FORGEJO_RUN_ID" | grep -E '^[0-9]+$' + test "$FORGEJO_RUN_ID" = "${{ env.FORGEJO_RUN_ID }}" + test "$FORGEJO_RUN_ID" = "${{ github.RUN_ID }}" + test "$FORGEJO_RUN_ID" = "${{ forge.RUN_ID }}" + test "$FORGEJO_RUN_ID" = "${{ forgejo.RUN_ID }}" + test "$FORGEJO_RUN_ID" = "$GITHUB_RUN_ID" + + - name: FORGEJO_SERVER_URL shell: bash run: | set -x - [[ "$GITHUB_SERVER_URL" =~ ^http ]] - test "$GITHUB_SERVER_URL" = "${{ env.GITHUB_SERVER_URL }}" - test "$GITHUB_SERVER_URL" = "${{ github.SERVER_URL }}" + [[ "$FORGEJO_SERVER_URL" =~ ^http ]] + test "$FORGEJO_SERVER_URL" = "${{ env.FORGEJO_SERVER_URL }}" + test "$FORGEJO_SERVER_URL" = "${{ github.SERVER_URL }}" + test "$FORGEJO_SERVER_URL" = "${{ forge.SERVER_URL }}" + test "$FORGEJO_SERVER_URL" = "${{ forgejo.SERVER_URL }}" + test "$FORGEJO_SERVER_URL" = "$GITHUB_SERVER_URL" - - name: GITHUB_SHA + - name: FORGEJO_SHA run: | set -x - test "$GITHUB_SHA" - test "$GITHUB_SHA" = "${{ env.GITHUB_SHA }}" - test "$GITHUB_SHA" = "${{ github.SHA }}" + test "$FORGEJO_SHA" + test "$FORGEJO_SHA" = "${{ env.FORGEJO_SHA }}" + test "$FORGEJO_SHA" = "${{ github.SHA }}" + test "$FORGEJO_SHA" = "${{ forge.SHA }}" + test "$FORGEJO_SHA" = "${{ forgejo.SHA }}" + test "$FORGEJO_SHA" = "$GITHUB_SHA" - - name: GITHUB_STEP_SUMMARY + - name: FORGEJO_STEP_SUMMARY run: | set -x - test -f "$GITHUB_STEP_SUMMARY" - test "$GITHUB_STEP_SUMMARY" = "${{ env.GITHUB_STEP_SUMMARY }}" + test -f "$FORGEJO_STEP_SUMMARY" + test "$FORGEJO_STEP_SUMMARY" = "${{ env.FORGEJO_STEP_SUMMARY }}" + test "$FORGEJO_STEP_SUMMARY" = "$GITHUB_STEP_SUMMARY" # See also actions/example-pull-request/.forgejo/workflows/test.yml - - name: GITHUB_TOKEN + - name: FORGEJO_TOKEN run: | set -x - test "$GITHUB_TOKEN" - test "$GITHUB_TOKEN" = "${{ env.GITHUB_TOKEN }}" - test "$GITHUB_TOKEN" = "${{ github.TOKEN }}" + test "$FORGEJO_TOKEN" + test "$FORGEJO_TOKEN" = "${{ env.FORGEJO_TOKEN }}" + test "$FORGEJO_TOKEN" = "${{ github.TOKEN }}" + test "$FORGEJO_TOKEN" = "${{ forge.TOKEN }}" + test "$FORGEJO_TOKEN" = "${{ forgejo.TOKEN }}" + test "$FORGEJO_TOKEN" = "$GITHUB_TOKEN" - - name: GITHUB_WORKSPACE + - name: FORGEJO_WORKSPACE run: | set -x - test -d "$GITHUB_WORKSPACE" - test "$GITHUB_WORKSPACE" = "${{ env.GITHUB_WORKSPACE }}" - test "$GITHUB_WORKSPACE" = "${{ github.WORKSPACE }}" + test -d "$FORGEJO_WORKSPACE" + test "$FORGEJO_WORKSPACE" = "${{ env.FORGEJO_WORKSPACE }}" + test "$FORGEJO_WORKSPACE" = "${{ github.WORKSPACE }}" + test "$FORGEJO_WORKSPACE" = "${{ forge.WORKSPACE }}" + test "$FORGEJO_WORKSPACE" = "${{ forgejo.WORKSPACE }}" + test "$FORGEJO_WORKSPACE" = "$GITHUB_WORKSPACE" - name: RUNNER_ARCH run: | @@ -194,11 +260,10 @@ jobs: set -x test "$RUNNER_OS" = Linux - # runner 3.3.0 $RUNNER_TOOL_CACHE is not an existing directory - # - name: RUNNER_TOOL_CACHE - # run: | - # set -x - # test -d "$RUNNER_TOOL_CACHE" + - name: RUNNER_TOOL_CACHE + run: | + set -x + test "$RUNNER_TOOL_CACHE" - name: RUNNER_TEMP run: | diff --git a/actions/example-context/action-for-context/action.yml b/actions/example-context/action-for-context/action.yml index dcb8f2b7..e675d6ca 100644 --- a/actions/example-context/action-for-context/action.yml +++ b/actions/example-context/action-for-context/action.yml @@ -6,18 +6,27 @@ inputs: runs: using: "composite" steps: - - name: GITHUB_ACTION_REPOSITORY + - name: FORGEJO_ACTION_REPOSITORY run: | set -x - test "$GITHUB_ACTION_REPOSITORY" = root/action-for-context - test "$GITHUB_ACTION_REPOSITORY" = "${{ env.GITHUB_ACTION_REPOSITORY }}" - test "$GITHUB_ACTION_REPOSITORY" = "${{ github.ACTION_REPOSITORY }}" - touch /srv/example/example-context/GITHUB_ACTION_REPOSITORY + test "$FORGEJO_ACTION_REPOSITORY" = root/action-for-context + test "$FORGEJO_ACTION_REPOSITORY" = "${{ env.FORGEJO_ACTION_REPOSITORY }}" + test "$FORGEJO_ACTION_REPOSITORY" = "${{ github.ACTION_REPOSITORY }}" + test "$FORGEJO_ACTION_REPOSITORY" = "${{ forge.ACTION_REPOSITORY }}" + test "$FORGEJO_ACTION_REPOSITORY" = "${{ forgejo.ACTION_REPOSITORY }}" + test "$FORGEJO_ACTION_REPOSITORY" = "$GITHUB_ACTION_REPOSITORY" + touch /srv/example/example-context/FORGEJO_ACTION_REPOSITORY - - name: GITHUB_ACTION_PATH + - name: FORGEJO_ACTION_PATH shell: bash run: | set -x - [[ "$GITHUB_ACTION_PATH" =~ action-for-context@main$ ]] - test "$GITHUB_ACTION_PATH" = "${{ github.ACTION_PATH }}" - touch /srv/example/example-context/GITHUB_ACTION_PATH + # prior to Forgejo runner 8.0.0 the action path is built out of the file path. + # with Forgejo runner 8.0.0 and above is it a 64 character hash string + # e.g. /var/run/act/actions/1b/5c1802fa47e35716c2a0977bc907049d31aef29191cba400011c0b38b52d12 + [[ "$FORGEJO_ACTION_PATH" =~ action-for-context@main$ ]] || [[ "$FORGEJO_ACTION_PATH" =~ /[0-9a-f]{2}/[0-9a-f]{62}$ ]] + test "$FORGEJO_ACTION_PATH" = "${{ github.ACTION_PATH }}" + test "$FORGEJO_ACTION_PATH" = "${{ forge.ACTION_PATH }}" + test "$FORGEJO_ACTION_PATH" = "${{ forgejo.ACTION_PATH }}" + test "$FORGEJO_ACTION_PATH" = "$GITHUB_ACTION_PATH" + touch /srv/example/example-context/FORGEJO_ACTION_PATH diff --git a/actions/example-create-runner-file/.forgejo/workflows/test.yaml b/actions/example-create-runner-file/.forgejo/workflows/test.yaml new file mode 100644 index 00000000..e44397dd --- /dev/null +++ b/actions/example-create-runner-file/.forgejo/workflows/test.yaml @@ -0,0 +1,9 @@ +on: + push: + +jobs: + test: + runs-on: create-runner-file + steps: + - run: | + echo "OK" diff --git a/actions/example-create-runner-file/run.sh b/actions/example-create-runner-file/run.sh new file mode 100644 index 00000000..637132e5 --- /dev/null +++ b/actions/example-create-runner-file/run.sh @@ -0,0 +1,40 @@ +source "lib/lib.sh" + +api="$url/api/v1" + +function main() { + local repo + repo="root/example-$example" + + secret="$(openssl rand -hex 20)" + runner_name="runner-$(openssl rand -hex 5)" + + create_offline_registration_token "$runner_name" root "$secret" + + # Changing to $DIR is necessary so that `.runner` gets created there. Otherwise, `forgejo-runner` would not pick it up. + pushd "$DIR" || exit 1 + ./forgejo-runner -c "$EXAMPLE_DIR/runner-config.yaml" create-runner-file --instance "http://$IP:3000" --name "$runner_name" --secret "$secret" --connect + popd || exit 1 + + FORGEJO_RUNNER_CONFIG="$EXAMPLE_DIR/runner-config.yaml" forgejo-runner.sh reload + + label_count=$(jq '.labels | length ' "$DIR/.runner") + if [[ "$label_count" != "1" ]] ; then + echo "Unexpected number of labels in .runner file: $label_count instead of 1" >&2 + exit 1 + fi + + runner_label=$(jq -r '.labels[0]' "$DIR/.runner") + if [[ "$runner_label" != "create-runner-file:docker://code.forgejo.org/oci/node:24-trixie" ]] ; then + echo "Unexpected runner label: '$runner_label' instead of create-runner-file:docker://code.forgejo.org/oci/node:24-trixie" >&2 + exit 1 + fi + + forgejo-test-helper.sh push_workflow "actions/example-$example" "$url" root "example-$example" setup-forgejo "$token" + + local sha + sha="$(forgejo-test-helper.sh branch_tip "$url" "$repo" main)" + forgejo-test-helper.sh wait_success "$url" "$repo" "$sha" +} + +main diff --git a/actions/example-create-runner-file/runner-config.yaml b/actions/example-create-runner-file/runner-config.yaml new file mode 100644 index 00000000..7096728f --- /dev/null +++ b/actions/example-create-runner-file/runner-config.yaml @@ -0,0 +1,31 @@ + +log: + level: debug + +runner: + file: .runner + capacity: 1 + env_file: .env + timeout: 3h + insecure: false + fetch_timeout: 5s + fetch_interval: 2s + labels: + - "create-runner-file:docker://code.forgejo.org/oci/node:24-trixie" + +cache: + enabled: true + dir: "/srv/example/cache" + host: "" + port: 0 + +container: + network: "bridge" + privileged: false + options: + workdir_parent: + valid_volumes: ["/srv/example"] + docker_host: "" + +host: + workdir_parent: diff --git a/actions/example-cron/.forgejo/workflows/test.yml b/actions/example-cron/.forgejo/workflows/test.yml index 2eedd142..58ae70a6 100644 --- a/actions/example-cron/.forgejo/workflows/test.yml +++ b/actions/example-cron/.forgejo/workflows/test.yml @@ -6,17 +6,17 @@ jobs: test: runs-on: docker container: - image: code.forgejo.org/oci/debian:bookworm + image: data.forgejo.org/oci/debian:trixie options: "--volume /srv/example:/srv/example" steps: - - run: | - touch /srv/example/cron-volume/DONE - - name: save context run: | - d=/srv/example/cron/contexts/$GITHUB_EVENT_NAME + d=/srv/example/cron/contexts/$FORGEJO_EVENT_NAME mkdir -p $d cat > $d/github <<'EOF' ${{ toJSON(github) }} EOF + + - run: | + touch /srv/example/cron-volume/DONE diff --git a/actions/example-cron/run.sh b/actions/example-cron/run.sh index f95045f8..bf19e981 100755 --- a/actions/example-cron/run.sh +++ b/actions/example-cron/run.sh @@ -7,7 +7,7 @@ forgejo-test-helper.sh push_workflow actions/example-$example $url root example- # See https://codeberg.org/forgejo/forgejo/pulls/1941 for more information # function verify_ref() { - local ref=$(sqlite3 $DIR/forgejo-work-path/forgejo.db 'select ref from action_schedule') + local ref=$(sqlite3 $DIR/forgejo-work-path/forgejo.db 'select ref from action_schedule') test "${ref##*/}" = "main" } verify_ref @@ -16,12 +16,12 @@ forgejo-curl.sh api_json --data '{"new_branch_name":"zzzz"}' $api/repos/root/exa verify_ref # cron runs once per minute, give it three minutes max before declaring failure -if ! RETRY_DELAYS="30 30 30 30 30 30" forgejo.sh retry test -f /srv/example/cron-volume/DONE ; then +if ! RETRY_DELAYS="30 30 30 30 30 30" forgejo.sh retry test -f /srv/example/cron-volume/DONE; then cat $FORGEJO_RUNNER_LOGS false fi c=/srv/example/cron/contexts/schedule/github cat $c -test "schedule" = "$(jq -r .event_name < $c)" -test "schedule" = "$(jq -r .event.action < $c)" +test "schedule" = "$(jq -r .event_name <$c)" +test "schedule" = "$(jq -r .event.action <$c)" diff --git a/actions/example-docker-action/.forgejo/workflows/test.yml b/actions/example-docker-action/.forgejo/workflows/test.yml index 988a81ed..d7ff2b98 100644 --- a/actions/example-docker-action/.forgejo/workflows/test.yml +++ b/actions/example-docker-action/.forgejo/workflows/test.yml @@ -9,11 +9,11 @@ jobs: # - uses: https://code.forgejo.org/forgejo/test-setup-forgejo-docker@main with: - args: ${{ github.workspace }}/SOMEFILE + args: ${{ forgejo.workspace }}/SOMEFILE # # ... which then also exists in the job workspace # because both docker containers are automatically # sharing the volume that contains it. # - run: | - test -f ${{ github.workspace }}/SOMEFILE + test -f ${{ forgejo.workspace }}/SOMEFILE diff --git a/actions/example-expression/.forgejo/workflows/test.yml b/actions/example-expression/.forgejo/workflows/test.yml index ab4bb646..ba37759e 100644 --- a/actions/example-expression/.forgejo/workflows/test.yml +++ b/actions/example-expression/.forgejo/workflows/test.yml @@ -23,7 +23,7 @@ jobs: if: ${{ env.KEY1 == 'nogood' }} - name: if does not skip id: conditional - run: echo 'check=good' >> $GITHUB_OUTPUT + run: echo 'check=good' >> $FORGEJO_OUTPUT if: env.KEY1 == 'value1' - name: verify if did not skip run: test ${{ steps.conditional.outputs.check }} = good @@ -98,10 +98,11 @@ jobs: set -x test "${{ fromJSON('["one","two"]')[0] }}" = 'one' - # As of act v1.13.0 this fails for real (before it pretended to work but did not) - # - name: hashFiles - # run: | - # set -x - # hash="bd52020371c038c4ad38a8d2df05dfa1a220d40fbe1ae83b63d6010cb527e531" - # test "${{ hashFiles('actions/example-expression/.forgejo/fileone.txt') }}" = $hash - # test "${{ hashFiles('actions/example-expression/.forgejo/fileone.*') }}" = $hash + - uses: actions/checkout@v4 + + - name: hashFiles + run: | + set -x + hash="aea6ca2329c852f5b480ec35e1fe09d39a6bd1b50f4f9cc38fbd4fef870dc107" + test "${{ hashFiles('.forgejo/fileone.txt') }}" = $hash + test "${{ hashFiles('.forgejo/fileone.*') }}" = $hash diff --git a/actions/example-force-rebuild/.forgejo/workflows/test.yml b/actions/example-force-rebuild/.forgejo/workflows/test.yml new file mode 100644 index 00000000..d6f8b3e9 --- /dev/null +++ b/actions/example-force-rebuild/.forgejo/workflows/test.yml @@ -0,0 +1,11 @@ +on: [push] + +jobs: + ls: + runs-on: docker + steps: + - uses: https://code.forgejo.org/forgejo/test-setup-forgejo-docker@main + with: + args: ${{ forgejo.workspace }}/SOMEFILE + - run: | + test -f ${{ forgejo.workspace }}/SOMEFILE diff --git a/actions/example-force-rebuild/run.sh b/actions/example-force-rebuild/run.sh new file mode 100755 index 00000000..b783b3a2 --- /dev/null +++ b/actions/example-force-rebuild/run.sh @@ -0,0 +1,69 @@ +TMPDIR=$(mktemp -d) + +trap "rm -fr $TMPDIR" EXIT + +function setup_with_rebuild() { + FORGEJO_RUNNER_CONFIG=$EXAMPLE_DIR/runner-config-with-rebuild.yml forgejo-runner.sh reload +} + +function setup_without_rebuild() { + FORGEJO_RUNNER_CONFIG=$EXAMPLE_DIR/runner-config-without-rebuild.yml forgejo-runner.sh reload +} + +function run() { + local dir="$1" + local expected="$2" + local repo=root/example-$example + forgejo-test-helper.sh push_workflow $dir $url root example-$example setup-forgejo $token + sha=$(forgejo-test-helper.sh branch_tip $url $repo main) + forgejo-test-helper.sh wait_$expected $url $repo $sha +} + +function get_remote_image() { + docker image ls --format='{{ .Repository }}' | grep '^runner-remote-docker-action' +} + +function remove_remote_images() { + docker image ls --format='{{ .Repository }}' | grep '^runner-remote-docker-action' | while read image; do + docker rmi $image + done +} + +function was_built() { + grep --quiet 'docker build -t runner-remote-docker-action' $FORGEJO_RUNNER_LOGS +} + +function main() { + local dir=$TMPDIR/repository + cp -a $EXAMPLE_DIR $dir + + remove_remote_images + + : + : Run one + : + setup_without_rebuild + run $dir success + local image="$(get_remote_image)" + test "$image" + was_built + + : + : Run two: verify the image was not rebuilt + : + setup_without_rebuild # resets the logs + run $dir success + test "$image" = "$(get_remote_image)" + ! was_built + + : + : Run two: verify the image was rebuilt and + : the image name stayed the same + : + setup_with_rebuild + run $dir success + test "$image" = "$(get_remote_image)" + was_built +} + +main diff --git a/actions/example-force-rebuild/runner-config-with-rebuild.yml b/actions/example-force-rebuild/runner-config-with-rebuild.yml new file mode 100644 index 00000000..6dee7b32 --- /dev/null +++ b/actions/example-force-rebuild/runner-config-with-rebuild.yml @@ -0,0 +1,31 @@ +log: + level: trace + job_level: trace + +runner: + file: .runner + capacity: 1 + env_file: .env + timeout: 3h + insecure: false + fetch_timeout: 5s + fetch_interval: 2s + labels: ["docker:docker://code.forgejo.org/oci/node:20-bookworm"] + +cache: + enabled: false + dir: "" + host: "" + port: 0 + +container: + network: "bridge" + privileged: false + options: + workdir_parent: + valid_volumes: ["/srv/example"] + docker_host: "" + force_rebuild: true + +host: + workdir_parent: diff --git a/actions/example-force-rebuild/runner-config-without-rebuild.yml b/actions/example-force-rebuild/runner-config-without-rebuild.yml new file mode 100644 index 00000000..8d9f71bb --- /dev/null +++ b/actions/example-force-rebuild/runner-config-without-rebuild.yml @@ -0,0 +1,31 @@ +log: + level: trace + job_level: trace + +runner: + file: .runner + capacity: 1 + env_file: .env + timeout: 3h + insecure: false + fetch_timeout: 5s + fetch_interval: 2s + labels: ["docker:docker://code.forgejo.org/oci/node:20-bookworm"] + +cache: + enabled: false + dir: "" + host: "" + port: 0 + +container: + network: "bridge" + privileged: false + options: + workdir_parent: + valid_volumes: ["/srv/example"] + docker_host: "" + force_rebuild: false + +host: + workdir_parent: diff --git a/actions/example-force-rebuild/teardown.sh b/actions/example-force-rebuild/teardown.sh new file mode 100755 index 00000000..b410c513 --- /dev/null +++ b/actions/example-force-rebuild/teardown.sh @@ -0,0 +1 @@ +forgejo-runner.sh reload diff --git a/actions/example-id-tokens/.forgejo/workflows/test.yml b/actions/example-id-tokens/.forgejo/workflows/test.yml new file mode 100644 index 00000000..31c49156 --- /dev/null +++ b/actions/example-id-tokens/.forgejo/workflows/test.yml @@ -0,0 +1,78 @@ +on: [push] + +env: + JWT_CLI_VERSION: 6.2.0 # renovate: datasource=github-releases depName=jwt-cli packageName=mike-engel/jwt-cli + +jobs: + generation-allowed: + enable-openid-connect: true + runs-on: docker + container: + image: data.forgejo.org/oci/ci:1 + steps: + - run: curl -L -o jwt-linux.tar.gz https://github.com/mike-engel/jwt-cli/releases/download/${{ env.JWT_CLI_VERSION }}/jwt-linux-musl.tar.gz && tar -xvzf ./jwt-linux.tar.gz && chmod a+x ./jwt + - name: validate token generation works + run: | + RAW_JWT=$(curl -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=exampleAudience" | jq -r ".value") + if [[ -z "RAW_JWT" ]]; then + echo "Error: RAW_JWT should be set" + exit 1 + fi + + DECODED_JWT_BODY=$(echo $RAW_JWT | jq -R 'split(".") | .[1] | @base64d | fromjson') + if [[ -z "$DECODED_JWT_BODY" ]]; then + echo "Error: DECODED_JWT_BODY should be set" + exit 1 + fi + + ISS=$(echo $DECODED_JWT_BODY | jq -r '.iss') + if [[ -z "$ISS" ]]; then + echo "Error: ISS should be set" + exit 1 + fi + + curl "$ISS/.well-known/keys" > jwks.json + JWKS=$(cat ./jwks.json) + if [[ -z "$JWKS" ]]; then + echo "Error: JWKS should be set" + exit 1 + fi + + # Verify that the JWT decodes with the JWKS data + ./jwt decode -S @./jwks.json -A RS256 $RAW_JWT || (echo "Error: failed signature validation" && exit 1) + + WORKFLOW=$(echo $DECODED_JWT_BODY | jq -r '.workflow') + AUD=$(echo $DECODED_JWT_BODY | jq -r '.aud') + EVENT_NAME=$(echo $DECODED_JWT_BODY | jq -r '.event_name') + SUB=$(echo $DECODED_JWT_BODY | jq -r '.sub') + if [[ "$WORKFLOW" != "test.yml" ]]; then + echo "Error: WORKFLOW should be test.yml but is $WORKFLOW" + exit 1 + fi + if [[ "$AUD" != "exampleAudience" ]]; then + echo "Error: AUD should be exampleAudience but is $AUD" + exit 1 + fi + if [[ "$EVENT_NAME" != "push" ]]; then + echo "Error: EVENT_NAME should be push but is $EVENT_NAME" + exit 1 + fi + if [[ "$SUB" != "repo:root/example-id-tokens:ref:refs/heads/main" ]]; then + echo "Error: SUB should be repo:root/example-id-tokens:ref:refs/heads/main but is $SUB" + exit 1 + fi + + generation-not-allowed: + enable-openid-connect: false + runs-on: docker + steps: + - name: check variables are unset + run: | + if [[ -n "$ACTIONS_ID_TOKEN_REQUEST_TOKEN" ]]; then + echo "Error: ACTIONS_ID_TOKEN_REQUEST_TOKEN should be unset" + exit 1 + fi + if [[ -n "$ACTIONS_ID_TOKEN_REQUEST_URL" ]]; then + echo "Error: ACTIONS_ID_TOKEN_REQUEST_TOKEN should be unset" + exit 1 + fi diff --git a/actions/example-if-cancel/.forgejo/workflows/test.yml b/actions/example-if-cancel/.forgejo/workflows/test.yml index 5a921988..d6800175 100644 --- a/actions/example-if-cancel/.forgejo/workflows/test.yml +++ b/actions/example-if-cancel/.forgejo/workflows/test.yml @@ -1,9 +1,3 @@ -# -# As of Forgejo v1.20 running this example would require using the web -# endpoints because there is no API to do the same. -# -# It was manually tested to **not work** with Forgejo v1.21 & runner 3.0.1 -# on: [push] jobs: diff --git a/actions/example-if/.forgejo/workflows/test.yml b/actions/example-if/.forgejo/workflows/test.yml index cc9401ce..355d9f20 100644 --- a/actions/example-if/.forgejo/workflows/test.yml +++ b/actions/example-if/.forgejo/workflows/test.yml @@ -8,7 +8,7 @@ jobs: - name: if true if: true id: if_true - run: echo 'check=good' >> $GITHUB_OUTPUT + run: echo 'check=good' >> $FORGEJO_OUTPUT - name: verify if true was run run: test ${{ steps.if_true.outputs.check }} = good diff --git a/actions/example-local-action/.forgejo/local-action/action.yml b/actions/example-local-action/.forgejo/local-action/action.yml index 79637578..900bc1c1 100644 --- a/actions/example-local-action/.forgejo/local-action/action.yml +++ b/actions/example-local-action/.forgejo/local-action/action.yml @@ -13,10 +13,10 @@ outputs: runs: using: "composite" steps: - - name: GITHUB_ACTION_PATH + - name: FORGEJO_ACTION_PATH run: | set -x - test "$(basename $GITHUB_ACTION_PATH)" = local-action - test "$GITHUB_ACTION_PATH" = "${{ env.GITHUB_ACTION_PATH }}" + test -e "$FORGEJO_ACTION_PATH" + test "$FORGEJO_ACTION_PATH" = "${{ env.FORGEJO_ACTION_PATH }}" - - run: echo key=${{ inputs.input-two-required }} >> $GITHUB_OUTPUT + - run: echo key=${{ inputs.input-two-required }} >> $FORGEJO_OUTPUT diff --git a/actions/example-lxc/.forgejo/workflows/test.yml b/actions/example-lxc/.forgejo/workflows/test.yml new file mode 100644 index 00000000..e7aa3fd9 --- /dev/null +++ b/actions/example-lxc/.forgejo/workflows/test.yml @@ -0,0 +1,16 @@ +on: [push] + +jobs: + job1: + runs-on: lxc + steps: + - uses: https://data.forgejo.org/actions/checkout@v4 + - run: systemctl --no-pager list-units + job2: + runs-on: lxc + steps: + - run: echo OK2 + job3: + runs-on: lxc + steps: + - run: echo OK3 diff --git a/actions/example-lxc/runner-config.yaml b/actions/example-lxc/runner-config.yaml new file mode 100644 index 00000000..617b3920 --- /dev/null +++ b/actions/example-lxc/runner-config.yaml @@ -0,0 +1,31 @@ + +log: + level: debug + job_level: debug + +runner: + file: .runner + capacity: 1 + env_file: .env + timeout: 3h + insecure: false + fetch_timeout: 5s + fetch_interval: 2s + labels: ["lxc:lxc://debian:bookworm"] + +cache: + enabled: false + dir: "" + host: "" + port: 0 + +container: + network: "bridge" + privileged: false + options: + workdir_parent: + valid_volumes: ["/srv/example"] + docker_host: "" + +host: + workdir_parent: diff --git a/actions/example-lxc/setup.sh b/actions/example-lxc/setup.sh new file mode 100755 index 00000000..9c1f5adf --- /dev/null +++ b/actions/example-lxc/setup.sh @@ -0,0 +1 @@ +FORGEJO_RUNNER_CONFIG=$EXAMPLE_DIR/runner-config.yaml forgejo-runner.sh reload diff --git a/actions/example-lxc/teardown.sh b/actions/example-lxc/teardown.sh new file mode 100755 index 00000000..b410c513 --- /dev/null +++ b/actions/example-lxc/teardown.sh @@ -0,0 +1 @@ +forgejo-runner.sh reload diff --git a/actions/example-matrix-dynamic/.forgejo/workflows/test.yml b/actions/example-matrix-dynamic/.forgejo/workflows/test.yml new file mode 100644 index 00000000..170a009b --- /dev/null +++ b/actions/example-matrix-dynamic/.forgejo/workflows/test.yml @@ -0,0 +1,49 @@ +on: [push] +jobs: + define-matrix: + runs-on: docker + outputs: + scalar-value: ${{ steps.define.outputs.scalar }} + array-value: ${{ steps.define.outputs.array }} + matrix-value: ${{ steps.define.outputs.matrix }} + steps: + - id: define + run: | + echo 'scalar=scalar value' >> "$FORGEJO_OUTPUT" + echo 'array=["value 1", "value 2"]' >> "$FORGEJO_OUTPUT" + echo 'matrix={"dimension-1": ["d1 v1", "d1 v2"], "dimension-2": ["d2 v1", "d2 v2"]}' >> "$GITHUB_OUTPUT" + + scalar-job: + runs-on: docker + needs: define-matrix + strategy: + matrix: + scalar: + - "${{ needs.define-matrix.outputs.scalar-value }}" + - hard-coded value + steps: + - run: | + set -x + [ "${{ matrix.scalar }}" = "scalar value" ] || [ "${{ matrix.scalar }}" = "hard-coded value" ] || exit 1 + + array-job: + runs-on: docker + needs: define-matrix + strategy: + matrix: + array: ${{ fromJSON(needs.define-matrix.outputs.array-value) }} + steps: + - run: | + set -x + [ "${{ matrix.array }}" = "value 1" ] || [ "${{ matrix.array }}" = "value 2" ] || exit 1 + + matrix-job: + runs-on: docker + needs: define-matrix + strategy: + matrix: ${{ fromJSON(needs.define-matrix.outputs.matrix-value) }} + steps: + - run: | + set -x + [ "${{ matrix.dimension-1 }}" = "d1 v1" ] || [ "${{ matrix.dimension-1 }}" = "d1 v2" ] || exit 1 + [ "${{ matrix.dimension-2 }}" = "d2 v1" ] || [ "${{ matrix.dimension-2 }}" = "d2 v2" ] || exit 1 diff --git a/actions/example-matrix-dynamic/run.sh b/actions/example-matrix-dynamic/run.sh new file mode 100644 index 00000000..18b8fc05 --- /dev/null +++ b/actions/example-matrix-dynamic/run.sh @@ -0,0 +1,10 @@ +forgejo-test-helper.sh run_workflow actions/example-$example $url root example-$example setup-forgejo $token + +# Verify that the matrix in the job was expanded correctly by checking that +# there are 9 completed jobs, by their commit statuses being present on the +# main branch's HEAD. +api=$url/api/v1 +sha=$(forgejo-curl.sh api_json $api/repos/root/example-matrix-dynamic/branches/main | jq -r ".commit.id") +num_runs=$(forgejo-curl.sh api_json $api/repos/root/example-matrix-dynamic/commits/$sha/status | jq ".total_count") +echo "Expecting 9 commit statuses, found $num_runs commit statuses" +test $num_runs = 9 diff --git a/actions/example-matrix/.forgejo/workflows/test.yml b/actions/example-matrix/.forgejo/workflows/test.yml new file mode 100644 index 00000000..34de0a59 --- /dev/null +++ b/actions/example-matrix/.forgejo/workflows/test.yml @@ -0,0 +1,12 @@ +on: [push] +jobs: + test: + runs-on: docker + name: name-${{ matrix.version }} + strategy: + matrix: + version: [1.18, 1.19] + steps: + - run: | + set -x + test "${{ matrix.version }}" diff --git a/actions/example-needs/.forgejo/workflows/test.yml b/actions/example-needs/.forgejo/workflows/test.yml new file mode 100644 index 00000000..d38a1e75 --- /dev/null +++ b/actions/example-needs/.forgejo/workflows/test.yml @@ -0,0 +1,19 @@ +on: [push] +jobs: + job1: + runs-on: docker + outputs: + job1output: ${{ steps.step1.outputs.value }} + steps: + - id: step1 + run: | + set -x + echo "value=value1" >> $FORGEJO_OUTPUT + + job2: + needs: [job1] + runs-on: docker + steps: + - run: | + set -x + test "${{ needs.job1.outputs.job1output }}" = "value1" diff --git a/actions/example-post-7-0-schedule/.forgejo/workflows/test.yml b/actions/example-post-7-0-schedule/.forgejo/workflows/test.yml new file mode 100644 index 00000000..94eb4961 --- /dev/null +++ b/actions/example-post-7-0-schedule/.forgejo/workflows/test.yml @@ -0,0 +1,23 @@ +on: + schedule: + - cron: '* * * * *' + +jobs: + test: + runs-on: ${{ vars.TEST_SCHEDULE_RUNSON }} + container: + image: data.forgejo.org/oci/debian:trixie + options: "--volume /srv/example:/srv/example" + + steps: + - name: save context + run: | + d=/srv/example/post-7-0-schedule/contexts/$FORGEJO_EVENT_NAME + mkdir -p $d + cat > $d/github <<'EOF' + ${{ toJSON(github) }} + EOF + + - run: | + echo "TEST_SCHEDULE_RUNSON=${{ vars.TEST_SCHEDULE_RUNSON }}" + touch /srv/example/post-7-0-schedule-volume/DONE diff --git a/actions/example-post-7-0-schedule/run.sh b/actions/example-post-7-0-schedule/run.sh new file mode 100755 index 00000000..29617c17 --- /dev/null +++ b/actions/example-post-7-0-schedule/run.sh @@ -0,0 +1,30 @@ +forgejo-test-helper.sh push_workflow actions/example-$example $url root example-$example setup-forgejo $token + +forgejo-curl.sh web -X POST http://${HOST_PORT}/admin/actions/variables/1/delete || true +forgejo-curl.sh web --form name=TEST_SCHEDULE_RUNSON --form data=docker http://${HOST_PORT}/admin/actions/variables/new + +# +# Verify that creating a new branch with the same SHA as the default branch +# does not change the ref associated with the schedule +# +# See https://codeberg.org/forgejo/forgejo/pulls/1941 for more information +# +function verify_ref() { + local ref=$(sqlite3 $DIR/forgejo-work-path/forgejo.db 'select ref from action_schedule') + test "${ref##*/}" = "main" +} +verify_ref +api=$url/api/v1 +forgejo-curl.sh api_json --data '{"new_branch_name":"zzzz"}' $api/repos/root/example-post-7-0-schedule/branches +verify_ref + +# runs once per minute, give it three minutes max before declaring failure +if ! RETRY_DELAYS="30 30 30 30 30 30" forgejo.sh retry test -f /srv/example/post-7-0-schedule-volume/DONE; then + cat $FORGEJO_RUNNER_LOGS + false +fi + +c=/srv/example/post-7-0-schedule/contexts/schedule/github +cat $c +test "schedule" = "$(jq -r .event_name <$c)" +test "schedule" = "$(jq -r .event.action <$c)" diff --git a/actions/example-post-7-0-schedule/setup.sh b/actions/example-post-7-0-schedule/setup.sh new file mode 100755 index 00000000..5592dbeb --- /dev/null +++ b/actions/example-post-7-0-schedule/setup.sh @@ -0,0 +1 @@ +mkdir -p /srv/example/post-7-0-schedule-volume diff --git a/actions/example-private-workflow-call/.forgejo/workflows/reusable.yaml b/actions/example-private-workflow-call/.forgejo/workflows/reusable.yaml new file mode 100644 index 00000000..48832449 --- /dev/null +++ b/actions/example-private-workflow-call/.forgejo/workflows/reusable.yaml @@ -0,0 +1,10 @@ +on: + workflow_call: + +jobs: + build: + runs-on: "docker" + container: + image: data.forgejo.org/oci/node:24-trixie + steps: + - run: echo 'OK' diff --git a/actions/example-private-workflow-call/.forgejo/workflows/test.yaml b/actions/example-private-workflow-call/.forgejo/workflows/test.yaml new file mode 100644 index 00000000..9bb279b3 --- /dev/null +++ b/actions/example-private-workflow-call/.forgejo/workflows/test.yaml @@ -0,0 +1,11 @@ +on: + push: + +jobs: + test: + # `runs-on` disables workflow expansion. We want that in this case, because then Forgejo Runner has to authenticate + # itself to access the reusable workflow. + runs-on: docker + container: + image: data.forgejo.org/oci/node:24-trixie + uses: ./.forgejo/workflows/reusable.yaml diff --git a/actions/example-private-workflow-call/run.sh b/actions/example-private-workflow-call/run.sh new file mode 100644 index 00000000..e71dc991 --- /dev/null +++ b/actions/example-private-workflow-call/run.sh @@ -0,0 +1,42 @@ +api="$url/api/v1" +export d=/srv/example/private-workflow-call + +function main() { + mkdir -p "$d" + + local repo + repo="root/example-$example" + + forgejo-test-helper.sh push_workflow "actions/example-$example" "$url" root "example-$example" setup-forgejo "$token" + + # push_workflow creates the repository and triggers a first workflow run. Wait for it to succeed. Ensures that the + # workflow is valid. + local sha + sha="$(forgejo-test-helper.sh branch_tip "$url" "$repo" main)" + forgejo-test-helper.sh wait_success "$url" "$repo" "$sha" + + # Make the repository private. That is necessary to verify that Forgejo Runner includes the correct credentials when + # cloning the workflow. + forgejo-curl.sh api_json -X PATCH --data-raw '{"private":true}' "$api/repos/root/example-$example" + + # Create a new commit that triggers a new workflow run that can be identified uniquely. + ( + cd "$d" || exit 1 + git clone "$url/root/example-$example" + cd "example-$example" || exit 1 + git config user.email root@example.com + git config user.name username + echo "A new file" > test.txt + git add . + git commit -m 'Commit a new file' + git push + ) + + # Wait for the workflow pulled from the private repository to succeed. + local new_sha + new_sha="$(forgejo-test-helper.sh branch_tip "$url" "$repo" main)" + [[ "$new_sha" != "$sha" ]] || exit 1 + forgejo-test-helper.sh wait_success "$url" "$repo" "$new_sha" +} + +main diff --git a/actions/example-private-workflow-call/setup.sh b/actions/example-private-workflow-call/setup.sh new file mode 100644 index 00000000..fd443948 --- /dev/null +++ b/actions/example-private-workflow-call/setup.sh @@ -0,0 +1 @@ +mkdir -p /srv/example/private-workflow-call diff --git a/actions/example-pull-request/.forgejo/workflows/test.yml b/actions/example-pull-request/.forgejo/workflows/test.yml index 772a38f8..34a915a0 100644 --- a/actions/example-pull-request/.forgejo/workflows/test.yml +++ b/actions/example-pull-request/.forgejo/workflows/test.yml @@ -9,7 +9,7 @@ jobs: test: runs-on: docker container: - image: code.forgejo.org/oci/node:20-bookworm + image: data.forgejo.org/oci/node:20-bookworm options: "--volume /srv/example:/srv/example" steps: @@ -17,45 +17,45 @@ jobs: shell: bash run: | set -x - test $GITHUB_TOKEN = ${{ env.GITHUB_TOKEN }} - test $GITHUB_TOKEN = ${{ github.token }} + test $FORGEJO_TOKEN = ${{ env.FORGEJO_TOKEN }} + test $FORGEJO_TOKEN = ${{ forgejo.token }} export DEBIAN_FRONTEND=noninteractive ; apt-get -qq update ; apt-get install -y -qq curl git >& /dev/null curl -sS -o /usr/local/bin/forgejo-curl.sh https://code.forgejo.org/forgejo/forgejo-curl/raw/branch/main/forgejo-curl.sh && chmod +x /usr/local/bin/forgejo-curl.sh - forgejo-curl.sh --token "$GITHUB_TOKEN" login $GITHUB_SERVER_URL - forgejo-curl.sh api_json $GITHUB_SERVER_URL/api/v1/user + forgejo-curl.sh --token "$FORGEJO_TOKEN" login $FORGEJO_SERVER_URL + forgejo-curl.sh api_json $FORGEJO_SERVER_URL/api/v1/user - name: determine if the PR is from a fork id: forked run: | - if test ${{ github.event.pull_request.base.repo.full_name }} = ${{ github.event.pull_request.head.repo.full_name }} ; then - echo value=false >> $GITHUB_OUTPUT + if test ${{ forgejo.event.pull_request.base.repo.full_name }} = ${{ forge.event.pull_request.head.repo.full_name }} ; then + echo value=false >> $FORGEJO_OUTPUT else - echo value=true >> $GITHUB_OUTPUT + echo value=true >> $FORGEJO_OUTPUT fi # See also actions/example-context/.forgejo/workflows/test.yml - - name: env.GITHUB_BASE_REF + - name: env.FORGEJO_BASE_REF run: | set -x - test "$GITHUB_BASE_REF" = main - test "$GITHUB_BASE_REF" = "${{ env.GITHUB_BASE_REF }}" + test "$FORGEJO_BASE_REF" = main + test "$FORGEJO_BASE_REF" = "${{ env.FORGEJO_BASE_REF }}" # See also actions/example-context/.forgejo/workflows/test.yml - - name: env.GITHUB_HEAD_REF + - name: env.FORGEJO_HEAD_REF run: | set -x if ${{ steps.forked.outputs.value }} ; then - test "$GITHUB_HEAD_REF" = main + test "$FORGEJO_HEAD_REF" = main else - test "$GITHUB_HEAD_REF" = other + test "$FORGEJO_HEAD_REF" = other fi - test "$GITHUB_HEAD_REF" = "${{ env.GITHUB_HEAD_REF }}" + test "$FORGEJO_HEAD_REF" = "${{ env.FORGEJO_HEAD_REF }}" - name: secrets shell: bash run: | set -x - case $GITHUB_EVENT_NAME in + case $FORGEJO_EVENT_NAME in pull_request_target) # # all PRs: secrets @@ -76,7 +76,7 @@ jobs: fi ;; *) - echo unexpected event $GITHUB_EVENT_NAME + echo unexpected event $FORGEJO_EVENT_NAME false ;; esac @@ -95,9 +95,9 @@ jobs: # # create an issue # - base_repo=${{ github.event.pull_request.base.repo.full_name }} - forgejo-curl.sh api_json --data-raw '{"title":"ISSUE"}' $GITHUB_SERVER_URL/api/v1/repos/$base_repo/issues - url=$(echo $GITHUB_SERVER_URL | sed -e "s|://|://$GITHUB_TOKEN@|") + base_repo=${{ forgejo.event.pull_request.base.repo.full_name }} + forgejo-curl.sh api_json --data-raw '{"title":"ISSUE"}' $FORGEJO_SERVER_URL/api/v1/repos/$base_repo/issues + url=$(echo $FORGEJO_SERVER_URL | sed -e "s|://|://$FORGEJO_TOKEN@|") git clone $url/$base_repo base branch=B$RANDOM ( @@ -108,7 +108,7 @@ jobs: echo CHANGE >> README git add . git commit -m 'change' - case $GITHUB_EVENT_NAME in + case $FORGEJO_EVENT_NAME in pull_request_target|pull_request) # # repository write scope via http git passthrough @@ -117,15 +117,15 @@ jobs: # # repository write scope via the API # - assert_fail_if_forked forgejo-curl.sh api_json --data-raw '{"title":"PR","base":"main","head":"'$branch'"}' $GITHUB_SERVER_URL/api/v1/repos/$base_repo/pulls - assert_fail_if_forked forgejo-curl.sh api_json --data-raw '{"color":"#ffffff","name":"labelname"}' $GITHUB_SERVER_URL/api/v1/repos/$base_repo/labels + assert_fail_if_forked forgejo-curl.sh api_json --data-raw '{"title":"PR","base":"main","head":"'$branch'"}' $FORGEJO_SERVER_URL/api/v1/repos/$base_repo/pulls + assert_fail_if_forked forgejo-curl.sh api_json --data-raw '{"color":"#ffffff","name":"labelname"}' $FORGEJO_SERVER_URL/api/v1/repos/$base_repo/labels # # See https://codeberg.org/forgejo/forgejo/issues/1525 # - ! forgejo-curl.sh api_json --data-raw '{"new_branch_name":"B'$RANDOM'"}' $GITHUB_SERVER_URL/api/v1/repos/$base_repo/branches + ! forgejo-curl.sh api_json --data-raw '{"new_branch_name":"B'$RANDOM'"}' $FORGEJO_SERVER_URL/api/v1/repos/$base_repo/branches ;; *) - echo unexpected event $GITHUB_EVENT_NAME + echo unexpected event $FORGEJO_EVENT_NAME false ;; esac @@ -133,17 +133,17 @@ jobs: - name: save event run: | - d=/srv/example/pull-request/contexts/${{ github.event.pull_request.head.repo.owner.username }}/$GITHUB_EVENT_NAME + d=/srv/example/pull-request/contexts/${{ forgejo.event.pull_request.head.repo.owner.username }}/$FORGEJO_EVENT_NAME mkdir -p $d cat > $d/github <<'EOF' ${{ toJSON(github) }} EOF - - uses: https://code.forgejo.org/actions/checkout@v4 + - uses: https://data.forgejo.org/actions/checkout@v4 - name: checkout the default branch if pull_request_target run: | set -x - case $GITHUB_EVENT_NAME in + case $FORGEJO_EVENT_NAME in pull_request_target) ! test -f file-unique-to-the-pr-branch ;; @@ -151,7 +151,7 @@ jobs: test -f file-unique-to-the-pr-branch ;; *) - echo unexpected event $GITHUB_EVENT_NAME + echo unexpected event $FORGEJO_EVENT_NAME false ;; esac diff --git a/actions/example-pull-request/assert-contexts.sh b/actions/example-pull-request/assert-contexts.sh new file mode 100755 index 00000000..83cd6606 --- /dev/null +++ b/actions/example-pull-request/assert-contexts.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -ex + +c=$d/contexts + +test opened = "$(jq -r .event.action <$c/fork-org/pull_request/github)" +test opened = "$(jq -r .event.action <$c/fork-org/pull_request_target/github)" + +test opened = "$(jq -r .event.action <$c/root/pull_request/github)" +test opened = "$(jq -r .event.action <$c/root/pull_request_target/github)" diff --git a/actions/example-pull-request/assert-token.sh b/actions/example-pull-request/assert-token.sh deleted file mode 100755 index 57f02571..00000000 --- a/actions/example-pull-request/assert-token.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -set -ex - -c=$d/contexts - -test opened = "$(jq -r .event.action < $c/fork-org/pull_request/github)" -test opened = "$(jq -r .event.action < $c/fork-org/pull_request_target/github)" - -test opened = "$(jq -r .event.action < $c/root/pull_request/github)" -test opened = "$(jq -r .event.action < $c/root/pull_request_target/github)" diff --git a/actions/example-pull-request/run.sh b/actions/example-pull-request/run.sh index 5ae0baae..de54e37c 100755 --- a/actions/example-pull-request/run.sh +++ b/actions/example-pull-request/run.sh @@ -3,7 +3,7 @@ export d=/srv/example/pull-request PROOF='some proof' -function setup() { +function main() { mkdir -p $d forgejo-test-helper.sh push_workflow actions/example-$example $url root example-$example setup-forgejo $token @@ -12,50 +12,45 @@ function setup() { forgejo-curl.sh api_json --data-raw '{"organization":"fork-org"}' $api/repos/root/example-pull-request/forks forgejo-curl.sh api_json -X PUT --data-raw '{"data":"AAAA"}' $api/repos/root/example-pull-request/actions/secrets/SECRET - ( - cd $d - git clone $url/fork-org/example-pull-request fork - cd fork - git config user.email root@example.com - git config user.name username - echo fork $PROOF >> README - touch file-unique-to-the-pr-branch - git add . - git commit -m 'fork change' - git push + cd $d + git clone $url/fork-org/example-pull-request fork + cd fork + git config user.email root@example.com + git config user.name username + echo fork $PROOF >>README + touch file-unique-to-the-pr-branch + git add . + git commit -m 'fork change' + git push ) forgejo.sh retry forgejo-curl.sh api_json --data-raw '{"title":"PR from fork","base":"main","head":"fork-org:main"}' $api/repos/root/example-pull-request/pulls ( - cd $d - git clone $url/root/example-pull-request - cd example-pull-request - git checkout -b other - git config user.email root@example.com - git config user.name username - touch file-unique-to-the-pr-branch - echo other $PROOF >> README - git add . - git commit -m 'other change' - git push --force -u origin other + cd $d + git clone $url/root/example-pull-request + cd example-pull-request + git checkout -b other + git config user.email root@example.com + git config user.name username + touch file-unique-to-the-pr-branch + echo other $PROOF >>README + git add . + git commit -m 'other change' + git push --force -u origin other ) forgejo.sh retry forgejo-curl.sh api_json --data-raw '{"title":"PR same repo","base":"main","head":"other"}' $api/repos/root/example-pull-request/pulls export RETRY_DELAYS="60 60 60 60 60 60 60" - for assert in $EXAMPLE_DIR/assert-*.sh ; do - if ! forgejo.sh retry $assert ; then - find $d - sed -e 's/^/[RUNNER LOGS]/' < $FORGEJO_RUNNER_LOGS - false - fi + for assert in $EXAMPLE_DIR/assert-*.sh; do + if ! forgejo.sh retry $assert; then + find $d + sed -e 's/^/[RUNNER LOGS]/' <$FORGEJO_RUNNER_LOGS + false + fi done } -function main() { - setup -} - main diff --git a/actions/example-pull-request/setup.sh b/actions/example-pull-request/setup.sh index 72c13c02..5f469629 100755 --- a/actions/example-pull-request/setup.sh +++ b/actions/example-pull-request/setup.sh @@ -1,2 +1 @@ mkdir -p /srv/example/pull-request - diff --git a/actions/example-push-cancel/run.sh b/actions/example-push-cancel/run.sh index 37ed9d38..891798ed 100755 --- a/actions/example-push-cancel/run.sh +++ b/actions/example-push-cancel/run.sh @@ -11,8 +11,8 @@ forgejo-test-helper.sh wait_running $url $repo $sha # # push to the same branch # -forgejo-test-helper.sh push_workflow actions/example-$example $url root example-$example setup-forgejo $token +forgejo-test-helper.sh push_workflow actions/example-echo $url root example-$example setup-forgejo $token # -# wait for the workflow to be canceld as a result of the previous push +# wait for the workflow to be canceled as a result of the previous push # forgejo-test-helper.sh wait_failure $url $repo $sha 'Has been cancelled' diff --git a/actions/example-push/.forgejo/workflows/test.yml b/actions/example-push/.forgejo/workflows/test.yml index 89763f29..ebf53d1b 100644 --- a/actions/example-push/.forgejo/workflows/test.yml +++ b/actions/example-push/.forgejo/workflows/test.yml @@ -9,14 +9,14 @@ jobs: test: runs-on: docker container: - image: code.forgejo.org/oci/node:20-bookworm + image: data.forgejo.org/oci/node:20-bookworm volumes: - /srv/example:/srv/example steps: - name: save event run: | - d=/srv/example/push/contexts/$GITHUB_EVENT_NAME + d=/srv/example/push/contexts/$FORGEJO_EVENT_NAME mkdir -p $d cat > $d/github <<'EOF' ${{ toJSON(github) }} diff --git a/actions/example-schedule-noncancel/.forgejo/workflows/schedule_continue.yml b/actions/example-schedule-noncancel/.forgejo/workflows/schedule_continue.yml new file mode 100644 index 00000000..7cc5bdb3 --- /dev/null +++ b/actions/example-schedule-noncancel/.forgejo/workflows/schedule_continue.yml @@ -0,0 +1,15 @@ +on: + schedule: + - cron: "* * * * *" +jobs: + test: + runs-on: docker + container: + image: data.forgejo.org/oci/debian:trixie + volumes: + - /srv/example:/srv/example + steps: + - run: | + while ! [ -f /srv/example/schedule-noncancel/PUSHED ]; do + sleep 3 + done diff --git a/actions/example-schedule-noncancel/run.sh b/actions/example-schedule-noncancel/run.sh new file mode 100755 index 00000000..b3756bf9 --- /dev/null +++ b/actions/example-schedule-noncancel/run.sh @@ -0,0 +1,99 @@ +repo=root/example-$example +# +# delete the repository +# +api=$url/api/v1 +if forgejo-curl.sh api_json -X GET $api/repos/root/example-$example; then + forgejo-curl.sh api_json -X DELETE $api/repos/root/example-$example +fi + +# +# push the repository +# +forgejo-test-helper.sh push_workflow actions/example-$example $url root example-$example setup-forgejo $token + +# +# get the run id of the workflow that just started +# +getScheduleRun() { + rm -f $DIR/forgejo-work-path/forgejo.copy.db + cp $DIR/forgejo-work-path/forgejo.db $DIR/forgejo-work-path/forgejo.copy.db + sqlite3 $DIR/forgejo-work-path/forgejo.copy.db \ + "pragma busy_timeout = 5000; \ + select action_run.id \ + from action_run \ + inner join action_schedule on action_run.schedule_id = action_schedule.id \ + inner join repository on action_schedule.repo_id = repository.id \ + where repository.name = 'example-schedule-noncancel' \ + order by action_run.created desc limit 1" | sed '2q;d' +} + +run_id=$(getScheduleRun) +while [ -z $run_id ]; do + echo waiting 5... + sleep 5 + run_id=$(getScheduleRun) +done + +echo Schedule run id: $run_id + +# +# Wait for it to be started +# +checkStarted() { + rm -f $DIR/forgejo-work-path/forgejo.copy.db + cp $DIR/forgejo-work-path/forgejo.db $DIR/forgejo-work-path/forgejo.copy.db + sqlite3 $DIR/forgejo-work-path/forgejo.copy.db \ + "pragma busy_timeout = 5000; \ + select id \ + from action_run \ + where id = $run_id \ + and started is not null" | sed '2q;d' +} + +started_check=$(checkStarted) +while [ -z $started_check ]; do + echo waiting 2... + sleep 2 + started_check=$(checkStarted) +done + +echo Run has started +echo Push to repo again + +# +# Push to the repo again +# +forgejo-test-helper.sh push_workflow actions/example-echo $url root example-$example setup-forgejo $token + +echo Signal to the workflow that the push has happened +mkdir -p /srv/example/schedule-noncancel +touch /srv/example/schedule-noncancel/PUSHED + +# +# Wait for the workflow to finish anyway +# +echo Wait for workflow to finish + +checkFinished() { + rm -f $DIR/forgejo-work-path/forgejo.copy.db + cp $DIR/forgejo-work-path/forgejo.db $DIR/forgejo-work-path/forgejo.copy.db + sqlite3 $DIR/forgejo-work-path/forgejo.copy.db \ + "pragma busy_timeout = 5000; \ + select status \ + from action_run \ + where id = $run_id \ + and (status != 6 and status != 5)" | sed '2q;d' +} + +finished_status=$(checkFinished) +while [ -z $finished_status ]; do + echo waiting 5... + sleep 5 + finished_status=$(checkFinished) +done + +echo Workflow finished. +rm -f $DIR/forgejo-work-path/forgejo.copy.db + +test $finished_status = 1 diff --git a/actions/example-schedule-noncancel/teardown.sh b/actions/example-schedule-noncancel/teardown.sh new file mode 100644 index 00000000..ae9987a3 --- /dev/null +++ b/actions/example-schedule-noncancel/teardown.sh @@ -0,0 +1,4 @@ +# +# this will effectively discard any linger workflow so they do not interfere with other tests +# +forgejo-runner.sh reload diff --git a/actions/example-service/.forgejo/workflows/test.yml b/actions/example-service/.forgejo/workflows/test.yml index 438203c6..11132c96 100644 --- a/actions/example-service/.forgejo/workflows/test.yml +++ b/actions/example-service/.forgejo/workflows/test.yml @@ -2,16 +2,32 @@ on: [push] jobs: # - # No volume involved + # No volume involved & the container is implicit + # + simple-no-container: + runs-on: docker + services: + pgsql: + image: data.forgejo.org/oci/postgres:15 + env: + POSTGRES_DB: test + POSTGRES_PASSWORD: postgres + steps: + - run: | + apt-get update -qq + apt-get install -y -qq postgresql-client + PGPASSWORD=postgres psql -h pgsql -U postgres -c '\dt' test + # + # No volume involved & the container is explicit # simple: runs-on: docker container: - image: code.forgejo.org/oci/debian:bookworm + image: data.forgejo.org/oci/debian:trixie services: pgsql: - image: code.forgejo.org/oci/postgres:15 + image: data.forgejo.org/oci/postgres:15 env: POSTGRES_DB: test POSTGRES_PASSWORD: postgres @@ -27,7 +43,7 @@ jobs: needs: [simple] runs-on: docker container: - image: code.forgejo.org/oci/debian:bookworm + image: data.forgejo.org/oci/debian:trixie options: "--volume /srv/example-service-volume-valid:/srv/example-service-volume-valid --volume /srv/example-service-volume-invalid:/srv/example-service-volume-invalid" steps: @@ -42,12 +58,12 @@ jobs: needs: [volume-on-step] runs-on: docker container: - image: code.forgejo.org/oci/debian:bookworm + image: data.forgejo.org/oci/debian:trixie options: "--volume /srv/example-service-volume-valid:/srv/example-service-volume-valid" services: myservice: - image: code.forgejo.org/oci/debian:bookworm + image: data.forgejo.org/oci/debian:trixie options: "--volume /srv/example-service-volume-valid:/srv/example-service-volume-valid" cmd: ["bash", "-c", "echo -n SUCCESS > /srv/example-service-volume-valid ; sleep infinity"] diff --git a/actions/example-service/runner-config.yaml b/actions/example-service/runner-config.yaml index 27981abe..c931a240 100644 --- a/actions/example-service/runner-config.yaml +++ b/actions/example-service/runner-config.yaml @@ -1,6 +1,6 @@ log: - level: info + level: debug runner: file: .runner diff --git a/actions/example-service/setup.sh b/actions/example-service/setup.sh index 3a9674ef..7bc1672a 100755 --- a/actions/example-service/setup.sh +++ b/actions/example-service/setup.sh @@ -1,3 +1,3 @@ -> /srv/example-service-volume-valid -> /srv/example-service-volume-invalid +>/srv/example-service-volume-valid +>/srv/example-service-volume-invalid FORGEJO_RUNNER_CONFIG=$EXAMPLE_DIR/runner-config.yaml forgejo-runner.sh reload diff --git a/actions/example-shell/.forgejo/workflows/test.yml b/actions/example-shell/.forgejo/workflows/test.yml new file mode 100644 index 00000000..5dad0b6e --- /dev/null +++ b/actions/example-shell/.forgejo/workflows/test.yml @@ -0,0 +1,87 @@ +on: [push] + +env: + ASSERT_SHELL: 'set -x ; readlink /proc/$$/exe ; readlink /proc/$$/exe | grep ' + +jobs: + default: + # docker:docker://code.forgejo.org/oci/node:22-bookworm + runs-on: docker + steps: + - name: default is bash + run: | + ${{ env.ASSERT_SHELL }} /bash + + sh-fallback: + needs: [default] + # alpine:docker://code.forgejo.org/oci/alpine:latest + runs-on: alpine + steps: + - name: default is bash but with a fallback to sh in case it does not exist + run: | + ${{ env.ASSERT_SHELL }} /busybox + + sh-fallback-with-container: + needs: [sh-fallback] + runs-on: docker + container: + image: data.forgejo.org/oci/alpine:latest + steps: + - name: default is bash but with a fallback to sh in case it does not exist + run: | + ${{ env.ASSERT_SHELL }} /busybox + + defaults-run: + needs: [sh-fallback-with-container] + # alpine:docker://code.forgejo.org/oci/alpine:latest + runs-on: alpine + defaults: + run: + shell: sh + steps: + - name: default is sh which is an alias for busybox in alpine + run: | + ${{ env.ASSERT_SHELL }} /busybox + + python: + needs: [alpine] + runs-on: docker + container: + image: data.forgejo.org/oci/python:slim + steps: + - name: python => python {0} + shell: python + run: | + print("something") + + other: + needs: [python] + runs-on: docker + container: + image: data.forgejo.org/oci/node:22-bookworm + steps: + - name: default is bash + run: | + ${{ env.ASSERT_SHELL }} /bash + + - name: bash => bash --noprofile --norc -e -o pipefail {0} + shell: bash + run: | + ${{ env.ASSERT_SHELL }} /bash + shopt -o + shopt -o | grep --quiet 'pipefail.*on' + + - name: sh => sh -e {0} + shell: sh + run: | + ${{ env.ASSERT_SHELL }} /dash + + - name: node => node {0} + shell: node + run: | + console.log("something") + + - name: dash -e {0} + shell: dash -e {0} + run: | + ${{ env.ASSERT_SHELL }} /dash diff --git a/actions/example-shell/runner-config.yaml b/actions/example-shell/runner-config.yaml new file mode 100644 index 00000000..4e4974d2 --- /dev/null +++ b/actions/example-shell/runner-config.yaml @@ -0,0 +1,32 @@ + +log: + level: debug + +runner: + file: .runner + capacity: 1 + env_file: .env + timeout: 3h + insecure: false + fetch_timeout: 5s + fetch_interval: 2s + labels: + - docker:docker://code.forgejo.org/oci/node:22-bookworm + - alpine:docker://code.forgejo.org/oci/alpine:latest + +cache: + enabled: false + dir: "" + host: "" + port: 0 + +container: + network: "" + privileged: false + options: + workdir_parent: + valid_volumes: [] + docker_host: "" + +host: + workdir_parent: diff --git a/actions/example-shell/setup.sh b/actions/example-shell/setup.sh new file mode 100755 index 00000000..9c1f5adf --- /dev/null +++ b/actions/example-shell/setup.sh @@ -0,0 +1 @@ +FORGEJO_RUNNER_CONFIG=$EXAMPLE_DIR/runner-config.yaml forgejo-runner.sh reload diff --git a/actions/example-shell/teardown.sh b/actions/example-shell/teardown.sh new file mode 100755 index 00000000..b410c513 --- /dev/null +++ b/actions/example-shell/teardown.sh @@ -0,0 +1 @@ +forgejo-runner.sh reload diff --git a/actions/example-tag/.forgejo/workflows/test.yml b/actions/example-tag/.forgejo/workflows/test.yml index c7e13570..1a2e4b91 100644 --- a/actions/example-tag/.forgejo/workflows/test.yml +++ b/actions/example-tag/.forgejo/workflows/test.yml @@ -7,14 +7,14 @@ jobs: test: runs-on: docker container: - image: code.forgejo.org/oci/node:20-bookworm + image: data.forgejo.org/oci/node:20-bookworm volumes: - /srv/example:/srv/example steps: - name: save event run: | - d=/srv/example/tag/contexts/$GITHUB_EVENT_NAME + d=/srv/example/tag/contexts/$FORGEJO_EVENT_NAME mkdir -p $d cat > $d/github <<'EOF' ${{ toJSON(github) }} diff --git a/actions/example-with-docker-host/.forgejo/workflows/test.yml b/actions/example-with-docker-host/.forgejo/workflows/test.yml new file mode 100644 index 00000000..454a10da --- /dev/null +++ b/actions/example-with-docker-host/.forgejo/workflows/test.yml @@ -0,0 +1,10 @@ +on: [push] + +jobs: + build: + runs-on: docker + container: + image: data.forgejo.org/oci/docker:28-cli + steps: + - run: ls -l /var/run/docker.sock + - run: docker ps diff --git a/actions/example-with-docker-host/runner-config.yaml b/actions/example-with-docker-host/runner-config.yaml new file mode 100644 index 00000000..839de20b --- /dev/null +++ b/actions/example-with-docker-host/runner-config.yaml @@ -0,0 +1,30 @@ + +log: + level: debug + +runner: + file: .runner + capacity: 1 + env_file: .env + timeout: 3h + insecure: false + fetch_timeout: 5s + fetch_interval: 2s + labels: ["docker:docker://code.forgejo.org/oci/node:20-bookworm"] + +cache: + enabled: true + dir: "/srv/example/cache" + host: "" + port: 0 + +container: + network: "bridge" + privileged: false + options: + workdir_parent: + valid_volumes: ["/srv/example"] + docker_host: "unix:///var/run/docker.sock" + +host: + workdir_parent: diff --git a/actions/example-with-docker-host/setup.sh b/actions/example-with-docker-host/setup.sh new file mode 100755 index 00000000..9c1f5adf --- /dev/null +++ b/actions/example-with-docker-host/setup.sh @@ -0,0 +1 @@ +FORGEJO_RUNNER_CONFIG=$EXAMPLE_DIR/runner-config.yaml forgejo-runner.sh reload diff --git a/actions/example-with-docker-host/teardown.sh b/actions/example-with-docker-host/teardown.sh new file mode 100755 index 00000000..b410c513 --- /dev/null +++ b/actions/example-with-docker-host/teardown.sh @@ -0,0 +1 @@ +forgejo-runner.sh reload diff --git a/actions/example-with-docker-socket/.forgejo/workflows/test.yml b/actions/example-with-docker-socket/.forgejo/workflows/test.yml new file mode 100644 index 00000000..454a10da --- /dev/null +++ b/actions/example-with-docker-socket/.forgejo/workflows/test.yml @@ -0,0 +1,10 @@ +on: [push] + +jobs: + build: + runs-on: docker + container: + image: data.forgejo.org/oci/docker:28-cli + steps: + - run: ls -l /var/run/docker.sock + - run: docker ps diff --git a/actions/example-with-docker-socket/runner-config.yaml b/actions/example-with-docker-socket/runner-config.yaml new file mode 100644 index 00000000..e09edaaa --- /dev/null +++ b/actions/example-with-docker-socket/runner-config.yaml @@ -0,0 +1,30 @@ + +log: + level: debug + +runner: + file: .runner + capacity: 1 + env_file: .env + timeout: 3h + insecure: false + fetch_timeout: 5s + fetch_interval: 2s + labels: ["docker:docker://code.forgejo.org/oci/node:20-bookworm"] + +cache: + enabled: true + dir: "/srv/example/cache" + host: "" + port: 0 + +container: + network: "bridge" + privileged: false + options: + workdir_parent: + valid_volumes: ["/srv/example"] + docker_host: "automount" + +host: + workdir_parent: diff --git a/actions/example-with-docker-socket/setup.sh b/actions/example-with-docker-socket/setup.sh new file mode 100755 index 00000000..9c1f5adf --- /dev/null +++ b/actions/example-with-docker-socket/setup.sh @@ -0,0 +1 @@ +FORGEJO_RUNNER_CONFIG=$EXAMPLE_DIR/runner-config.yaml forgejo-runner.sh reload diff --git a/actions/example-with-docker-socket/teardown.sh b/actions/example-with-docker-socket/teardown.sh new file mode 100755 index 00000000..b410c513 --- /dev/null +++ b/actions/example-with-docker-socket/teardown.sh @@ -0,0 +1 @@ +forgejo-runner.sh reload diff --git a/actions/example-with-docker-tcp/.forgejo/workflows/test.yml b/actions/example-with-docker-tcp/.forgejo/workflows/test.yml new file mode 100644 index 00000000..c4388ae8 --- /dev/null +++ b/actions/example-with-docker-tcp/.forgejo/workflows/test.yml @@ -0,0 +1,11 @@ +on: [push] + +jobs: + build: + runs-on: docker + container: + image: data.forgejo.org/oci/node:20-bookworm + steps: + - run: | + ! test -e /var/run/docker.sock + ! env | grep DOCKER_HOST diff --git a/actions/example-with-docker-tcp/runner-config.yaml b/actions/example-with-docker-tcp/runner-config.yaml new file mode 100644 index 00000000..730d9c88 --- /dev/null +++ b/actions/example-with-docker-tcp/runner-config.yaml @@ -0,0 +1,30 @@ + +log: + level: debug + +runner: + file: .runner + capacity: 1 + env_file: .env + timeout: 3h + insecure: false + fetch_timeout: 5s + fetch_interval: 2s + labels: ["docker:docker://code.forgejo.org/oci/node:20-bookworm"] + +cache: + enabled: true + dir: "/srv/example/cache" + host: "" + port: 0 + +container: + network: "bridge" + privileged: false + options: + workdir_parent: + valid_volumes: ["/srv/example"] + docker_host: "tcp://127.0.0.1:2375" + +host: + workdir_parent: diff --git a/actions/example-with-docker-tcp/setup.sh b/actions/example-with-docker-tcp/setup.sh new file mode 100755 index 00000000..9c1f5adf --- /dev/null +++ b/actions/example-with-docker-tcp/setup.sh @@ -0,0 +1 @@ +FORGEJO_RUNNER_CONFIG=$EXAMPLE_DIR/runner-config.yaml forgejo-runner.sh reload diff --git a/actions/example-with-docker-tcp/teardown.sh b/actions/example-with-docker-tcp/teardown.sh new file mode 100755 index 00000000..b410c513 --- /dev/null +++ b/actions/example-with-docker-tcp/teardown.sh @@ -0,0 +1 @@ +forgejo-runner.sh reload diff --git a/actions/example-without-docker-socket/.forgejo/workflows/test.yml b/actions/example-without-docker-socket/.forgejo/workflows/test.yml new file mode 100644 index 00000000..8d5c8371 --- /dev/null +++ b/actions/example-without-docker-socket/.forgejo/workflows/test.yml @@ -0,0 +1,6 @@ +on: [push] +jobs: + test: + runs-on: docker + steps: + - run: "! test -e /var/run/docker.sock" diff --git a/actions/example-workflow-call-expansion/.forgejo/workflows/reusable-layer-1.yml b/actions/example-workflow-call-expansion/.forgejo/workflows/reusable-layer-1.yml new file mode 100644 index 00000000..649392c1 --- /dev/null +++ b/actions/example-workflow-call-expansion/.forgejo/workflows/reusable-layer-1.yml @@ -0,0 +1,74 @@ +on: + workflow_call: + inputs: + input1: + required: true + type: string + input3: + required: true + type: string + outputs: + output1: + value: ${{ jobs.callee-1.outputs.job-output }} + output2: + value: ${{ jobs.callee-2.outputs.job-output }} + output3: + value: ${{ jobs.layer-2.outputs.output3 }} + output4: + value: ${{ jobs.layer-2.outputs.output4 }} + +jobs: + callee-1: + runs-on: docker + outputs: + job-output: callee-1-output + container: + image: data.forgejo.org/oci/node:22-bookworm + volumes: + - /srv/example:/srv/example + steps: + - name: verify workflow inputs + run: | + set -x + test "top-level-input1" = "${{ inputs.input1 }}" + test "dynamic output" = "${{ inputs.input3 }}" + - name: verify workflow secrets + run: | + set -x + test "AAAA" = "${{ secrets.secret1 }}" + test "BBBB1234" = "${{ secrets.secret2 }}" + test "" = "${{ secrets.secret3 }}" # wasn't specified to the workflow, should be absent + - name: indicate callee-1 hit + run: touch /srv/example/callee-1 + + layer-2: + needs: [callee-1] + uses: ./.forgejo/workflows/reusable-layer-2.yml + with: + input1: ${{ inputs.input1 }} + input2: mid-level-input2 + input3: ${{ inputs.input3 }} + input4: ${{ needs.callee-1.outputs.job-output }} + secrets: inherit + + callee-2: + needs: [callee-1, layer-2] + runs-on: docker + outputs: + job-output: callee-2-output + container: + image: data.forgejo.org/oci/node:22-bookworm + volumes: + - /srv/example:/srv/example + steps: + - name: verify callee-1 completed + run: | + set -x + test -f /srv/example/callee-1 + - name: verify layer-2 completed + run: | + set -x + test -f /srv/example/callee-3 + test -f /srv/example/callee-4 + - name: indicate callee-2 hit + run: touch /srv/example/callee-2 diff --git a/actions/example-workflow-call-expansion/.forgejo/workflows/reusable-layer-2.yml b/actions/example-workflow-call-expansion/.forgejo/workflows/reusable-layer-2.yml new file mode 100644 index 00000000..3b633ebd --- /dev/null +++ b/actions/example-workflow-call-expansion/.forgejo/workflows/reusable-layer-2.yml @@ -0,0 +1,63 @@ +on: + workflow_call: + inputs: + input1: + required: true + type: string + input2: + required: true + type: string + input3: + required: true + type: string + input4: + required: true + type: string + outputs: + output3: + value: ${{ jobs.callee-3.outputs.job-output }} + output4: + value: ${{ jobs.callee-4.outputs.job-output }} + +jobs: + callee-3: + runs-on: docker + outputs: + job-output: callee-3-output + container: + image: data.forgejo.org/oci/node:22-bookworm + volumes: + - /srv/example:/srv/example + steps: + - name: verify workflow inputs + run: | + set -x + test "top-level-input1" = "${{ inputs.input1 }}" + test "mid-level-input2" = "${{ inputs.input2 }}" + test "dynamic output" = "${{ inputs.input3 }}" + test "callee-1-output" = "${{ inputs.input4 }}" + - name: verify workflow secrets inherited + run: | + set -x + test "AAAA" = "${{ secrets.secret1 }}" + test "BBBB1234" = "${{ secrets.secret2 }}" + test "" = "${{ secrets.secret3 }}" # wasn't specified to the workflow, should be absent + - name: indicate callee-3 hit + run: touch /srv/example/callee-3 + + callee-4: + needs: callee-3 + runs-on: docker + outputs: + job-output: callee-4-output + container: + image: data.forgejo.org/oci/node:22-bookworm + volumes: + - /srv/example:/srv/example + steps: + - name: verify callee-3 completed + run: | + set -x + test -f /srv/example/callee-3 + - name: indicate callee-4 hit + run: touch /srv/example/callee-4 diff --git a/actions/example-workflow-call-expansion/.forgejo/workflows/test.yml b/actions/example-workflow-call-expansion/.forgejo/workflows/test.yml new file mode 100644 index 00000000..cd9290a2 --- /dev/null +++ b/actions/example-workflow-call-expansion/.forgejo/workflows/test.yml @@ -0,0 +1,53 @@ +on: + push: + +jobs: + pre-job: + runs-on: docker + container: + image: data.forgejo.org/oci/node:22-bookworm + outputs: + dynamic: "${{ steps.dynamic-step.outputs.dynamic }}" + steps: + - id: dynamic-step + run: echo "dynamic=dynamic output" >> $FORGEJO_OUTPUT + + layer-1: + needs: [pre-job] + uses: ./.forgejo/workflows/reusable-layer-1.yml + with: + input1: top-level-input1 + input3: ${{ needs.pre-job.outputs.dynamic }} + secrets: + secret1: AAAA + secret2: BBBB1234 + + verify: + needs: [layer-1] + runs-on: docker + container: + image: data.forgejo.org/oci/node:22-bookworm + volumes: + - /srv/example:/srv/example + steps: + - name: verify test config secret + run: | + set -x + # SECRET3 is set on the repo, but not passed into `reusable-layer-1.yml` so that we can test secrets don't + # leak into the workflow if they're not explicitly defined. This check verifies that the test environment has + # that secret, otherwise the test assertions that it isn't present within the workflow would be meaningless. + test "CCCC" = "${{ secrets.secret3 }}" + - name: verify callee-[0-4] completed + run: | + set -x + test -f /srv/example/callee-1 + test -f /srv/example/callee-2 + test -f /srv/example/callee-3 + test -f /srv/example/callee-4 + - name: verify workflow outputs + run: | + set -x + test "callee-1-output" = "${{ needs.layer-1.outputs.output1 }}" + test "callee-2-output" = "${{ needs.layer-1.outputs.output2 }}" + test "callee-3-output" = "${{ needs.layer-1.outputs.output3 }}" + test "callee-4-output" = "${{ needs.layer-1.outputs.output4 }}" diff --git a/actions/example-workflow-call-expansion/run.sh b/actions/example-workflow-call-expansion/run.sh new file mode 100644 index 00000000..07ca4cb7 --- /dev/null +++ b/actions/example-workflow-call-expansion/run.sh @@ -0,0 +1,12 @@ +repo=root/example-$example +api=$url/api/v1 + +# Prepare test repo +forgejo-test-helper.sh push_workflow actions/example-$example $url root example-$example setup-forgejo $token +sha=$(forgejo-test-helper.sh branch_tip $url $repo main) + +# Install a repo secret +forgejo-curl.sh api_json -X PUT --data-raw '{"data":"CCCC"}' $api/repos/$repo/actions/secrets/SECRET3 + +# Wait for action to complete +forgejo-test-helper.sh wait_success $url root/example-$example $sha diff --git a/actions/example-workflow-call/.forgejo/workflows/reusable.yml b/actions/example-workflow-call/.forgejo/workflows/reusable.yml new file mode 100644 index 00000000..6181aff6 --- /dev/null +++ b/actions/example-workflow-call/.forgejo/workflows/reusable.yml @@ -0,0 +1,35 @@ +on: + workflow_call: + inputs: + parameter1: + required: true + type: string + outputs: + output1: + value: ${{ jobs.callee.outputs.job-output }} + +jobs: + callee: + runs-on: docker + container: + image: data.forgejo.org/oci/node:22-bookworm + volumes: + - /srv/example:/srv/example + outputs: + job-output: ${{ steps.stepwithoutput.outputs.myvalue }} + steps: + + - id: stepwithoutput + run: | + set -x + test "${{ inputs.parameter1 }}" = "value1" + test "${{ secrets.secret }}" = "keep_it_private" + echo "myvalue=outputvalue1" >> $FORGEJO_OUTPUT + + - name: save event + run: | + d=/srv/example/push/contexts/$FORGEJO_EVENT_NAME + mkdir -p $d + cat > $d/github <<'EOF' + ${{ toJSON(github) }} + EOF diff --git a/actions/example-workflow-call/.forgejo/workflows/test.yml b/actions/example-workflow-call/.forgejo/workflows/test.yml new file mode 100644 index 00000000..fef61667 --- /dev/null +++ b/actions/example-workflow-call/.forgejo/workflows/test.yml @@ -0,0 +1,23 @@ +on: + push: + +jobs: + caller: + runs-on: docker + container: + image: data.forgejo.org/oci/node:22-bookworm + uses: ./.forgejo/workflows/reusable.yml + with: + parameter1: value1 + secrets: + secret: keep_it_private + + verify: + needs: [caller] + runs-on: docker + container: + image: data.forgejo.org/oci/node:22-bookworm + steps: + - run: | + set -x + test "${{ needs.caller.outputs.output1 }}" = "outputvalue1" diff --git a/actions/example-workflow-dispatch/.forgejo/workflows/test.yml b/actions/example-workflow-dispatch/.forgejo/workflows/test.yml new file mode 100644 index 00000000..3839f7b5 --- /dev/null +++ b/actions/example-workflow-dispatch/.forgejo/workflows/test.yml @@ -0,0 +1,57 @@ +on: + workflow_dispatch: + inputs: + logLevel: + description: 'Log Level' + required: true + default: 'warning' + type: choice + options: + - info + - warning + - debug + tags: + description: 'Test scenario tags' + required: false + type: boolean + boolean_default_true: + description: 'Test scenario tags' + required: true + type: boolean + default: true + boolean_default_false: + description: 'Test scenario tags' + required: false + type: boolean + default: false + number1_default: + description: 'Number w. default' + default: '100' + type: number + number2: + description: 'Number w/o. default' + type: number + string1_default: + description: 'String w. default' + default: 'Hello world' + type: string + string2: + description: 'String w/o. default' + required: true + type: string + +jobs: + test: + runs-on: docker + container: + image: data.forgejo.org/oci/debian:trixie + options: "--volume /srv/example:/srv/example" + + steps: + - name: save and display context + run: | + d=/srv/example/workflow-dispatch/contexts/$FORGEJO_EVENT_NAME + mkdir -p $d + tee $d/github <<'EOF' + ${{ toJSON(github) }} + EOF diff --git a/actions/example-workflow-dispatch/run.sh b/actions/example-workflow-dispatch/run.sh new file mode 100755 index 00000000..8a49365b --- /dev/null +++ b/actions/example-workflow-dispatch/run.sh @@ -0,0 +1,62 @@ +TMPDIR=$(mktemp -d) + +trap "rm -fr $TMPDIR" EXIT + +source $EXAMPLE_DIR/../../lib/lib.sh + +export d=/srv/example/tag +context=/srv/example/workflow-dispatch/contexts/workflow_dispatch/github +api=$url/api/v1 +repo=root/example-$example + +function context_wait() { + if ! forgejo.sh retry test -f $context; then + cat "$FORGEJO_RUNNER_LOGS" + false + fi +} + +function verify_required() { + local actual=$(forgejo-curl.sh api_json -w '%{http_code}' --data '{"ref":"main","inputs":{}}' $api/repos/$repo/actions/workflows/test.yml/dispatches) + local expected=400 + if test "$actual" != $expected; then + log_info "dispatch is expected to fail with status $expected because of string2 is a required value but got status $actual instead" + return 1 + fi +} + +function verify_inputs() { + local inputs='{"string2":"value2"}' + forgejo-curl.sh api_json --data '{"ref":"main","inputs":'$inputs'}' $api/repos/$repo/actions/workflows/test.yml/dispatches + cat >$TMPDIR/expected <<'EOF' + { + "boolean_default_false": "false", + "boolean_default_true": "true", + "logLevel": "warning", + "number1_default": "100", + "string1_default": "Hello world", + "string2": "value2" + } +EOF +} + +function run_tests() { + verify_required + + npm --silent install json-diff + verify_inputs + context_wait + node_modules/.bin/json-diff <(jq .event.inputs <$context) $TMPDIR/expected +} + +function main() { + mkdir -p $d + + forgejo-test-helper.sh push_workflow actions/example-$example $url root example-$example setup-forgejo $token + + run_tests + + test "workflow_dispatch" = "$(jq -r .event_name <$context)" +} + +main diff --git a/actions/example-workflow-dispatch/setup.sh b/actions/example-workflow-dispatch/setup.sh new file mode 100755 index 00000000..402b08ce --- /dev/null +++ b/actions/example-workflow-dispatch/setup.sh @@ -0,0 +1 @@ +mkdir -p /srv/example/workflow-dispatch diff --git a/actions/run.sh b/actions/run.sh deleted file mode 100755 index ab8b86be..00000000 --- a/actions/run.sh +++ /dev/null @@ -1,127 +0,0 @@ -#!/bin/bash - -set -e -set -o pipefail - -SELF_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -function run() { - local example=$1 - - export example - export EXAMPLE_DIR=$SELF_DIR/example-$example - - if test -f $EXAMPLE_DIR/setup.sh ; then - echo "============================ SETUP example-$example ===================" - bash -ex $EXAMPLE_DIR/setup.sh || return 1 - fi - - if test -f $EXAMPLE_DIR/run.sh ; then - echo "============================ RUN example-$example ===================" - bash -ex $EXAMPLE_DIR/run.sh || return 1 - else - forgejo-test-helper.sh run_workflow actions/example-$example $url root example-$example $example $token || return 1 - fi - - if test -f $EXAMPLE_DIR/teardown.sh ; then - echo "============================ TEARDOWN example-$example ===================" - bash -ex $EXAMPLE_DIR/teardown.sh || return 1 - fi -} - -function examples_v1_20() { - echo 'echo checkout service container expression local-action docker-action if if-fail' -} - -function examples_v1_21() { - # keep "cron" last otherwise it will linger and pollute the following runs - echo 'echo push tag push-cancel artifacts service checkout pull-request container expression local-action context docker-action if if-fail cron' -} - -function examples_v7_0() { - examples_v1_21 -} - -function save_contexts() { - local example="$1" - - if test -d /srv/example/$example/contexts; then - mkdir -p /srv/contexts - rsync -av /srv/example/$example/contexts/ /srv/contexts/$example/ - fi -} - -function cleanup_example_volume() { - if ! test -d /srv/example ; then - mkdir -p /srv/example - return - fi - - if test $(id -u) != 0 ; then - SUDO=sudo - fi - - $SUDO rm -fr /srv/example/* -} - -function setup() { - local binary=$1 - forgejo-binary.sh setup root admin1234 $binary - cleanup_example_volume - export FORGEJO_RUNNER_CONFIG=$SELF_DIR/runner-config.yaml - forgejo-runner.sh setup -} - -function teardown() { - forgejo-curl.sh logout - forgejo-runner.sh teardown - forgejo-binary.sh teardown -} - -function main() { - local binary="$1" - shift - export full_version="$1" - shift - export version="$1" - shift - - export DOT=$DIR/forgejo-curl - - teardown - - if test "$#" = 0 ; then - examples=$(examples_${version/./_}) - else - examples="$@" - fi - - if test "$examples" = "none" ; then - exit 0 - fi - - setup $binary - - if ! test -f "$DIR/forgejo-auth-url" ; then - echo "DIR=$DIR must be a directory with a forgejo-auth-url file" - fi - - export FORGEJO_RUNNER_LOGS=$DIR/forgejo-runner.log - export url=$(cat $DIR/forgejo-auth-url) - export token=$(cat $DIR/forgejo-token) - - for example in $examples ; do - echo "======================== BEGIN example-$example ===================" - if ! time run $example >& /tmp/run.out ; then - sed -e 's/^/[RUN] /' < /tmp/run.out - echo "======================== FAIL example-$example ===================" - sleep 5 # hack for Forgejo v1.21 to workaround a bug by which the last lines of the output are moved to the next step - false - fi - echo "======================== END example-$example ===================" - save_contexts $example - cleanup_example_volume - done -} - -main "$@" diff --git a/actions/runner-config.yaml b/actions/runner-config.yaml index 12019d78..5859b08e 100644 --- a/actions/runner-config.yaml +++ b/actions/runner-config.yaml @@ -1,6 +1,6 @@ - log: - level: info + level: trace + job_level: trace runner: file: .runner diff --git a/end-to-end.sh b/end-to-end.sh new file mode 100755 index 00000000..e57c8b1b --- /dev/null +++ b/end-to-end.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MIT + +SELF_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SELF="${BASH_SOURCE[0]}" +source $SELF_DIR/lib/lib.sh + +source $SELF_DIR/federation/federation.sh +source $SELF_DIR/actions/actions.sh +source $SELF_DIR/forgejo/fixtures.sh +source $SELF_DIR/storage/storage.sh +source $SELF_DIR/upgrade/upgrade.sh +source $SELF_DIR/packages/packages.sh + +"$@" diff --git a/federation/ONE-app.ini b/federation/ONE-app.ini new file mode 100644 index 00000000..92a75b71 --- /dev/null +++ b/federation/ONE-app.ini @@ -0,0 +1,34 @@ +RUN_MODE = prod +WORK_PATH = forgejo-ONE + +[server] +APP_DATA_PATH = ${WORK_PATH}/data +DOMAIN = ${IP} +HTTP_PORT = 3001 +SSH_LISTEN_PORT = 2201 + +[queue] +TYPE = immediate + +[database] +DB_TYPE = sqlite3 +PATH = ${WORK_PATH}/forgejo.db + +[log] +MODE = file +LEVEL = trace +logger.router.MODE = file + +[log.file] +FILE_NAME = forgejo.log + +[security] +INSTALL_LOCK = true + +[repository] +ENABLE_PUSH_CREATE_USER = true +DEFAULT_PUSH_CREATE_PRIVATE = false + +[federation] +ENABLED = true + diff --git a/federation/TWO-app.ini b/federation/TWO-app.ini new file mode 100644 index 00000000..21448bda --- /dev/null +++ b/federation/TWO-app.ini @@ -0,0 +1,33 @@ +RUN_MODE = prod +WORK_PATH = forgejo-TWO + +[server] +APP_DATA_PATH = ${WORK_PATH}/data +DOMAIN = ${IP} +HTTP_PORT = 3002 +SSH_LISTEN_PORT = 2202 + +[queue] +TYPE = immediate + +[database] +DB_TYPE = sqlite3 +PATH = ${WORK_PATH}/forgejo.db + +[log] +MODE = file +LEVEL = trace +logger.router.MODE = file + +[log.file] +FILE_NAME = forgejo.log + +[security] +INSTALL_LOCK = true + +[repository] +ENABLE_PUSH_CREATE_USER = true +DEFAULT_PUSH_CREATE_PRIVATE = false + +[federation] +ENABLED = true diff --git a/federation/federation.sh b/federation/federation.sh new file mode 100755 index 00000000..4d7c09a5 --- /dev/null +++ b/federation/federation.sh @@ -0,0 +1,96 @@ +# Copyright 2024 The Forgejo Authors +# SPDX-License-Identifier: MIT + +FEDERATION_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +export FEDERATION_INSTANCES="ONE TWO" +export FEDERATION_CONFIGS + +function federation_setup_variables() { + if test "$FEDERATION_CONFIGS"; then + return + fi + for instance in $FEDERATION_INSTANCES; do + local config=$FEDERATION_DIR/$instance-app.ini + FEDERATION_CONFIGS="$FEDERATION_CONFIGS $config" + local base=$(work_path_base $config) + local work_path=$DIR/$base + local host_port=$(get_host_port $config) + + eval export ${instance}_CONFIG=$config + eval export ${instance}_CURL=$work_path/forgejo-curl.sh + eval export ${instance}_HOST_PORT=$host_port + done +} + +function federation_verify_scenario() { + local scenario=$1 + + federation_setup_variables + + export scenario + export SCENARIO_DIR=$FEDERATION_DIR/scenario-$scenario + + if test -f $SCENARIO_DIR/setup.sh; then + echo "============================ SETUP scenario-$scenario ===================" + bash -ex $SCENARIO_DIR/setup.sh || return 1 + fi + + echo "============================ RUN scenario-$scenario ===================" + bash -ex $SCENARIO_DIR/run.sh || return 1 + + if test -f $SCENARIO_DIR/teardown.sh; then + echo "============================ TEARDOWN scenario-$scenario ===================" + bash -ex $SCENARIO_DIR/teardown.sh || return 1 + fi +} + +function federation_setup() { + federation_setup_variables + + local version=$1 + federation_teardown + + local config + for config in $FEDERATION_CONFIGS; do + reset_forgejo $config + start_forgejo $version $config + done +} + +function federation_teardown() { + federation_setup_variables + + local config + for config in $FEDERATION_CONFIGS; do + stop_forgejo $config + done +} + +function test_federation() { + # start_gitlab gitlab/gitlab-ce:17.1.0-ce.0 + federation_setup_variables + + local versions="${1:-$RELEASE_NUMBERS}" + + for version in $versions; do + # name, minimum version + # NOTE: newline seperated, not comma :> + scenarios=( + "star 7.1" + "mastodon 14.0" + "gotosocial 14.0" + ) + + for scenario_version_str in "${scenarios[@]}"; do + IFS=' ' declare -a scenario_version="($scenario_version_str)" + + if dpkg --compare-versions "$version" lt "${scenario_version[1]}"; then + continue + fi + + federation_setup "$version" + run federation_verify_scenario "${scenario_version[0]}" + done + done +} diff --git a/federation/scenario-gotosocial/.gitignore b/federation/scenario-gotosocial/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/federation/scenario-gotosocial/run.sh b/federation/scenario-gotosocial/run.sh new file mode 100644 index 00000000..9fd57a7b --- /dev/null +++ b/federation/scenario-gotosocial/run.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +source "$DIR/federation_scenario-$scenario-env" + +if [[ -z "$password" ]]; then + exit 1 +fi + +if [[ -z "$port" ]]; then + exit 1 +fi + +status_code="$(curl -o /dev/null -w '%{http_code}' "http://localhost:$port/")" +if [[ "$status_code" != "200" ]]; then + exit 1 +fi diff --git a/federation/scenario-gotosocial/setup.sh b/federation/scenario-gotosocial/setup.sh new file mode 100644 index 00000000..fcf9a432 --- /dev/null +++ b/federation/scenario-gotosocial/setup.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash + +source $SCENARIO_DIR/../../lib/lib.sh + +GTS_VERSION="0.20.0" # renovate: datasource=docker depName=data.forgejo.org/oci/gotosocial + +echo "setting up gotosocial" + +tmpdir="$(mktemp --tmpdir -d gts.XXXXXXXXXX)" +cat << EOF > "$tmpdir/config.yaml" +host: "localhost:8080" +protocol: http +db-type: sqlite +db-address: /mount/gts.db3 + +http-client: + allow-ips: ["0.0.0.0/0", "::/0"] + insecure-outgoing: true +EOF + +podman unshare \ + chown 1000:1000 -R $tmpdir + +container_id="$( + podman run \ + -d \ + --env "GTS_CONFIG_PATH=/mount/config.yaml" \ + -v "$tmpdir:/mount" \ + -p "8080:8080" \ + --network=host \ + "data.forgejo.org/oci/gotosocial:$GTS_VERSION" \ + server start +)" + +function wait_gts_ready() { + http_status=$(curl -s -w \ + "%{http_code}" -o /dev/null \ + "http://localhost:8080/" + ) + + [[ "$http_status" == 200 ]] && echo "ready" +} + +retry wait_gts_ready + +password="verysecurepassword" +podman exec -it "$container_id" /gotosocial/gotosocial admin \ + account create \ + --username "test" \ + --email "test@localhost" \ + --password "$password" + +cat << EOF > "$DIR/federation_scenario-gotosocial-env" +password="$password" +port="8080" +container_id="$container_id" +EOF + diff --git a/federation/scenario-gotosocial/teardown.sh b/federation/scenario-gotosocial/teardown.sh new file mode 100644 index 00000000..6e6d556a --- /dev/null +++ b/federation/scenario-gotosocial/teardown.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +source "$DIR/federation_scenario-gotosocial-env" + +if [[ -z "$container_id" ]]; then + echo "gotosocial container ID not found, container may not be stopped" + exit 1 +fi + +podman stop "$container_id" +rm "$DIR/federation_scenario-gotosocial-env" + diff --git a/federation/scenario-mastodon/.gitignore b/federation/scenario-mastodon/.gitignore new file mode 100644 index 00000000..041e9d6f --- /dev/null +++ b/federation/scenario-mastodon/.gitignore @@ -0,0 +1,3 @@ +/resources/certs/forgejo* +/forgejo/certs/* +!/forgejo/certs/.gitkeep diff --git a/federation/scenario-mastodon/TEST_INSTRUCTION.md b/federation/scenario-mastodon/TEST_INSTRUCTION.md new file mode 100644 index 00000000..82d957b0 --- /dev/null +++ b/federation/scenario-mastodon/TEST_INSTRUCTION.md @@ -0,0 +1,38 @@ +# Manual testing + +1. compile forgejo binary to test on a debian/ubuntu system +2. start applications + * local forgejo: + ```sh + cd federation/scenario-mastodon + # create cert & startup & create test accounts + SCENARIO_DIR="." ./setup.sh + # Mastodon password in "/tmp/forgejo-end-to-end/federation_scenario-mastodon-env" + # Bind forgejo to localhost:3003 and set the domain to `forgejo` + ``` + * containerized forgejo: + ```sh + cd federation/scenario-mastodon + # Generate self-signed certs on first run + source ./functions.sh + generate_certs forgejo "./resources/certs" + mv "./resources/certs/forgejo"* "forgejo/certs" + + # Setup container + export FORGEJO_PATH="/path/to/forgejo/binary" + export COMPOSE_PROFILES="forgejo_container" + export MASTODON_HOST="mastodon-app" + + podman-compose up -d + podman-compose exec forgejo-app bash -c "/init/create_test_account.sh" + # Mastodon password is the last line of the output + podman-compose exec mastodon-app bash -c "/init/create_test_account.sh" + ``` +3. login to mastodon: http://localhost:4000 + 1. test@localhost - password from start app. +4. search for forgejo user: `https://forgejo/api/v1/activitypub/user-id/1` +5. Press follow +6. FYI: + 1. login to forgejo: http://localhost:3003/ + 2. me - me + 3. swagger-uri: http://localhost:3003/api/swagger#/activitypub diff --git a/federation/scenario-mastodon/compose.yaml b/federation/scenario-mastodon/compose.yaml new file mode 100644 index 00000000..ea7c28a6 --- /dev/null +++ b/federation/scenario-mastodon/compose.yaml @@ -0,0 +1,95 @@ +networks: + external_network: + internal_network: + internal: true + +services: + forgejo: + image: data.forgejo.org/oci/alpine:latest + volumes: + - ./forgejo/certs/:/usr/local/share/ca-certificates/ + - ./forgejo/init/:/init/ + - ./forgejo/etc/lighttpd.conf:/etc/lighttpd.conf + restart: unless-stopped + entrypoint: "sh /init/init.sh" + networks: + - external_network + - internal_network + + forgejo-app: + profiles: + - forgejo_container + # built from https://code.forgejo.org/federation/build-mastodon/src/branch/main/debian-containerfile + image: data.forgejo.org/federation/debian:trixie-cacerts + tmpfs: + - /data + volumes: + - ./forgejo-app/init/:/init/ + - ./forgejo-app/config/:/config/ + - ./resources/certs/:/usr/local/share/ca-certificates/ + - "${FORGEJO_PATH}:/usr/local/bin/forgejo" + ports: + - 3003:3003 + entrypoint: "sh /init/init.sh" + networks: + - external_network + - internal_network + + postgres: + image: data.forgejo.org/oci/postgres:14 + tmpfs: + - /var/lib/postgresql/data + environment: + POSTGRES_USER: postgres + POSTGRES_DB: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_HOST_AUTH_METHOD: trust + networks: + - internal_network + + redis: + image: data.forgejo.org/oci/redis:7.2 + tmpfs: + - /var/lib/redis/ + networks: + - internal_network + + mastodon-app: + # built from https://code.forgejo.org/federation/build-mastodon/src/branch/main/mastodon-containerfile + image: data.forgejo.org/federation/mastodon:v4.5-test + volumes: + - ./resources/certs:/usr/local/share/ca-certificates/ + - ./mastodon-app/init/:/init/ + environment: &mastodon_env + DB_HOST: postgres + DB_USER: postgres + DB_PASS: postgres + REDIS_HOST: redis + PORT: 4000 + LOCAL_DOMAIN: ${MASTODON_HOST}:4000 + ALTERNATE_DOMAINS: ${MASTODON_HOST},localhost + EMAIL_DOMAIN_ALLOWLIST: localhost + AUTHORIZED_FETCH: "true" + ALLOWED_PRIVATE_ADDRESSES: 0.0.0.0/0,::/0 + SECRET_KEY_BASE: bc1bdb4d3d57a2c292a8f145d5d3c921 + ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY: fkSxKD2bF396kdQbrP1EJ7WbU7ZgNokR + ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT: r0hvVmzBVsjxC7AMlwhOzmtc36ZCOS1E + ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY: PhdFyyfy5xJ7WVd2lWBpcPScRQHzRTNr + ports: + - "4000:4000" + entrypoint: "sh /init/init.sh" + networks: + - external_network + - internal_network + + mastodon-sidekiq: + # built from https://code.forgejo.org/federation/build-mastodon/src/branch/main/mastodon-containerfile + image: data.forgejo.org/federation/mastodon:v4.5-test + volumes: + - ./resources/certs:/usr/local/share/ca-certificates/ + - ./mastodon-sidekiq/init/:/init/ + restart: unless-stopped + environment: *mastodon_env + entrypoint: "sh /init/init.sh" + networks: + - internal_network diff --git a/federation/scenario-mastodon/forgejo-app/config/app.ini b/federation/scenario-mastodon/forgejo-app/config/app.ini new file mode 100644 index 00000000..55ef4f61 --- /dev/null +++ b/federation/scenario-mastodon/forgejo-app/config/app.ini @@ -0,0 +1,32 @@ +RUN_MODE = prod + +[server] +APP_DATA_PATH = /data +DOMAIN = forgejo +ROOT_URL = https://forgejo/ +HTTP_PORT = 3003 +PROTOCOL = http + +[queue] +TYPE = immediate + +[database] +DB_TYPE = sqlite3 +PATH = /data/forgejo.db + +[log] +MODE = console +LEVEL = debug + +[security] +INSTALL_LOCK = true + +[repository] +ENABLE_PUSH_CREATE_USER = true +DEFAULT_PUSH_CREATE_PRIVATE = false + +[federation] +ENABLED = true + +[session] +COOKIE_SECURE = false diff --git a/federation/scenario-mastodon/forgejo-app/init/create_test_account.sh b/federation/scenario-mastodon/forgejo-app/init/create_test_account.sh new file mode 100755 index 00000000..33fc4807 --- /dev/null +++ b/federation/scenario-mastodon/forgejo-app/init/create_test_account.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +sleep 10 + +/usr/local/bin/forgejo -c /etc/forgejo/app.ini admin user create --username me --password me --email "me@example.com" --admin --must-change-password=false +/usr/local/bin/forgejo -c /etc/forgejo/app.ini admin user create --username to-be-followd --password to-be-followd --email "to-be-followd@example.com" --admin --must-change-password=false +/usr/local/bin/forgejo -c /etc/forgejo/app.ini admin user generate-access-token -u me -t token --scopes write:activitypub,write:repository,write:user diff --git a/federation/scenario-mastodon/forgejo-app/init/init.sh b/federation/scenario-mastodon/forgejo-app/init/init.sh new file mode 100755 index 00000000..3848fa53 --- /dev/null +++ b/federation/scenario-mastodon/forgejo-app/init/init.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +sudo update-ca-certificates + +sudo mkdir -p /data/forgejo +sudo chown forgejo:forgejo /data/forgejo +sudo install -D -o forgejo -g forgejo /config/app.ini /etc/forgejo/app.ini + +/usr/local/bin/forgejo -c /etc/forgejo/app.ini + diff --git a/federation/scenario-mastodon/forgejo/certs/.gitkeep b/federation/scenario-mastodon/forgejo/certs/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/federation/scenario-mastodon/forgejo/etc/lighttpd.conf b/federation/scenario-mastodon/forgejo/etc/lighttpd.conf new file mode 100644 index 00000000..325779ad --- /dev/null +++ b/federation/scenario-mastodon/forgejo/etc/lighttpd.conf @@ -0,0 +1,22 @@ +server.document-root = "/var/www" + +server.modules = ( + "mod_openssl", + "mod_proxy" +) + +$SERVER["socket"] == ":443" { + ssl.engine = "enable" + ssl.pemfile = "/usr/local/share/ca-certificates/forgejo-snakeoil.crt" + ssl.privkey = "/usr/local/share/ca-certificates/forgejo-snakeoil.key" +} + +proxy.server = ( + "" => ( + "forgejo" => ( + "host" => "host.containers.internal", + "port" => 3003, + ) + ) +) + diff --git a/federation/scenario-mastodon/forgejo/init/init.sh b/federation/scenario-mastodon/forgejo/init/init.sh new file mode 100755 index 00000000..6660768d --- /dev/null +++ b/federation/scenario-mastodon/forgejo/init/init.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env sh + +apk add lighttpd + +lighttpd -D -f /etc/lighttpd.conf + diff --git a/federation/scenario-mastodon/functions.sh b/federation/scenario-mastodon/functions.sh new file mode 100644 index 00000000..507131cc --- /dev/null +++ b/federation/scenario-mastodon/functions.sh @@ -0,0 +1,32 @@ +function generate_certs() { + + host=${1} + cert_location=${2} + + rootCertificate="${cert_location}/custom-snakeoil-rootCA.crt" + rootCertKey="${cert_location}/custom-snakeoil-rootCA.key" + extensionFile="${cert_location}/${host}-snakeoil.ext" + keyFile="${cert_location}/${host}-snakeoil.key" + csrFile="${cert_location}/${host}-snakeoil.csr" + crtAltSubFile="${cert_location}/${host}-snakeoil.crt" + + cat << EOF > ${extensionFile} +authorityKeyIdentifier=keyid,issuer +basicConstraints=CA:FALSE +subjectAltName = @alt_names +[alt_names] +DNS.1 = ${host} +DNS.2 = localhost +EOF + + # Create CSR + openssl req -newkey rsa:2048 -nodes -keyout ${keyFile} \ + -out ${csrFile} -subj "/CN=${host}" -addext "subjectAltName=DNS:localhost" + + # Sign Our CSR with the root CA cert + openssl x509 -req -CA ${rootCertificate} \ + -CAkey ${rootCertKey} \ + -in ${csrFile} \ + -out ${crtAltSubFile} \ + -days 3650 -CAcreateserial -extfile ${extensionFile} +} \ No newline at end of file diff --git a/federation/scenario-mastodon/mastodon-app/init/create_test_account.sh b/federation/scenario-mastodon/mastodon-app/init/create_test_account.sh new file mode 100755 index 00000000..283000fb --- /dev/null +++ b/federation/scenario-mastodon/mastodon-app/init/create_test_account.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +account_create="$(tootctl accounts create test --email test@localhost --role Owner --confirmed)" +tootctl account modify test --approve + +echo "${account_create}" + +password=$(echo "${account_create}" | + tail -n 1 | + sed 's/New password: //' | + sed 's/\r//' +) + +echo "$password" diff --git a/federation/scenario-mastodon/mastodon-app/init/init.sh b/federation/scenario-mastodon/mastodon-app/init/init.sh new file mode 100755 index 00000000..731aa55d --- /dev/null +++ b/federation/scenario-mastodon/mastodon-app/init/init.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +sudo update-ca-certificates +sudo touch /opt/mastodon/log/prod.log +sudo chown mastodon: /opt/mastodon/log/prod.log +rails db:setup +bundle exec puma -C config/puma.rb +#sleep 2h diff --git a/federation/scenario-mastodon/mastodon-sidekiq/init/init.sh b/federation/scenario-mastodon/mastodon-sidekiq/init/init.sh new file mode 100755 index 00000000..af9c5190 --- /dev/null +++ b/federation/scenario-mastodon/mastodon-sidekiq/init/init.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +sudo update-ca-certificates +sudo touch /opt/mastodon/log/prod.log +sudo chown mastodon: /opt/mastodon/log/prod.log +bundle exec sidekiq +#sleep 2h diff --git a/federation/scenario-mastodon/resources/certs/custom-snakeoil-rootCA.crt b/federation/scenario-mastodon/resources/certs/custom-snakeoil-rootCA.crt new file mode 100644 index 00000000..91a0d144 --- /dev/null +++ b/federation/scenario-mastodon/resources/certs/custom-snakeoil-rootCA.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDGTCCAgGgAwIBAgIUU+o53CfULAHTgPuCq/Ua8JRTWLIwDQYJKoZIhvcNAQEL +BQAwGzEZMBcGA1UEAwwQY29kZS5mb3JnZWpvLm9yZzAgFw0yNTEwMjMwODI2NTVa +GA8yMTI1MDkyOTA4MjY1NVowGzEZMBcGA1UEAwwQY29kZS5mb3JnZWpvLm9yZzCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKJl1YjGLoYK5J7wCbgL7WCZ +DGznwmp2SxpxJx/9Y6Pldt1QXTp0/VrR/H8iu3bNh13jmupXTKyGHU94MTNHER1T +/jbGw8LRPWCIYNjpYFZU17glTGs/DOieh7acuuvu+imoamk1oRLVaaHDewz09Tc2 +wkklCH+2ME2TC6mHIqpHOLO//ESEU0Glo+/mVMEcTJf9zdDhSGhZPKhXEaWgrLMo +EV3r0hpxHCE21OeaRrOKjMtOfp6/v0yKAsJ0QbLHXw1JDauiMWHUxp1H3jIHGgtc +0ALdiS1fhYi8zX3bkbMfctjREVtbhO0Aqps5pvDjhjTNyTmSQ3dkkU37W7Mz+WkC +AwEAAaNTMFEwHQYDVR0OBBYEFKXOSikliKVL6VYbbcaOR3k3khKyMB8GA1UdIwQY +MBaAFKXOSikliKVL6VYbbcaOR3k3khKyMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI +hvcNAQELBQADggEBADE4RGzIXT3LsLGxqRiuOPrXnOTy6izD0sXraJGPWOTEm0MB +H+MnV1YmqRiafwCTbKyiTfzF50JX0zwa6NnkK7k7tyht7O2B0/1VfsrIaXGBP05B +pZMC1bMSaDEu+zvRUDFvNiE5Oxkw0LGy44o36e3SNCEXMCYU3fiTX/5IxfB/a1Bk ++5tNfpK4CKwyk2/pb8ClgBldYGxfp/hyzTVh7y4c5bSRzoawGxq2ipfmJbSBYEme +vyySFXJI1W9ih8utE2sQKbRS7YrwxSNS9Uj6qwixTlHB5a/MzlFmD630VkmkI1qq +5VkQxq7dJSTlVHX8qiQqvGoPPIp5ucbBDmyj2A8= +-----END CERTIFICATE----- diff --git a/federation/scenario-mastodon/resources/certs/custom-snakeoil-rootCA.key b/federation/scenario-mastodon/resources/certs/custom-snakeoil-rootCA.key new file mode 100644 index 00000000..b4b13057 --- /dev/null +++ b/federation/scenario-mastodon/resources/certs/custom-snakeoil-rootCA.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCiZdWIxi6GCuSe +8Am4C+1gmQxs58JqdksacScf/WOj5XbdUF06dP1a0fx/Irt2zYdd45rqV0yshh1P +eDEzRxEdU/42xsPC0T1giGDY6WBWVNe4JUxrPwzonoe2nLrr7vopqGppNaES1Wmh +w3sM9PU3NsJJJQh/tjBNkwuphyKqRzizv/xEhFNBpaPv5lTBHEyX/c3Q4UhoWTyo +VxGloKyzKBFd69IacRwhNtTnmkaziozLTn6ev79MigLCdEGyx18NSQ2rojFh1Mad +R94yBxoLXNAC3YktX4WIvM1925GzH3LY0RFbW4TtAKqbOabw44Y0zck5kkN3ZJFN ++1uzM/lpAgMBAAECggEAAdGmR0j0k/ISyfhYnFJfFAfBN+x0a1wl7rOjDP/Tg7r9 +Ln21yzYTJJcfnu5TaOfLH84KrRwrT6JhhfaYn64PC8PmH/rXDftPsFSOt/DZo2+B +vaSgGyWcMVqdnNOOep6IXq36rr3krwQra14Rmbbm36AYihh+iuzbB4w0vPvpwDwv +G9DITTLrIwDRbXReZ13FjqphP5dqT6jG7BnRLe7vyQ7CJwYdUDLkg2YLykwbHvco +DISS3IoYgF5R7KaGpwH2iFmeHYwXaVH9Y0RyjEvxp87iK8Awvm4yn7hWBx9NsMm2 +of7107TlFBU81JbG09KQZ+mS3S4C9XfQScqBoP66tQKBgQDYS4QhwkYFNusN8z+U +63IGMxJXMF0bvF1zqjhrfkdX16jDD7v8cMbZAjk80obmRdhFpNiuaCT7dbnXpt7L +Ppfu6IkcJsAJc32lbWGc56XzfzDnNecvQbCbMnRYI5GDzcTTY+ObgyhJv4SwuD3E +kdHhxOFPuxlLFey9eg9vC6ADnQKBgQDANX5oEqvVty8gn+cOU3fEiqQ+ZqvcgMcL +CUQYIAUDvXjZuXTbU0cSzgZnZi3JwtEVwj0u+0eXXlju6AVgKC/yd4aIpQ2f6hXO +UlODWIqiNq3lVgjatO6zQ2CXuBeV7crX6odNrhkvSwSPNlC2Ra7QZ8Uk0PpX0sTm +JyuMA/WBPQKBgQCkqulPYj44nhTZrAUN9Sn7+knOQy2/feqPsln9zEe4YqFCz+nI +SHu6nuzAl27IRQhgDR5BuVvebUQtIAeiKGc3JaWs3vt4topDtUCJWfqHpJ+whuMY +oSQ5I3Jb38ha1f8xCG0x6ep0KvB0MfAkhPeKsH7wWnrpJSn1HsY9PlZ2KQKBgQCS +/xZKb6UdEDipocDqkukw1bsgwhLD03TmOtLqBGrxXlFzacM2DW14sznwkBOKj0Sq +eF+kc6Zf3Fb1d1rNHE73B3RLQre1yiedIBcgh3GW92xszSx+XwuC64+O2Mqo7jBI +iuOpg/Fc2umEwUxe6dH1Lrd2HaCn09ikD+bc8RYsHQKBgQDXfAiAf3MdzG8+4zgD +kzfZsUXRUm3ACqrkhlUOzPsh2y5yGO0gxkrUR4ps2+wn0aapwYi+JdbEHpDqI4Ze +vE3d8ZgLF4ER+uuiayuItMIFa8T0AiH1oJMptUY4kgj1AaG0b3+ZxU/uGXjpciyA +a7/psxJ+in3AQ005JGir8rx+gA== +-----END PRIVATE KEY----- diff --git a/federation/scenario-mastodon/run.sh b/federation/scenario-mastodon/run.sh new file mode 100644 index 00000000..7e07a1b8 --- /dev/null +++ b/federation/scenario-mastodon/run.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +source "$DIR/federation_scenario-$scenario-env" + +if [[ -z "$password" ]]; then + exit 1 +fi + +if [[ -z "$port" ]]; then + exit 1 +fi + +status_code="$(curl -o /dev/null -w '%{http_code}' "http://localhost:$port/")" +if [[ "$status_code" != "200" ]]; then + exit 1 +fi + diff --git a/federation/scenario-mastodon/setup.sh b/federation/scenario-mastodon/setup.sh new file mode 100755 index 00000000..cb9efb98 --- /dev/null +++ b/federation/scenario-mastodon/setup.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash + +source "$SCENARIO_DIR/../../lib/lib.sh" +source "$SCENARIO_DIR/functions.sh" + +echo "Setting up Forgejo x Mastodon" + +if [[ ! -d "$DIR" ]]; then + mkdir -p "$DIR" +fi + +echo "Generating forgejo & mastodon self-signed certificate" + +generate_certs forgejo "$SCENARIO_DIR/resources/certs" + +mv "$SCENARIO_DIR/resources/certs/forgejo"* "$SCENARIO_DIR/forgejo/certs/" + +export MASTODON_HOST="localhost" + +podman-compose \ + -f "$SCENARIO_DIR/compose.yaml" \ + up -d + +function wait_up() { + command="$(podman-compose \ + -f "$SCENARIO_DIR/compose.yaml" \ + exec mastodon-app \ + bin/tootctl accounts + )" + + first="$(head -n 1 <<< "$command")" + [[ "$first" == *"Commands:"* ]] && echo "ready" +} + +retry wait_up + +password="$(podman-compose \ + -f "$SCENARIO_DIR/compose.yaml" \ + exec mastodon-app \ + bash -c "/init/create_test_account.sh" | \ + tail -n 1 | \ + sed 's/\r//' +)" + +cat << EOF > "$DIR/federation_scenario-mastodon-env" +password="$password" +port="4000" +EOF diff --git a/federation/scenario-mastodon/teardown.sh b/federation/scenario-mastodon/teardown.sh new file mode 100644 index 00000000..5e5d35f4 --- /dev/null +++ b/federation/scenario-mastodon/teardown.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +podman-compose \ + -f "$SCENARIO_DIR/compose.yaml" \ + down + +rm "$DIR/federation_scenario-mastodon-env" + diff --git a/federation/scenario-star/run.sh b/federation/scenario-star/run.sh new file mode 100644 index 00000000..ad340d22 --- /dev/null +++ b/federation/scenario-star/run.sh @@ -0,0 +1,47 @@ +TMPDIR=$(mktemp -d) + +trap "rm -fr $TMPDIR" EXIT + +source $SCENARIO_DIR/../../lib/lib.sh + +function star_count() { + local curl=$1 + local host_port=$2 + local count=$3 + + $curl api_json http://$host_port/api/v1/repos/root/test >$TMPDIR/count.json + if test $count != $(jq -r .stars_count <$TMPDIR/count.json); then + jq . <$TMPDIR/count.json + return 1 + fi +} + +# +# create a repo on each instance +# +$ONE_CURL api_json --data '{"name":"test","auto_init":true}' $ONE_HOST_PORT/api/v1/user/repos >$TMPDIR/one-repo.json +one_repo_id=$(jq -r .id <$TMPDIR/one-repo.json) +$TWO_CURL api_json --data '{"name":"test","auto_init":true}' $TWO_HOST_PORT/api/v1/user/repos >$TMPDIR/two-repo.json +two_repo_id=$(jq -r .id <$TMPDIR/two-repo.json) + +# +# the repo in instance two is federated with the repo in instance one +# +$ONE_CURL web --form action=federation --form following_repos=http://$TWO_HOST_PORT/api/v1/activitypub/repository-id/$two_repo_id http://$ONE_HOST_PORT/root/test/settings + +# +# check that both repo have 0 star +# +star_count $ONE_CURL $ONE_HOST_PORT 0 +star_count $TWO_CURL $TWO_HOST_PORT 0 + +# +# star the repo on instance one and expect the star to show on instance two +# +$ONE_CURL api_json -X PUT $ONE_HOST_PORT/api/v1/user/starred/root/test + +# +# check that both repo have 1 star +# +star_count $ONE_CURL $ONE_HOST_PORT 1 +retry star_count $TWO_CURL $TWO_HOST_PORT 1 diff --git a/federation/scenario-star/setup.sh b/federation/scenario-star/setup.sh new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/federation/scenario-star/setup.sh @@ -0,0 +1 @@ + diff --git a/federation/scenario-star/teardown.sh b/federation/scenario-star/teardown.sh new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/federation/scenario-star/teardown.sh @@ -0,0 +1 @@ + diff --git a/forgejo/build.sh b/forgejo/build.sh deleted file mode 100755 index 5ee106dc..00000000 --- a/forgejo/build.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -# Copyright 2024 The Forgejo Authors -# SPDX-License-Identifier: MIT - -set -ex - -SELF_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -version=$1 -DIR=$2 - -v=$(echo $version | sed -E -e 's/([0-9]+\.[0-9]+).*/\1/') -read url ref semver < $SELF_DIR/sources/$v - -rm -fr $DIR/src -if [[ "$ref" =~ ^refs/ ]] ; then - git clone --depth 1 $url $DIR/src - cd $DIR/src - git fetch origin +$ref:$ref - git checkout -b $v $ref -else - git clone --depth 1 -b $ref $url $DIR/src - cd $DIR/src -fi -export TAGS="bindata sqlite sqlite_unlock_notify" -make deps-backend backend -# -# use the gitea target here so that branches that do not contain the commit that adds -# the `forgejo` target to the Makefile can build successfully -# -make VERSION=v$version GITEA_VERSION=v$version FORGEJO_VERSION=$semver generate gitea -mv gitea $DIR/forgejo-$version diff --git a/forgejo/fixtures.sh b/forgejo/fixtures.sh new file mode 100644 index 00000000..b49abf50 --- /dev/null +++ b/forgejo/fixtures.sh @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MIT + +FIXTURES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +source $FIXTURES_DIR/fixtures/storage.sh +source $FIXTURES_DIR/fixtures/doctor.sh diff --git a/forgejo/fixtures/doctor.sh b/forgejo/fixtures/doctor.sh new file mode 100644 index 00000000..c0d81099 --- /dev/null +++ b/forgejo/fixtures/doctor.sh @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: MIT + +function doctor_run() { + local config=$1 + local base=$(work_path_base $config) + local work_path=$DIR/$base + + $work_path/forgejocli doctor check --all # --log-file - +} diff --git a/forgejo/upgrades/fixtures.sh b/forgejo/fixtures/storage.sh similarity index 66% rename from forgejo/upgrades/fixtures.sh rename to forgejo/fixtures/storage.sh index 1b8cb44c..80b7c70c 100644 --- a/forgejo/upgrades/fixtures.sh +++ b/forgejo/fixtures/storage.sh @@ -1,4 +1,3 @@ -#!/bin/bash # SPDX-License-Identifier: MIT #ONEPIXEL="iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==" @@ -8,20 +7,44 @@ # ONEPIXEL="iVBORw0KGgoAAAANSUhEUgAAASIAAAEiCAYAAABdvt+2AAADrElEQVR4nOzUMRHAMADEsL9eeQd6AsOLhMCT/7udAYS+OgDAiICcEQE5IwJyRgTkjAjIGRGQMyIgZ0RAzoiAnBEBOSMCckYE5IwIyBkRkDMiIGdEQM6IgJwRATkjAnJGBOSMCMgZEZAzIiBnREDOiICcEQE5IwJyRgTkjAjIGRGQMyIgZ0RAzoiAnBEBOSMCckYE5IwIyBkRkDMiIGdEQM6IgJwRATkjAnJGBOSMCMgZEZAzIiBnREDOiICcEQE5IwJyRgTkjAjIGRGQMyIgZ0RAzoiAnBEBOSMCckYE5IwIyBkRkDMiIGdEQM6IgJwRATkjAnJGBOSMCMgZEZAzIiBnREDOiICcEQE5IwJyRgTkjAjIGRGQMyIgZ0RAzoiAnBEBOSMCckYE5IwIyBkRkDMiIGdEQM6IgJwRATkjAnJGBOSMCMgZEZAzIiBnREDOiICcEQE5IwJyRgTkjAjIGRGQMyIgZ0RAzoiAnBEBOSMCckYE5IwIyBkRkDMiIGdEQM6IgJwRATkjAnJGBOSMCMgZEZAzIiBnREDOiICcEQE5IwJyRgTkjAjIGRGQMyIgZ0RAzoiAnBEBOSMCckYE5IwIyBkRkDMiIGdEQM6IgJwRATkjAnJGBOSMCMgZEZAzIiBnREDOiICcEQE5IwJyRgTkjAjIGRGQMyIgZ0RAzoiAnBEBOSMCckYE5IwIyBkRkDMiIGdEQM6IgJwRATkjAnJGBOSMCMgZEZAzIiBnREDOiICcEQE5IwJyRgTkjAjIGRGQMyIgZ0RAzoiAnBEBOSMCckYE5IwIyBkRkDMiIGdEQM6IgJwRATkjAnJGBOSMCMgZEZAzIiBnREDOiICcEQE5IwJyRgTkjAjIGRGQMyIgZ0RAzoiAnBEBOSMCckYE5IwIyBkRkDMiIGdEQM6IgJwRATkjAnJGBOSMCMgZEZAzIiBnREDOiICcEQE5IwJyRgTkjAjIGRGQMyIgZ0RAzoiAnBEBOSMCckYE5IwIyBkRkDMiIGdEQM6IgJwRATkjAnJGBOSMCMgZEZAzIiBnREDOiICcEQE5IwJyRgTkjAjIGRGQMyIgZ0RAzoiAnBEBOSMCckYE5IwIyBkRkDMiIGdEQM6IgJwRATkjAnJGBOSMCMgZEZAzIiBnREDOiICcEQE5IwJyRgTkjAjIGRGQMyIgZ0RAzoiAnBEBOSMCckYE5IwIyBkRkDMiIGdEQM6IgJwRATkjAnJGBOSMCMgZEZAzIiBnREDuBQAA//+4jAPFe1H1tgAAAABJRU5ErkJggg==" +STORAGE_FUN="attachments avatars lfs packages repo_archive repo_avatars" +: ${FORGEJO_REPO:=fixture} + function fixture_get_paths_s3() { local path=$1 ( - echo -n $path/ - mc ls --quiet --recursive testS3/$path | sed -e 's/.* //' - ) > $DIR/path + mc ls --quiet --recursive testS3/$path | sed -e "s|.* |$path/|" + ) >$DIR/path +} + +function fixture_content_search_s3() { + local path="$1" + local expected="$2" + + fixture_get_paths_s3 $path + if test $(wc -l <$DIR/path) -lt 1; then + echo expected at least one but got "'$(cat $DIR/path)'" + return 1 + fi + for filename in $(cat $DIR/path); do + local content=$(mc cat testS3/$filename | base64 -w0) + if test "$content" = "$expected"; then + return 0 + fi + done + echo nothing in $path found with the expected content "$expected" + return 1 } function fixture_get_paths_local() { local path=$1 local work_path=$DIR/forgejo-work-path - ( cd $work_path ; find $path -type f) > $DIR/path + ( + cd $work_path + find $path -type f + ) >$DIR/path } function fixture_get_one_path() { @@ -30,7 +53,7 @@ function fixture_get_one_path() { fixture_get_paths_$storage $path - if test $(wc -l < $DIR/path) != 1 ; then + if test $(wc -l <$DIR/path) != 1; then echo expected one path but got cat $DIR/path return 1 @@ -57,13 +80,25 @@ function fixture_lfs_create() { ( cd $DIR/fixture git lfs track "*.txt" - echo CONTENT > file.txt + echo CONTENT >file.txt git add . git commit -m 'lfs files' git push ) } +function fixture_lfs_assert() { + local d=$(mktemp -d) + ( + git clone http://${FORGEJO_USER}:${FORGEJO_PASSWORD}@${HOST_PORT}/${FORGEJO_USER}/${FORGEJO_REPO} $d/${FORGEJO_REPO} + cd $d/${FORGEJO_REPO} + rm file.txt + git-lfs checkout file.txt + test -f file.txt + ) + rm -fr $d +} + function fixture_lfs_assert_s3() { local content=$(mc cat testS3/forgejo/lfs/d6/1e/5fa787e50330288923bd0c9866b44643925965144262288447cf52f9f9b7) test "$content" = CONTENT @@ -78,9 +113,9 @@ function fixture_lfs_assert_local() { } function fixture_packages_create() { - echo PACKAGE_CONTENT > $DIR/fixture/package - $work_path/forgejo-api -X DELETE http://${HOST_PORT}/api/packages/${FORGEJO_USER}/generic/test_package/1.0.0/file.txt || true - $work_path/forgejo-api --upload-file $DIR/fixture/package http://${HOST_PORT}/api/packages/${FORGEJO_USER}/generic/test_package/1.0.0/file.txt + echo PACKAGE_CONTENT >$DIR/fixture/package + forgejo-curl.sh api_json -X DELETE http://${HOST_PORT}/api/packages/${FORGEJO_USER}/generic/test_package/1.0.0/file.txt || true + forgejo-curl.sh api_json --upload-file $DIR/fixture/package http://${HOST_PORT}/api/packages/${FORGEJO_USER}/generic/test_package/1.0.0/file.txt } function fixture_packages_assert_s3() { @@ -96,14 +131,12 @@ function fixture_packages_assert_local() { } function fixture_avatars_create() { - echo -n $ONEPIXEL | base64 --decode > $DIR/avatar.png - $work_path/forgejo-client --form avatar=@$DIR/avatar.png http://${HOST_PORT}/user/settings/avatar + echo -n $ONEPIXEL | base64 --decode >$DIR/avatar.png + forgejo-curl.sh web --form avatar=@$DIR/avatar.png http://${HOST_PORT}/user/settings/avatar } function fixture_avatars_assert_s3() { - local filename=$(fixture_get_one_path s3 forgejo/avatars) - local content=$(mc cat testS3/$filename | base64 -w0) - test "$content" = "$ONEPIXEL" + fixture_content_search_s3 forgejo/avatars "$ONEPIXEL" } function fixture_avatars_assert_local() { @@ -115,10 +148,8 @@ function fixture_avatars_assert_local() { } function fixture_repo_avatars_create() { - echo -n $ONEPIXEL | base64 --decode > $DIR/repo-avatar.png - $work_path/forgejo-client --form avatar=@$DIR/repo-avatar.png http://${HOST_PORT}/${FORGEJO_USER}/${FORGEJO_REPO}/settings/avatar - # v1.21 only - #$work_path/forgejo-api -X POST --data-raw '{"body":"'$avatar'"}' http://${HOST_PORT}/api/v1/repos/${FORGEJO_USER}/${FORGEJO_REPO}/avatar + echo -n $ONEPIXEL | base64 --decode >$DIR/repo-avatar.png + forgejo-curl.sh web --form avatar=@$DIR/repo-avatar.png http://${HOST_PORT}/${FORGEJO_USER}/${FORGEJO_REPO}/settings/avatar } function fixture_repo_avatars_assert_s3() { @@ -136,18 +167,18 @@ function fixture_repo_avatars_assert_local() { } function fixture_attachments_create_1_18() { - echo -n $ONEPIXEL | base64 --decode > $DIR/attachment.png - $work_path/forgejo-client --trace-ascii - --form file=@$DIR/attachment.png http://${HOST_PORT}/${FORGEJO_USER}/${FORGEJO_REPO}/issues/attachments + echo -n $ONEPIXEL | base64 --decode >$DIR/attachment.png + forgejo-curl.sh web --trace-ascii - --form file=@$DIR/attachment.png http://${HOST_PORT}/${FORGEJO_USER}/${FORGEJO_REPO}/issues/attachments } function fixture_attachments_create() { - if $work_path/forgejo-api http://${HOST_PORT}/api/v1/version | grep --quiet --fixed-strings 1.18. ; then + if forgejo-curl.sh api_json http://${HOST_PORT}/api/v1/version | grep --quiet --fixed-strings 1.18.; then fixture_attachments_create_1_18 return fi - id=$($work_path/forgejo-api --data-raw '{"title":"TITLE"}' http://${HOST_PORT}/api/v1/repos/${FORGEJO_USER}/${FORGEJO_REPO}/issues | jq .id) - echo -n $ONEPIXEL | base64 --decode > $DIR/attachment.png - $work_path/forgejo-client -H @$DIR/forgejo-work-path/forgejo-header --form name=attachment.png --form attachment=@$DIR/attachment.png http://${HOST_PORT}/api/v1/repos/${FORGEJO_USER}/${FORGEJO_REPO}/issues/$id/assets + id=$(forgejo-curl.sh api_json --data-raw '{"title":"TITLE"}' http://${HOST_PORT}/api/v1/repos/${FORGEJO_USER}/${FORGEJO_REPO}/issues | jq .id) + echo -n $ONEPIXEL | base64 --decode >$DIR/attachment.png + forgejo-curl.sh api --form name=attachment.png --form attachment=@$DIR/attachment.png http://${HOST_PORT}/api/v1/repos/${FORGEJO_USER}/${FORGEJO_REPO}/issues/$id/assets } function fixture_attachments_assert_s3() { @@ -176,12 +207,18 @@ function fixture_create() { git remote add origin http://${FORGEJO_USER}:${FORGEJO_PASSWORD}@${HOST_PORT}/${FORGEJO_USER}/${FORGEJO_REPO} git config user.email root@example.com git config user.name username - echo SOMETHING > README + echo SOMETHING >README git add README git commit -m 'initial commit' git push --set-upstream --force origin main ) - for fun in ${STORAGE_FUN} ; do + for fun in ${STORAGE_FUN}; do fixture_${fun}_create done } + +function fixture_assert() { + for fun in lfs; do + fixture_${fun}_assert + done +} diff --git a/forgejo/sources/1.20 b/forgejo/sources/1.20 deleted file mode 100644 index 3539e492..00000000 --- a/forgejo/sources/1.20 +++ /dev/null @@ -1 +0,0 @@ -https://codeberg.org/forgejo/forgejo v1.20/forgejo 5.0.0+0-gitea-1.20.0 diff --git a/forgejo/sources/1.21 b/forgejo/sources/1.21 deleted file mode 100644 index fc1869a6..00000000 --- a/forgejo/sources/1.21 +++ /dev/null @@ -1 +0,0 @@ -https://codeberg.org/forgejo/forgejo v1.21/forgejo 6.0.0+0-gitea-1.21.0 diff --git a/forgejo/sources/10.0 b/forgejo/sources/10.0 new file mode 100644 index 00000000..7c1c0138 --- /dev/null +++ b/forgejo/sources/10.0 @@ -0,0 +1 @@ +https://codeberg.org/forgejo/forgejo forgejo 10.0.0+gitea-1.22 diff --git a/forgejo/sources/11.0 b/forgejo/sources/11.0 new file mode 100644 index 00000000..0286dcaf --- /dev/null +++ b/forgejo/sources/11.0 @@ -0,0 +1 @@ +https://codeberg.org/forgejo/forgejo forgejo 11.0.0 diff --git a/forgejo/sources/12.0 b/forgejo/sources/12.0 new file mode 100644 index 00000000..1ed248e4 --- /dev/null +++ b/forgejo/sources/12.0 @@ -0,0 +1 @@ +https://codeberg.org/forgejo/forgejo forgejo 12.0.0 diff --git a/forgejo/sources/13.0 b/forgejo/sources/13.0 new file mode 100644 index 00000000..24bcca16 --- /dev/null +++ b/forgejo/sources/13.0 @@ -0,0 +1 @@ +https://codeberg.org/forgejo/forgejo forgejo 13.0.0 diff --git a/forgejo/sources/14.0 b/forgejo/sources/14.0 new file mode 100644 index 00000000..84203a1b --- /dev/null +++ b/forgejo/sources/14.0 @@ -0,0 +1 @@ +https://codeberg.org/forgejo/forgejo forgejo 14.0.0 diff --git a/forgejo/sources/15.0 b/forgejo/sources/15.0 new file mode 100644 index 00000000..595283d3 --- /dev/null +++ b/forgejo/sources/15.0 @@ -0,0 +1 @@ +https://codeberg.org/forgejo/forgejo forgejo 15.0.0 diff --git a/forgejo/sources/7.0 b/forgejo/sources/7.0 index 32da8fd4..0e2cc26e 100644 --- a/forgejo/sources/7.0 +++ b/forgejo/sources/7.0 @@ -1 +1 @@ -https://codeberg.org/forgejo/forgejo forgejo 7.0.0+gitea-1.22.0 +https://codeberg.org/forgejo/forgejo v7.0/forgejo 7.0.0+gitea-1.21.0 diff --git a/forgejo/sources/8.0 b/forgejo/sources/8.0 new file mode 100644 index 00000000..42ce80b7 --- /dev/null +++ b/forgejo/sources/8.0 @@ -0,0 +1 @@ +https://codeberg.org/forgejo/forgejo v8.0/forgejo 8.0.0+gitea-1.22.0 diff --git a/forgejo/sources/9.0 b/forgejo/sources/9.0 new file mode 100644 index 00000000..bd6c2d0f --- /dev/null +++ b/forgejo/sources/9.0 @@ -0,0 +1 @@ +https://codeberg.org/forgejo/forgejo forgejo 9.0.0+gitea-1.22.0 diff --git a/forgejo/upgrades/misplace-app.ini b/forgejo/upgrades/misplace-app.ini deleted file mode 100644 index 0aeff453..00000000 --- a/forgejo/upgrades/misplace-app.ini +++ /dev/null @@ -1,59 +0,0 @@ -RUN_MODE = prod -WORK_PATH = ${WORK_PATH} - -[server] -APP_DATA_PATH = ${WORK_PATH}/elsewhere -HTTP_PORT = 3000 -SSH_LISTEN_PORT = 2222 -LFS_START_SERVER = true - -[database] -DB_TYPE = sqlite3 - -[log] -MODE = file -LEVEL = debug -ROUTER = file - -[log.file] -FILE_NAME = forgejo.log - -[security] -INSTALL_LOCK = true - -[repository] -ENABLE_PUSH_CREATE_USER = true -DEFAULT_PUSH_CREATE_PRIVATE = false - -[actions] -ENABLED = true - -[attachment] - -[storage.attachments] -PATH = ${WORK_PATH}/data/attachments - -[lfs] - -[storage.lfs] -PATH = ${WORK_PATH}/data/lfs - -[avatar] - -[storage.avatars] -PATH = ${WORK_PATH}/data/avatars - -[repo-avatar] - -[storage.repo-avatars] -PATH = ${WORK_PATH}/data/repo-avatars - -[repo-archive] - -[storage.repo-archive] -PATH = ${WORK_PATH}/data/repo-archive - -[packages] - -[storage.packages] -PATH = ${WORK_PATH}/data/packages diff --git a/forgejo/upgrades/misplace-s3-app.ini b/forgejo/upgrades/misplace-s3-app.ini deleted file mode 100644 index d9243dd2..00000000 --- a/forgejo/upgrades/misplace-s3-app.ini +++ /dev/null @@ -1,89 +0,0 @@ -RUN_MODE = prod -WORK_PATH = ${WORK_PATH} - -[server] -APP_DATA_PATH = ${WORK_PATH}/elsewhere -HTTP_PORT = 3000 -SSH_LISTEN_PORT = 2222 -LFS_START_SERVER = true - -[database] -DB_TYPE = sqlite3 - -[log] -MODE = file -LEVEL = debug -ROUTER = file - -[log.file] -FILE_NAME = forgejo.log - -[security] -INSTALL_LOCK = true - -[repository] -ENABLE_PUSH_CREATE_USER = true -DEFAULT_PUSH_CREATE_PRIVATE = false - -[actions] -ENABLED = true - -[attachment] -STORAGE_TYPE = minio -SERVE_DIRECT = false -MINIO_ENDPOINT = 127.0.0.1:9000 -MINIO_ACCESS_KEY_ID = 123456 -MINIO_SECRET_ACCESS_KEY = 12345678 -MINIO_BUCKET = forgejo -MINIO_LOCATION = us-east-1 -MINIO_USE_SSL = false - -[lfs] -STORAGE_TYPE = minio -SERVE_DIRECT = false -MINIO_ENDPOINT = 127.0.0.1:9000 -MINIO_ACCESS_KEY_ID = 123456 -MINIO_SECRET_ACCESS_KEY = 12345678 -MINIO_BUCKET = forgejo -MINIO_LOCATION = us-east-1 -MINIO_USE_SSL = false - -[repo-avatar] -STORAGE_TYPE = minio -SERVE_DIRECT = false -MINIO_ENDPOINT = 127.0.0.1:9000 -MINIO_ACCESS_KEY_ID = 123456 -MINIO_SECRET_ACCESS_KEY = 12345678 -MINIO_BUCKET = forgejo -MINIO_LOCATION = us-east-1 -MINIO_USE_SSL = false - -[avatar] -STORAGE_TYPE = minio -SERVE_DIRECT = false -MINIO_ENDPOINT = 127.0.0.1:9000 -MINIO_ACCESS_KEY_ID = 123456 -MINIO_SECRET_ACCESS_KEY = 12345678 -MINIO_BUCKET = forgejo -MINIO_LOCATION = us-east-1 -MINIO_USE_SSL = false - -[repo-archive] -STORAGE_TYPE = minio -SERVE_DIRECT = false -MINIO_ENDPOINT = 127.0.0.1:9000 -MINIO_ACCESS_KEY_ID = 123456 -MINIO_SECRET_ACCESS_KEY = 12345678 -MINIO_BUCKET = forgejo -MINIO_LOCATION = us-east-1 -MINIO_USE_SSL = false - -[packages] -STORAGE_TYPE = minio -SERVE_DIRECT = false -MINIO_ENDPOINT = 127.0.0.1:9000 -MINIO_ACCESS_KEY_ID = 123456 -MINIO_SECRET_ACCESS_KEY = 12345678 -MINIO_BUCKET = forgejo -MINIO_LOCATION = us-east-1 -MINIO_USE_SSL = false diff --git a/forgejo/upgrades/misplace-s3-two-app.ini b/forgejo/upgrades/misplace-s3-two-app.ini deleted file mode 100644 index 00445ea3..00000000 --- a/forgejo/upgrades/misplace-s3-two-app.ini +++ /dev/null @@ -1,113 +0,0 @@ -RUN_MODE = prod -WORK_PATH = ${WORK_PATH} - -[server] -APP_DATA_PATH = ${WORK_PATH}/elsewhere -HTTP_PORT = 3000 -SSH_LISTEN_PORT = 2222 -LFS_START_SERVER = true - -[database] -DB_TYPE = sqlite3 - -[log] -MODE = file -LEVEL = debug -ROUTER = file - -[log.file] -FILE_NAME = forgejo.log - -[security] -INSTALL_LOCK = true - -[repository] -ENABLE_PUSH_CREATE_USER = true -DEFAULT_PUSH_CREATE_PRIVATE = false - -[actions] -ENABLED = true - -[storage.attachments] -STORAGE_TYPE = minio -SERVE_DIRECT = false -MINIO_ENDPOINT = 127.0.0.1:9000 -MINIO_ACCESS_KEY_ID = 123456 -MINIO_SECRET_ACCESS_KEY = 12345678 -MINIO_BUCKET = forgejo -MINIO_LOCATION = us-east-1 -MINIO_USE_SSL = false - -[storage.lfs] -STORAGE_TYPE = minio -SERVE_DIRECT = false -MINIO_ENDPOINT = 127.0.0.1:9000 -MINIO_ACCESS_KEY_ID = 123456 -MINIO_SECRET_ACCESS_KEY = 12345678 -MINIO_BUCKET = forgejo -MINIO_LOCATION = us-east-1 -MINIO_USE_SSL = false - -[picture] -AVATAR_STORAGE_TYPE = minio -REPOSITORY_AVATAR_STORAGE_TYPE = minio - -[storage.repo-avatars] -STORAGE_TYPE = minio -SERVE_DIRECT = false -MINIO_ENDPOINT = 127.0.0.1:9000 -MINIO_ACCESS_KEY_ID = 123456 -MINIO_SECRET_ACCESS_KEY = 12345678 -MINIO_BUCKET = forgejo -MINIO_LOCATION = us-east-1 -MINIO_USE_SSL = false - -[storage.minio] -STORAGE_TYPE = minio -SERVE_DIRECT = false -MINIO_ENDPOINT = 127.0.0.1:9000 -MINIO_ACCESS_KEY_ID = 123456 -MINIO_SECRET_ACCESS_KEY = 12345678 -MINIO_BUCKET = forgejo -MINIO_LOCATION = us-east-1 -MINIO_USE_SSL = false - -[storage] -STORAGE_TYPE = minio -SERVE_DIRECT = false -MINIO_ENDPOINT = 127.0.0.1:9000 -MINIO_ACCESS_KEY_ID = 123456 -MINIO_SECRET_ACCESS_KEY = 12345678 -MINIO_BUCKET = forgejo -MINIO_LOCATION = us-east-1 -MINIO_USE_SSL = false - -[storage.avatars] -STORAGE_TYPE = minio -SERVE_DIRECT = false -MINIO_ENDPOINT = 127.0.0.1:9000 -MINIO_ACCESS_KEY_ID = 123456 -MINIO_SECRET_ACCESS_KEY = 12345678 -MINIO_BUCKET = forgejo -MINIO_LOCATION = us-east-1 -MINIO_USE_SSL = false - -[storage.repo-archive] -STORAGE_TYPE = minio -SERVE_DIRECT = false -MINIO_ENDPOINT = 127.0.0.1:9000 -MINIO_ACCESS_KEY_ID = 123456 -MINIO_SECRET_ACCESS_KEY = 12345678 -MINIO_BUCKET = forgejo -MINIO_LOCATION = us-east-1 -MINIO_USE_SSL = false - -[storage.packages] -STORAGE_TYPE = minio -SERVE_DIRECT = false -MINIO_ENDPOINT = 127.0.0.1:9000 -MINIO_ACCESS_KEY_ID = 123456 -MINIO_SECRET_ACCESS_KEY = 12345678 -MINIO_BUCKET = forgejo -MINIO_LOCATION = us-east-1 -MINIO_USE_SSL = false diff --git a/forgejo/upgrades/storage-relative-app.ini b/forgejo/upgrades/storage-relative-app.ini deleted file mode 100644 index eba5232d..00000000 --- a/forgejo/upgrades/storage-relative-app.ini +++ /dev/null @@ -1,44 +0,0 @@ -RUN_MODE = prod -WORK_PATH = ${WORK_PATH} - -[server] -APP_DATA_PATH = ${WORK_PATH}/data -HTTP_PORT = 3000 -SSH_LISTEN_PORT = 2222 -LFS_START_SERVER = true - -[database] -DB_TYPE = sqlite3 - -[log] -MODE = file -LEVEL = debug -ROUTER = file - -[log.file] -FILE_NAME = forgejo.log - -[security] -INSTALL_LOCK = true - -[repository] -ENABLE_PUSH_CREATE_USER = true -DEFAULT_PUSH_CREATE_PRIVATE = false - -[storage.attachments] -PATH = relative-attachments - -[storage.lfs] -PATH = relative-lfs - -[storage.avatars] -PATH = relative-avatars - -[storage.repo-avatars] -PATH = relative-repo-avatars - -[storage.repo-archive] -PATH = relative-repo-archive - -[storage.packages] -PATH = relative-packages diff --git a/forgejo/upgrades/test-upgrade.sh b/forgejo/upgrades/test-upgrade.sh deleted file mode 100755 index a848163b..00000000 --- a/forgejo/upgrades/test-upgrade.sh +++ /dev/null @@ -1,620 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: MIT - -# -# Debug loop from the source tree: -# -# ./.forgejo/upgrades/test-upgrade.sh dependencies -# ./.forgejo/upgrades/test-upgrade.sh build_all -# VERBOSE=true ./.forgejo/upgrades/test-upgrade.sh test_downgrade_1.20.2_fails -# -# Everything happens in /tmp/forgejo-upgrades -# - -PREFIX=============== -HOST_PORT=0.0.0.0:3000 -STORAGE_PATHS="attachments avatars lfs packages repo-archive repo-avatars" -STORAGE_FUN="attachments avatars lfs packages repo_archive repo_avatars" -DIR=/tmp/forgejo-upgrades -if ${VERBOSE:-false} ; then - set -ex - PS4='${BASH_SOURCE[0]}:$LINENO: ${FUNCNAME[0]}: ' -else - set -e -fi -SELF_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -: ${FORGEJO_USER:=root} -: ${FORGEJO_REPO:=fixture} -: ${FORGEJO_PASSWORD:=admin1234} - -source $SELF_DIR/fixtures.sh - -function maybe_sudo() { - if test $(id -u) != 0 ; then - SUDO=sudo - fi -} - -function log_info() { - echo "$PREFIX $@" -} - -function dependencies() { - maybe_sudo - if ! which curl daemon jq git-lfs > /dev/null ; then - export DEBIAN_FRONTEND=noninteractive - $SUDO apt-get update -qq - $SUDO apt-get install -y -qq curl daemon git-lfs jq sqlite3 gettext-base - fi - - if ! test -f /usr/local/bin/mc || ! test -f /usr/local/bin/minio > /dev/null ; then - $SUDO curl --fail -sS https://dl.min.io/client/mc/release/linux-amd64/mc -o /usr/local/bin/mc - $SUDO curl --fail -sS https://dl.min.io/server/minio/release/linux-amd64/minio -o /usr/local/bin/minio - fi - if ! test -x /usr/local/bin/mc || ! test -x /usr/local/bin/minio > /dev/null ; then - $SUDO chmod +x /usr/local/bin/mc - $SUDO chmod +x /usr/local/bin/minio - fi - - if ! test -f /usr/local/bin/garage > /dev/null ; then - $SUDO curl --fail -sS https://garagehq.deuxfleurs.fr/_releases/v0.8.2/x86_64-unknown-linux-musl/garage -o /usr/local/bin/garage - fi - if ! test -x /usr/local/bin/garage > /dev/null ; then - $SUDO chmod +x /usr/local/bin/garage - fi -} - -function build_all() { - log_info 7.0.0-dev - $SELF_DIR/../build.sh 7.0.0-dev $DIR -} - -function retry() { - rm -f $DIR/wait-for.out - success=false - for delay in 1 1 5 5 15 ; do - if "$@" >> $DIR/wait-for.out 2>&1 ; then - success=true - break - fi - cat $DIR/wait-for.out - echo waiting $delay - sleep $delay - done - if test $success = false ; then - cat $DIR/wait-for.out - return 1 - fi -} - -function download() { - local version=$1 - - if ! test -f $DIR/forgejo-$version ; then - mkdir -p $DIR - for owner in forgejo forgejo-experimental forgejo-integration ; do - if wget -O $DIR/forgejo-$version --quiet https://codeberg.org/$owner/forgejo/releases/download/v$version/forgejo-$version-linux-amd64 ; then - break - fi - done - chmod +x $DIR/forgejo-$version - fi -} - -function cleanup_logs() { - local work_path=$DIR/forgejo-work-path - - rm -f $DIR/*.log - rm -f $work_path/log/*.log -} - -function clobber() { - rm -fr /tmp/forgejo-upgrades -} - -function start_forgejo() { - local version=$1 - - download $version - local work_path=$DIR/forgejo-work-path - daemon --chdir=$DIR --unsafe --env="TERM=$TERM" --env="HOME=$HOME" --env="PATH=$PATH" --pidfile=$DIR/forgejo-pid --errlog=$DIR/forgejo-err.log --output=$DIR/forgejo-out.log -- $DIR/forgejo-$version --config $work_path/app.ini --work-path $work_path - if ! retry grep 'Starting server on' $work_path/log/forgejo.log ; then - cat $DIR/*.log - cat $work_path/log/*.log - return 1 - fi - create_user $version -} - -function start_minio() { - mkdir -p $DIR/minio - daemon --chdir=$DIR --unsafe \ - --env="PATH=$PATH" \ - --env=MINIO_ROOT_USER=123456 \ - --env=MINIO_ROOT_PASSWORD=12345678 \ - --env=MINIO_VOLUMES=$DIR/minio \ - --pidfile=$DIR/minio-pid --errlog=$DIR/minio-err.log --output=$DIR/minio-out.log -- /usr/local/bin/minio server - retry mc alias set testS3 http://127.0.0.1:9000 123456 12345678 -} - -function start_garage() { - mkdir -p $DIR/garage/{data,meta} - cat > $DIR/garage/garage.toml < $work_path/forgejo-token - ( echo -n 'Authorization: token ' ; cat $work_path/forgejo-token ) > $work_path/forgejo-header - ( echo "#!/bin/sh" ; echo 'curl -f -sS -H "Content-Type: application/json" -H @'$work_path/forgejo-header' "$@"' ) > $work_path/forgejo-api && chmod +x $work_path/forgejo-api - $work_path/forgejo-api http://${HOST_PORT}/api/v1/version - - # - # forgejo-client is to use with web endpoints - # - # - # login and obtain a CSRF, all stored in the cookie file - # - ( echo "#!/bin/sh" ; echo 'curl --cookie-jar '$DIR/cookies' --cookie '$DIR/cookies' -f -sS "$@"' ) > $work_path/forgejo-client-update-cookies && chmod +x $work_path/forgejo-client-update-cookies - $work_path/forgejo-client-update-cookies http://${HOST_PORT}/user/login -o /dev/null - $work_path/forgejo-client-update-cookies --verbose -X POST --data user_name=${FORGEJO_USER} --data password=${FORGEJO_PASSWORD} http://${HOST_PORT}/user/login >& $DIR/login.html - $work_path/forgejo-client-update-cookies http://${HOST_PORT}/user/login -o /dev/null - local csrf=$(sed -n -e '/csrf/s/.*csrf\t//p' $DIR/cookies) - # - # use the cookie file but do not modify it - # - ( echo "#!/bin/sh" ; echo 'curl --cookie '$DIR/cookies' -H "X-Csrf-Token: '$csrf'" -f -sS "$@"' ) > $work_path/forgejo-client && chmod +x $work_path/forgejo-client -} - -function stop_daemon() { - local daemon=$1 - - if test -f $DIR/$daemon-pid ; then - local pid=$(cat $DIR/$daemon-pid) - kill -TERM $pid - pidwait $pid || true - for delay in 1 1 2 2 5 5 ; do - if ! test -f $DIR/$daemon-pid ; then - break - fi - sleep $delay - done - ! test -f $DIR/$daemon-pid - fi -} - -function stop() { - stop_daemon forgejo - stop_daemon minio - stop_daemon garage - - cleanup_logs -} - -function reset_forgejo() { - local config=$1 - local work_path=$DIR/forgejo-work-path - rm -fr $work_path - mkdir -p $work_path - WORK_PATH=$work_path envsubst < $SELF_DIR/$config-app.ini > $work_path/app.ini -} - -function reset_minio() { - rm -fr $DIR/minio -} - -function reset_garage() { - rm -fr $DIR/garage -} - -function reset() { - local config=$1 - reset_forgejo $config - reset_minio - reset_garage -} - -function verify_storage() { - local work_path=$DIR/forgejo-work-path - - for path in ${STORAGE_PATHS} ; do - test -d $work_path/data/$path - done -} - -function cleanup_storage() { - local work_path=$DIR/forgejo-work-path - - for path in ${STORAGE_PATHS} ; do - rm -fr $work_path/data/$path - done -} - -function test_downgrade_1.20.2_fails() { - local work_path=$DIR/forgejo-work-path - - log_info "See also https://codeberg.org/forgejo/forgejo/pulls/1225" - - log_info "downgrading from 1.20.3-0 to 1.20.2-0 fails" - stop - reset default - start 1.20.3-0 - stop - download 1.20.2-0 - timeout 60 $DIR/forgejo-1.20.2-0 --config $work_path/app.ini --work-path $work_path || true - if ! grep --fixed-strings --quiet 'use the newer database' $work_path/log/forgejo.log ; then - cat $work_path/log/forgejo.log - return 1 - fi -} - -function test_bug_storage_merged() { - local work_path=$DIR/forgejo-work-path - - log_info "See also https://codeberg.org/forgejo/forgejo/pulls/1225" - - log_info "using < 1.20.3-0 and [storage].PATH merge all storage" - for version in 1.18.5-0 1.19.4-0 1.20.2-0 ; do - stop - reset merged - start $version - for path in ${STORAGE_PATHS} ; do - ! test -d $work_path/data/$path - done - for path in ${STORAGE_PATHS} ; do - ! test -d $work_path/merged/$path - done - test -d $work_path/merged - done - stop - - log_info "upgrading from 1.20.2-0 with [storage].PATH fails" - download 1.20.3-0 - timeout 60 $DIR/forgejo-1.20.3-0 --config $work_path/app.ini --work-path $work_path || true - if ! grep --fixed-strings --quiet '[storage].PATH is set and may create storage issues' $work_path/log/forgejo.log ; then - cat $work_path/log/forgejo.log - return 1 - fi -} - -function test_bug_storage_relative_path() { - local work_path=$DIR/forgejo-work-path - - log_info "using < 1.20.3-0 legacy [server].XXXX and [picture].XXXX are relative to WORK_PATH" - for version in 1.18.5-0 1.19.4-0 1.20.2-0 ; do - stop - reset legagy-relative - start $version - test -d $work_path/relative-lfs - test -d $work_path/relative-avatars - test -d $work_path/relative-repo-avatars - done - - log_info "using >= 1.20.3-0 legacy [server].XXXX and [picture].XXXX are relative to APP_DATA_PATH" - for version in 1.20.3-0 1.21.0-5-rc2 ; do - stop - reset legagy-relative - start $version - test -d $work_path/data/relative-lfs - test -d $work_path/data/relative-avatars - test -d $work_path/data/relative-repo-avatars - done - - log_info "using >= 1.20.3-0 relative [storage.XXXX].PATHS are relative to APP_DATA_PATH" - for version in 1.20.3-0 1.21.0-5-rc2 ; do - stop - reset storage-relative - start $version - for path in ${STORAGE_PATHS} ; do - test -d $work_path/data/relative-$path - done - done - - log_info "using 1.20.[12]-0 relative [storage.XXXX].PATHS are inconsistent" - for version in 1.20.2-0 ; do - stop - reset storage-relative - start $version - test -d $work_path/data/packages - test -d $work_path/relative-repo-archive - test -d $work_path/relative-attachments - test -d $work_path/relative-lfs - test -d $work_path/data/avatars - test -d $work_path/data/repo-avatars - done - - log_info "using < 1.20 relative [storage.XXXX].PATHS are inconsistent" - for version in 1.18.5-0 1.19.4-0 ; do - stop - reset storage-relative - start $version - test -d $work_path/relative-packages - test -d $work_path/relative-repo-archive - test -d $work_path/relative-attachments - test -d $work_path/data/lfs - test -d $work_path/data/avatars - test -d $work_path/data/repo-avatars - done - - log_info "using < 1.20.3-0 relative [XXXX].PATHS are relative to WORK_PATH" - for version in 1.18.5-0 1.19.4-0 1.20.2-0 ; do - stop - reset relative - start $version - for path in ${STORAGE_PATHS} ; do - test -d $work_path/relative-$path - done - done - - log_info "using >= 1.20.3-0 relative [XXXX].PATHS are relative to APP_DATA_PATH" - for version in 1.20.3-0 1.21.0-5-rc2 ; do - stop - reset relative - start $version - for path in ${STORAGE_PATHS} ; do - test -d $work_path/data/relative-$path - done - done - - stop -} - -function test_bug_storage_s3_misplace() { - local work_path=$DIR/forgejo-work-path - local s3_backend=${2:-minio} - - log_info "See also https://codeberg.org/forgejo/forgejo/issues/1338" - - for version in 1.20.2-0 1.20.3-0 ; do - log_info "Forgejo $version & $s3_backend" - stop - reset misplace-s3 - start $version $s3_backend - fixture_create - for fun in ${STORAGE_FUN} ; do - fixture_${fun}_assert_s3 - done - done - - for version in 1.18.5-0 1.19.4-0 ; do - log_info "Forgejo $version & $s3_backend" - stop - reset misplace-s3 - start $version $s3_backend - fixture_create - # - # some storage are in S3 - # - fixture_attachments_assert_s3 - fixture_lfs_assert_s3 - # - # others are in local - # - fixture_repo_archive_assert_local elsewhere/repo-archive - fixture_avatars_assert_local elsewhere/avatars - fixture_packages_assert_local elsewhere/packages - fixture_repo_avatars_assert_local elsewhere/repo-avatars - done -} - -function test_storage_stable_s3() { - local work_path=$DIR/forgejo-work-path - local s3_backend=${1:-minio} - - log_info "See also https://codeberg.org/forgejo/forgejo/issues/1338" - - for version in 1.18.5-0 1.19.4-0 1.20.2-0 1.20.3-0 ; do - log_info "Forgejo $version & $s3_backend" - stop - reset stable-s3 - start $version $s3_backend - fixture_create - for fun in ${STORAGE_FUN} ; do - fixture_${fun}_assert_s3 - done - done -} - -function test_bug_storage_misplace() { - local work_path=$DIR/forgejo-work-path - - log_info "See also https://codeberg.org/forgejo/forgejo/pulls/1225" - - log_info "using < 1.20 and conflicting sections misplace storage" - for version in 1.18.5-0 1.19.4-0 ; do - stop - reset misplace - start $version - # - # some storage are where they should be - # - test -d $work_path/data/packages - test -d $work_path/data/repo-archive - test -d $work_path/data/attachments - # - # others are under APP_DATA_PATH - # - test -d $work_path/elsewhere/lfs - test -d $work_path/elsewhere/avatars - test -d $work_path/elsewhere/repo-avatars - done - - log_info "using < 1.20.[12]-0 and conflicting sections ignores [storage.*]" - for version in 1.20.2-0 ; do - stop - reset misplace - start $version - for path in ${STORAGE_PATHS} ; do - test -d $work_path/elsewhere/$path - done - done - - stop - - log_info "upgrading from 1.20.2-0 with conflicting sections fails" - download 1.20.3-0 - timeout 60 $DIR/forgejo-1.20.3-0 --config $work_path/app.ini --work-path $work_path || true - for path in ${STORAGE_PATHS} ; do - if ! grep --fixed-strings --quiet "[storage.$path] may conflict" $work_path/log/forgejo.log ; then - cat $work_path/log/forgejo.log - return 1 - fi - done -} - -function test_successful_upgrades() { - for config in default specific ; do - log_info "using $config app.ini" - reset $config - - for version in 1.18.5-0 1.19.4-0 1.20.2-0 1.20.3-0 1.21.0-5-rc2 ; do - log_info "run $version" - cleanup_storage - start $version - verify_storage - stop - done - done -} - -function test_forgejo_database_version() { - local expected_version=$1 - local work_path=$DIR/forgejo-work-path - - actual_version=$(sqlite3 $work_path/forgejo.db "select version from forgejo_version") - test "$expected_version" = "$actual_version" -} - -function test_forgejo_database_v3_upgrades_list_table() { - local table=$1 - local work_path=$DIR/forgejo-work-path - - sqlite3 $work_path/forgejo.db ".tables $table" .exit | grep --quiet $table -} - -function test_forgejo_database_v3_upgrades() { - local table=forgejo_auth_token - - stop - - reset default - log_info "run 1.20.4-1" - start 1.20.4-1 - stop - ! test_forgejo_database_v3_upgrades_list_table $table - test_forgejo_database_version 2 - - log_info "run 1.20.5-0" - start 1.20.5-0 - stop - test_forgejo_database_v3_upgrades_list_table $table - test_forgejo_database_version 3 -} - -function run() { - local fun=$1 - shift - - echo Start running $fun - mkdir -p $DIR - > $DIR/$fun.out - tail --follow $DIR/$fun.out | sed --unbuffered -n -e "/^$PREFIX/s/^$PREFIX //p" & - pid=$! - if ! VERBOSE=true ${BASH_SOURCE[0]} $fun "$@" >& $DIR/$fun.out ; then - kill $pid - cat $DIR/$fun.out - echo Failure running $fun - return 1 - fi - kill $pid - echo Success running $fun -} - -function test_upgrades() { - run stop - run dependencies - run build_all - run test_successful_upgrades - run test_bug_storage_misplace - run test_bug_storage_merged - run test_downgrade_1.20.2_fails - run test_bug_storage_s3_misplace - run test_storage_stable_s3 minio - run test_storage_stable_s3 garage - run test_forgejo_database_v3_upgrades -} - -"$@" diff --git a/lib/ORGANIZATIONS b/lib/ORGANIZATIONS new file mode 100644 index 00000000..8c8989aa --- /dev/null +++ b/lib/ORGANIZATIONS @@ -0,0 +1 @@ +forgejo forgejo-experimental forgejo-integration diff --git a/lib/api.sh b/lib/api.sh new file mode 100644 index 00000000..cc56f506 --- /dev/null +++ b/lib/api.sh @@ -0,0 +1,148 @@ +#!/bin/bash +# Copyright 2024 The Forgejo Authors +# SPDX-License-Identifier: MIT + +API_TMPDIR=$(mktemp -d) +: ${PASSWORD:=admin1234} + +function api_user_make_admin() { + local api="$1" username="$2" + + forgejo-curl.sh api_json -X PATCH --data '{"admin":true}' $api/admin/users/$username +} + +function api_user_create() { + local api="$1" username="$2" email="$3" + log_info "(re)create user $username" + forgejo-curl.sh api_json -X DELETE $api/admin/users/$username?purge=true >&/dev/null || true + forgejo-curl.sh api_json --data '{"username":"'$username'","email":"'$email'","password":"admin1234","must_change_password":false}' $api/admin/users +} + +function user_login() { + local username=$1 + ( + export DOT=$API_TMPDIR/$username + forgejo-curl.sh logout + forgejo-curl.sh --user $username --password "admin1234" login http://${HOST_PORT} + ) +} + +function api_branch_tip() { + local api="$1" + local repo="$2" + local branch="$3" + + retry forgejo-curl.sh api_json $api/repos/$repo/branches/$branch >&/dev/null + forgejo-curl.sh api_json $api/repos/$repo/branches/$branch | jq --raw-output .commit.id +} + +function api_branch_protect() { + local api="$1" + local repo="$2" + local branch="$3" + + forgejo-curl.sh api_json -X DELETE $api/repos/${repo}/branch_protections/$branch >&/dev/null || true + forgejo-curl.sh api_json --data '{"branch_name":"'$branch'","required_approvals":1}' $api/repos/${repo}/branch_protections +} + +function api_pr_approve() { + local api="$1" + local repo="$2" + local pr="$3" + + forgejo-curl.sh api_json --data '{"event":"APPROVED"}' $api/repos/${repo}/pulls/$pr/reviews +} + +function api_pr_is_merged() { + local api="$1" + local repo="$2" + local pr="$3" + + forgejo-curl.sh api_json $api/repos/$repo/pulls/$pr >$API_TMPDIR/pr.json + $(jq -r .merged <$API_TMPDIR/pr.json) +} + +function api_pr_delete_all() { + local api="$1" + local repo="$2" + + forgejo-curl.sh api_json $api/repos/${repo}/pulls | jq --raw-output '.[] | .number' | while read pr; do + forgejo-curl.sh api_json -X DELETE $api/repos/${repo}/issues/$pr + done +} + +function api_pr_get_status() { + local api="$1" + local repo="$2" + local sha="$3" + + forgejo-curl.sh api_json $api/repos/$repo/commits/$sha/status +} + +function api_pr_check_status() { + local api="$1" + local repo="$2" + local sha="$3" + local expected_status="$4" + local expected_description="$5" + + api_pr_get_status $api $repo $sha >$API_TMPDIR/status.json + local status="$(jq --raw-output .state <$API_TMPDIR/status.json)" + local description="$(jq --raw-output .statuses[0].description <$API_TMPDIR/status.json)" + if test "$status" = "$expected_status" && test -z "$expected_description" -o "$description" = "$expected_description"; then + echo OK + elif test "$status" = "failure" -o "$status" = "success"; then + echo NOK + else + echo RETRY + fi +} + +function api_pr_wait_success() { + api_pr_wait_status success "$@" +} + +function api_pr_wait_failure() { + api_pr_wait_status failure "$@" +} + +function api_pr_wait_running() { + api_pr_wait_status pending "$@" "Has started running" +} + +function api_pr_wait_log() { + local sha="$1" expected_status="$2" expected_description="$3" + local status="$(jq --raw-output .state <$API_TMPDIR/status.json)" + local description="$(jq --raw-output .statuses[0].description <$API_TMPDIR/status.json)" + if test "$expected_description"; then + expected_description=" '$expected_description'" + fi + log_info "$sha status waiting '$expected_status'$expected_description, currently '$status' '$description'" +} + +# default loop delay is 3600 sec (1 hour) +: ${API_LOOPS:=100} +: ${API_LOOP_DELAY:=36} + +function api_pr_wait_status() { + local status="$1" + local api="$2" + local repo="$3" + local sha="$4" + local description="$5" + + for i in $(seq $API_LOOPS); do + if test $(api_pr_check_status "$api" "$repo" "$sha" "$status" "$description") != RETRY; then + break + fi + api_pr_wait_log "$sha" "$status" "$description" + sleep $API_LOOP_DELAY + done + if test $(api_pr_check_status "$api" "$repo" "$sha" "$status" "$description") = "OK"; then + log_info "$sha status OK" + else + api_pr_get_status $api $repo $sha | jq .statuses + log_info "$sha status NOK" + return 1 + fi +} diff --git a/lib/build.sh b/lib/build.sh new file mode 100755 index 00000000..8fac7201 --- /dev/null +++ b/lib/build.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# Copyright 2024 The Forgejo Authors +# SPDX-License-Identifier: MIT + +set -ex + +SELF_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +version=$1 +dir_binaries=$2 + +v=$(echo $version | sed -E -e 's/^([0-9]+\.[0-9]+).*/\1/') +src=$dir_binaries/src-$v +read url ref semver <$SELF_DIR/../forgejo/sources/$v + +if ! test -d $src; then + mkdir -p $src + cd $src + git init + git remote add origin $url +else + cd $src +fi + +if ! [[ "$ref" =~ ^refs/ ]]; then + ref=refs/heads/$ref +fi +for retry in 1 2 3; do + if timeout 15m git fetch --update-head-ok origin +$ref:$ref; then + break + else + echo "Retry git fetch in 60 seconds" + sleep 60 + fi +done +git fetch --update-head-ok origin +$ref:$ref +git switch --force-create $v $ref + +export TAGS="bindata sqlite sqlite_unlock_notify" FORGEJO_VERSION=$semver EXTRA_GOFLAGS="-cover" +make deps-backend backend +make generate forgejo +cp -a forgejo $dir_binaries/forgejo-$v-dev diff --git a/lib/lib.sh b/lib/lib.sh index f5155c0b..b1e9409f 100644 --- a/lib/lib.sh +++ b/lib/lib.sh @@ -2,13 +2,486 @@ # Copyright 2024 The Forgejo Authors # SPDX-License-Identifier: MIT -set -e +LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +source $LIB_DIR/api.sh + +if ${VERBOSE:-false}; then + set -ex + PS4='${BASH_SOURCE[0]}:$LINENO: ${FUNCNAME[0]}: ' +else + set -e +fi + set -o pipefail export DEBIAN_FRONTEND=noninteractive -if test $(id -u) != 0 ; then - SUDO=sudo +if test $(id -u) != 0; then + SUDO=sudo fi -PS4='${BASH_SOURCE[0]}:$LINENO: ${FUNCNAME[0]}: ' +IP=$(hostname -I | cut -f1 -d' ') + +# +# Forgejo releases for which a branch exists (7.0/forgejo etc.) +# +RELEASE_NUMBERS="11.0 14.0 15.0" + +PREFIX=============== +export DIR=/tmp/forgejo-end-to-end +DIR_BINARIES=/srv/forgejo-binaries +COVERAGE_DIR="$DIR/coverage" +export DOT_FORGEJO_CURL=$DIR/forgejo-curl +export DOT=$DOT_FORGEJO_CURL # for backward compatibility with forgejo-curl.sh 1.0.0 +: ${FORGEJO_USER:=root} +: ${FORGEJO_PASSWORD:=admin1234} +: ${FORGEJO_INSTANCE:=https://codeberg.org} +ORGANIZATIONS=$(cat $LIB_DIR/ORGANIZATIONS) + +function log_info() { + echo "$PREFIX $@" +} + +function dependencies() { + + if ! test -f /usr/local/bin/forgejo-curl.sh; then + $SUDO curl --fail -sS https://code.forgejo.org/forgejo/forgejo-curl/raw/branch/main/forgejo-curl.sh -o /usr/local/bin/forgejo-curl.sh + $SUDO chmod +x /usr/local/bin/forgejo-curl.sh + fi + + if ! which make curl daemon git-lfs jq sqlite3 skopeo podman podman-compose pup >/dev/null; then + $SUDO apt-get update -qq + $SUDO apt-get install -y -qq make curl daemon git-lfs jq sqlite3 skopeo podman podman-compose pup + fi + + if ! test -f /usr/local/bin/mc || ! test -f /usr/local/bin/minio; then + $SUDO curl --fail -sS https://dl.min.io/client/mc/release/linux-amd64/mc -o /usr/local/bin/mc + $SUDO curl --fail -sS https://dl.min.io/server/minio/release/linux-amd64/minio -o /usr/local/bin/minio + fi + if ! test -x /usr/local/bin/mc || ! test -x /usr/local/bin/minio; then + $SUDO chmod +x /usr/local/bin/mc + $SUDO chmod +x /usr/local/bin/minio + fi + + if ! test -f /usr/local/bin/garage >/dev/null; then + $SUDO curl --fail -sS https://garagehq.deuxfleurs.fr/_releases/v0.8.2/x86_64-unknown-linux-musl/garage -o /usr/local/bin/garage + fi + if ! test -x /usr/local/bin/garage >/dev/null; then + $SUDO chmod +x /usr/local/bin/garage + fi +} + +function retry() { + rm -f $DIR/wait-for.out + success=false + for delay in 1 1 5 5 15 15 15; do + if "$@" >>$DIR/wait-for.out 2>&1; then + success=true + break + fi + cat $DIR/wait-for.out + echo waiting $delay + sleep $delay + done + if test $success = false; then + cat $DIR/wait-for.out + return 1 + fi +} + +function get_versions() { + local releases=$1 + local page=1 + local tmp=$(mktemp) + while true; do + curl --fail -sS "$releases?limit=100&page=$page" | jq -r '.[] | .tag_name' >$tmp + cat $tmp + if ! test -s $tmp; then + break + fi + page=$(expr $page + 1) + done | grep -v -e '-rc' | sort --version-sort +} + +function full_version() { + local version=$1 + local owner=$2 + + if [[ $version =~ ^[0-9]+\.[0-9]+$ ]]; then + full_version=$(get_versions "$FORGEJO_INSTANCE/api/v1/repos/$owner/forgejo/releases" | sed -n -e "/^v$version/p" | sort --reverse --version-sort | head -1) + echo ${full_version#v} + else + echo $version + fi +} + +function download_forgejo() { + local version=$1 + + if ! test -f $DIR_BINARIES/forgejo-$version; then + mkdir -p $DIR_BINARIES + for owner in $ORGANIZATIONS; do + full_version=$(full_version $version $owner) + if test "$full_version" = ""; then + continue + fi + if wget -O $DIR_BINARIES/forgejo-$version --quiet $FORGEJO_INSTANCE/$owner/forgejo/releases/download/v$full_version/forgejo-$full_version-linux-amd64; then + break + fi + done + if test -s $DIR_BINARIES/forgejo-$version; then + if test "$version" != "$full_version"; then + log_info "downloaded Forgejo $full_version for $version" + fi + else + echo unable to download Forgejo $version + return 1 + fi + chmod +x $DIR_BINARIES/forgejo-$version + fi +} + +function download_gitea() { + local version=$1 + + if ! test -f $DIR_BINARIES/gitea-$version; then + mkdir -p $DIR_BINARIES + if [[ $version =~ ^[0-9]+\.[0-9]+$ ]]; then + full_version=$(git ls-remote --refs --tags --sort=version:refname https://git-mirror.forgejo.org/go-gitea/gitea "v$version*" | sed -n -E -e "s|^.*/v($version[\.0-9]*)$|\1|p" | tail -1) + else + full_version=$version + fi + wget -O $DIR_BINARIES/gitea-$version --quiet https://dl.gitea.com/gitea/$full_version/gitea-$full_version-linux-amd64 + + if test -s $DIR_BINARIES/gitea-$version; then + if test "$version" != "$full_version"; then + log_info "downloaded Gitea $full_version for $version" + fi + else + echo unable to download Gitea $version + return 1 + fi + chmod +x $DIR_BINARIES/gitea-$version + fi +} + +function cleanup_logs() { + local config=$1 + + local base=$(work_path_base $config) + local work_path=$DIR/$base + + rm -f $DIR/$base*.log + rm -f $work_path/log/*.log +} + +function clobber() { + rm -fr /tmp/forgejo-end-to-end +} + +: ${GITLAB_USER:=root} +: ${GITLAB_PASSWORD:=Wrobyak4} +: ${GITLAB_PORT:=8181} + +function start_gitlab_cache_load() { + local image=$1 + local d=$DIR_BINARIES/gitlab + if test -d $d; then + log_info "loading $image from $d" + skopeo copy dir:$d docker-daemon:$image + fi +} + +function start_gitlab_cache_save() { + local image=$1 + local d=$DIR_BINARIES/gitlab + if ! test -d $d; then + log_info "saving $image to $d" + skopeo copy docker-daemon:$image dir:$d + fi +} + +function start_gitlab() { + local image=$1 + local config=$2 + + start_gitlab_cache_load $image + + local GITLAB_OMNIBUS_CONFIG="nginx['listen_https'] = false ; nginx['listen_port'] = 8181 ; external_url 'http://$IP:$GITLAB_PORT'; gitlab_rails['gitlab_shell_ssh_port'] = 2221; $config" + docker run --name="test-gitlab" --shm-size=128M -d \ + -e GITLAB_OMNIBUS_CONFIG="$GITLAB_OMNIBUS_CONFIG" \ + -p 2221:22 -p $GITLAB_PORT:8181 \ + $image >&/dev/null &/dev/null +} + +function stop_forgejo() { + local config=$1 + + stop_daemon $(work_path_base $config) +} + +function start_gitea() { + local version=$1 + local config=$2 + + download_gitea $version + start_forgejo_daemon $version $DIR_BINARIES/gitea-$version $config +} + +function start_forgejo() { + local version=$1 + local config=$2 + + download_forgejo $version + start_forgejo_daemon $version $DIR_BINARIES/forgejo-$version $config +} + +function start_forgejo_daemon() { + local version=$1 + local binary=$2 + local config=$3 + + local base=$(work_path_base $config) + local work_path=$DIR/$base + mkdir -p $COVERAGE_DIR + daemon --chdir=$DIR --unsafe --env="TERM=$TERM" --env="HOME=$HOME" --env="PATH=$PATH" --env="GOCOVERDIR=$COVERAGE_DIR" --pidfile=$DIR/$base-pid --errlog=$DIR/$base-err.log --output=$DIR/$base-out.log -- $binary --config $work_path/app.ini --work-path $work_path + if ! retry grep --no-messages --quiet 'Starting server on' $work_path/log/forgejo.log; then + grep '' $DIR/$base*.log + grep '' $work_path/log/*.log 2>/dev/null + return 1 + fi + echo "$binary --config $work_path/app.ini --work-path $work_path" '"$@"' >$work_path/forgejocli + chmod +x $work_path/forgejocli + cp -a $work_path/forgejocli $DIR/forgejocli # because setup-forgejo/forgejo-runner.sh expects it here + create_user_and_login $version $config +} + +function start_minio() { + mkdir -p $DIR/minio + daemon --chdir=$DIR --unsafe \ + --env="PATH=$PATH" \ + --env=MINIO_ROOT_USER=123456 \ + --env=MINIO_ROOT_PASSWORD=12345678 \ + --env=MINIO_VOLUMES=$DIR/minio \ + --pidfile=$DIR/minio-pid --errlog=$DIR/minio-err.log --output=$DIR/minio-out.log -- /usr/local/bin/minio server + retry mc alias set testS3 http://127.0.0.1:9000 123456 12345678 >&/dev/null + mc alias set testS3 http://127.0.0.1:9000 123456 12345678 +} + +function start_garage() { + mkdir -p $DIR/garage/{data,meta} + cat >$DIR/garage/garage.toml <$work_path/app.ini +} + +function reset_minio() { + rm -fr $DIR/minio +} + +function reset_garage() { + rm -fr $DIR/garage +} + +function create_user_and_login() { + local version=$1 + local config=$2 + + local work_path=$DIR/$(work_path_base $config) + + local email="$FORGEJO_USER@example.com" + if ! $work_path/forgejocli admin user list | grep --quiet "$email"; then + $work_path/forgejocli admin user create --admin --username "$FORGEJO_USER" --password "$FORGEJO_PASSWORD" --email $email + fi + + forgejo-curl.sh logout + local scopes='--scopes ["all"]' + if echo $version | grep --quiet 1.18; then + scopes="" + fi + forgejo-curl.sh --user "$FORGEJO_USER" --password "$FORGEJO_PASSWORD" $scopes login http://$(get_host_port $config) + + local forgejo_curl=$work_path/forgejo-curl.sh + cat >$forgejo_curl <$DIR/$fun.out + tail --follow $DIR/$fun.out |& sed --unbuffered -n -e "/^$PREFIX/s/^$PREFIX //p" & + local pid=$! + if ! VERBOSE=true $SELF $fun "$@" >&$DIR/$fun.out; then + kill $pid + cat $DIR/$fun.out + echo Failure running $fun + return 1 + fi + kill $pid + echo Success running $fun +} diff --git a/forgejo/upgrades/merged-app.ini b/packages/alpine-app.ini similarity index 75% rename from forgejo/upgrades/merged-app.ini rename to packages/alpine-app.ini index 0b7150c0..21f95ffc 100644 --- a/forgejo/upgrades/merged-app.ini +++ b/packages/alpine-app.ini @@ -1,19 +1,21 @@ RUN_MODE = prod -WORK_PATH = ${WORK_PATH} +WORK_PATH = forgejo-work-path [server] APP_DATA_PATH = ${WORK_PATH}/data +DOMAIN = ${IP} HTTP_PORT = 3000 SSH_LISTEN_PORT = 2222 LFS_START_SERVER = true [database] DB_TYPE = sqlite3 +PATH = ${WORK_PATH}/forgejo.db [log] MODE = file -LEVEL = debug -ROUTER = file +LEVEL = trace +logger.router.MODE = file [log.file] FILE_NAME = forgejo.log @@ -27,6 +29,3 @@ DEFAULT_PUSH_CREATE_PRIVATE = false [actions] ENABLED = true - -[storage] -PATH = ${WORK_PATH}/merged diff --git a/packages/alpine.sh b/packages/alpine.sh index 96c619b0..ce5c4ac8 100644 --- a/packages/alpine.sh +++ b/packages/alpine.sh @@ -1,17 +1,26 @@ -#!/bin/sh -# Copyright 2024 The Forgejo Authors +# Copyright 2025 The Forgejo Authors # SPDX-License-Identifier: MIT -SELF_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +function test_packages_alpine_version() { + local alpine_version=$1 forgejo_version=$2 + stop_forgejo + reset_forgejo $PACKAGES_DIR/alpine-app.ini + start_forgejo $forgejo_version -source $SELF_DIR/../lib/lib.sh + local d=$PACKAGES_DIR/alpine + local token=$(cat $DIR/forgejo-curl/token) + local url=http://${HOST_PORT} -function main() { - local d=$SELF_DIR/alpine - local token=$(cat $DIR/forgejo-token) - local url=$(cat $DIR/forgejo-url) - - docker run --rm --volume $d:$d:ro --workdir $d docker.io/alpine:3.19 ash -c "./test.sh $url $token" + log_info "alpine:$alpine_version & Forgejo $forgejo_version" + docker run --rm --volume $d:$d:ro --workdir $d code.forgejo.org/oci/alpine:$alpine_version ash -c "./test.sh $url $token" } -"${@:-main}" +function test_packages_alpine() { + local forgejo_versions="${1:-$RELEASE_NUMBERS}" + + for alpine_version in 3.22 3.23; do + for forgejo_version in $forgejo_versions; do + test_packages_alpine_version $alpine_version $forgejo_version + done + done +} diff --git a/packages/alpine/package-source/forgejo-2173/APKBUILD b/packages/alpine/package-source/forgejo-2173/APKBUILD new file mode 100644 index 00000000..75c9dd13 --- /dev/null +++ b/packages/alpine/package-source/forgejo-2173/APKBUILD @@ -0,0 +1,24 @@ +# -*- mode: Shell-script; eval: (setq indent-tabs-mode 't); eval: (setq tab-width 4) -*- +# Maintainer: Dominic Meiser +pkgname=forgejo-2173 +pkgver=1.0 +pkgrel=0 +pkgdesc="Forgejo #2173 Reproduction" +url="https://msrd0.dev/msrd0/$pkgname" +arch="noarch" +license="custom" + +subpackages="$pkgname-openrc" + +source="forgejo_2173 forgejo_2173.init" +builddir="$srcdir" + +package() { + install -D -m755 "$srcdir/forgejo_2173" "$pkgdir"/usr/bin/forgejo_2173 + install -D -m755 "$srcdir/forgejo_2173.init" "$pkgdir"/etc/init.d/forgejo_2173 +} + +sha512sums=" +651c2a816510a18981bcd45077eb5acd6e58511d641949ddc690e326b81018d851eb7f1c88e2336eada2f216606ce2aa0569eb2d02d7c423c80705cc00acf838 forgejo_2173 +abc3b1c91bd69478e8e0d46a31148bcd5b4e7838dc35e7b601673866d7e925d70ab70d63c32df98aad060134eaaa6f957691c2c4397d85af5a77f9773de21b5b forgejo_2173.init +" diff --git a/packages/alpine/package-source/forgejo_2174 b/packages/alpine/package-source/forgejo-2173/forgejo_2173 similarity index 100% rename from packages/alpine/package-source/forgejo_2174 rename to packages/alpine/package-source/forgejo-2173/forgejo_2173 diff --git a/packages/alpine/package-source/forgejo-2173/forgejo_2173.init b/packages/alpine/package-source/forgejo-2173/forgejo_2173.init new file mode 100755 index 00000000..b5d66cc5 --- /dev/null +++ b/packages/alpine/package-source/forgejo-2173/forgejo_2173.init @@ -0,0 +1,7 @@ +#!/sbin/openrc-run + +command="/usr/bin/forgejo_2173" + +depend() { + need net +} diff --git a/packages/alpine/package-source/APKBUILD b/packages/alpine/package-source/forgejo-2174/APKBUILD similarity index 100% rename from packages/alpine/package-source/APKBUILD rename to packages/alpine/package-source/forgejo-2174/APKBUILD diff --git a/packages/alpine/package-source/forgejo-2174/forgejo_2174 b/packages/alpine/package-source/forgejo-2174/forgejo_2174 new file mode 100755 index 00000000..b12f87b3 --- /dev/null +++ b/packages/alpine/package-source/forgejo-2174/forgejo_2174 @@ -0,0 +1,3 @@ +#!/bin/sh + +echo "Hello World" diff --git a/packages/alpine/package-source/forgejo_2174.init b/packages/alpine/package-source/forgejo-2174/forgejo_2174.init similarity index 100% rename from packages/alpine/package-source/forgejo_2174.init rename to packages/alpine/package-source/forgejo-2174/forgejo_2174.init diff --git a/packages/alpine/test.sh b/packages/alpine/test.sh index e2108797..4676e7ce 100755 --- a/packages/alpine/test.sh +++ b/packages/alpine/test.sh @@ -6,7 +6,7 @@ forgejo_token=$2 # initialize abuild apk update -apk add --no-cache alpine-sdk sudo util-linux +apk add --no-cache alpine-sdk sudo util-linux curl adduser -D user -h /home/user addgroup user abuild echo "root ALL=(ALL) ALL" >/etc/sudoers @@ -28,31 +28,36 @@ cat /home/user/.abuild/abuild.conf chown -R user:user alpine packages # build the package -sudo -u user APKBUILD=alpine/APKBUILD abuild -r +sudo -u user APKBUILD=alpine/forgejo-2174/APKBUILD abuild -r + +# build the package +sudo -u user APKBUILD=alpine/forgejo-2173/APKBUILD abuild -r # upload new package -cd packages/srv/x86_64/ +cd packages/alpine/x86_64/ for file in $(find . -name '*.apk' -type f | sed -e 's,./,,'); do - # remove old package - curl \ - --fail \ - -H "Authorization: token $forgejo_token" \ - -X DELETE \ - "$forgejo_url/api/packages/root/alpine/3.19/forgejo-2174/$file" \ - || true + # remove old package + curl \ + --fail \ + -H "Authorization: token $forgejo_token" \ + -X DELETE \ + "$forgejo_url/api/packages/root/alpine/3.21/e2e-tests/$file" || + true - # upload new package - curl \ - --fail \ - -H "Authorization: token $forgejo_token" \ - -T "$file" \ - "$forgejo_url/api/packages/root/alpine/3.19/forgejo-2174" + # upload new package + curl \ + --fail \ + -H "Authorization: token $forgejo_token" \ + -T "$file" \ + "$forgejo_url/api/packages/root/alpine/3.21/e2e-tests" done # ensure that the install-if condition works as expected apk add openrc (cd /etc/apk/keys && curl -JO $forgejo_url/api/packages/root/alpine/key) -echo "$forgejo_url/api/packages/root/alpine/3.19/forgejo-2174" >>/etc/apk/repositories -apk add forgejo-2174 -[ -e /usr/bin/forgejo_2174 ] # from the installed package +echo "$forgejo_url/api/packages/root/alpine/3.21/e2e-tests" >>/etc/apk/repositories +apk add forgejo-2174 forgejo-2173 +[ -e /usr/bin/forgejo_2174 ] # from the installed package +[ -e /usr/bin/forgejo_2173 ] # from the installed package [ -e /etc/init.d/forgejo_2174 ] # from the -openrc package installed because of the install-if condition +[ -e /etc/init.d/forgejo_2173 ] # from the -openrc package installed because of the install-if condition diff --git a/packages/packages.sh b/packages/packages.sh new file mode 100644 index 00000000..4fc9c6a4 --- /dev/null +++ b/packages/packages.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# Copyright 2024 The Forgejo Authors +# SPDX-License-Identifier: MIT + +PACKAGES_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +source $PACKAGES_DIR/alpine.sh + +function test_packages() { + local forgejo_versions="${1:-$RELEASE_NUMBERS}" + + run test_packages_alpine $forgejo_versions +} diff --git a/packages/run.sh b/packages/run.sh deleted file mode 100755 index 7a0a62e2..00000000 --- a/packages/run.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash -# Copyright 2024 The Forgejo Authors -# SPDX-License-Identifier: MIT - -SELF_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source $SELF_DIR/../lib/lib.sh - -function run() { - local package=$1 - - bash -ex $SELF_DIR/$package.sh -} - -function packages_v1_21() { - echo 'alpine' -} - -function packages_v7_0() { - packages_v1_21 -} - -function setup() { - local binary=$1 - forgejo-binary.sh setup root admin1234 $binary -} - -function teardown() { - forgejo-curl.sh logout - forgejo-binary.sh teardown -} - -function main() { - local binary="$1" - shift - export full_version="$1" - shift - export version="$1" - shift - - export DOT=$DIR/forgejo-curl - - teardown - - if test "$#" = 0 ; then - packages=$(packages_${version/./_}) - else - packages="$@" - fi - - if test "$packages" = "none" ; then - exit 0 - fi - - setup $binary - - if ! test -f "$DIR/forgejo-auth-url" ; then - echo "DIR=$DIR must be a directory with a forgejo-auth-url file" - fi - - export url=$(cat $DIR/forgejo-auth-url) - export token=$(cat $DIR/forgejo-token) - - for package in $packages ; do - echo "======================== BEGIN package-$package ===================" - if ! time run $package >& /tmp/run.out ; then - sed -e 's/^/[RUN] /' < /tmp/run.out - echo "======================== FAIL package-$package ===================" - sleep 5 # hack for Forgejo v1.21 to workaround a bug by which the last lines of the output are moved to the next step - false - else - if test "$VERBOSE" = true ; then - sed -e 's/^/[RUN] /' < /tmp/run.out - fi - fi - echo "======================== END package-$package ===================" - done -} - -main "$@" diff --git a/renovate.json b/renovate.json new file mode 100644 index 00000000..6b4cadc2 --- /dev/null +++ b/renovate.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "local>forgejo/renovate-config" + ], + "packageRules": [ + { + "description": "Separate test actions", + "matchFileNames": ["actions/**"], + "additionalBranchPrefix": "actions", + "commitMessageTopic": "{{depName}} (test actions)" + } + ] +} diff --git a/run.sh b/run.sh new file mode 100755 index 00000000..92a91611 --- /dev/null +++ b/run.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +podman build -t forgejo-e2e . +patchelf ../forgejo/forgejo --set-interpreter /lib64/ld-linux-x86-64.so.2 +podman run \ + -it --privileged \ + -v ../forgejo/gitea:/srv/forgejo-binaries/forgejo-14.0 \ + -p 3001-3003:3001-3003 \ + -p 4000:4000 \ + -p 8080:8080 \ + forgejo-e2e diff --git a/forgejo/upgrades/default-app.ini b/storage/default-app.ini similarity index 84% rename from forgejo/upgrades/default-app.ini rename to storage/default-app.ini index a51290a8..21f95ffc 100644 --- a/forgejo/upgrades/default-app.ini +++ b/storage/default-app.ini @@ -1,8 +1,9 @@ RUN_MODE = prod -WORK_PATH = ${WORK_PATH} +WORK_PATH = forgejo-work-path [server] APP_DATA_PATH = ${WORK_PATH}/data +DOMAIN = ${IP} HTTP_PORT = 3000 SSH_LISTEN_PORT = 2222 LFS_START_SERVER = true @@ -14,7 +15,7 @@ PATH = ${WORK_PATH}/forgejo.db [log] MODE = file LEVEL = trace -ROUTER = file +logger.router.MODE = file [log.file] FILE_NAME = forgejo.log diff --git a/forgejo/upgrades/specific-app.ini b/storage/specific-app.ini similarity index 90% rename from forgejo/upgrades/specific-app.ini rename to storage/specific-app.ini index d7a0badc..02629581 100644 --- a/forgejo/upgrades/specific-app.ini +++ b/storage/specific-app.ini @@ -1,8 +1,9 @@ RUN_MODE = prod -WORK_PATH = ${WORK_PATH} +WORK_PATH = forgejo-work-path [server] APP_DATA_PATH = ${WORK_PATH}/elsewhere +DOMAIN = ${IP} HTTP_PORT = 3000 SSH_LISTEN_PORT = 2222 LFS_START_SERVER = true @@ -13,7 +14,7 @@ DB_TYPE = sqlite3 [log] MODE = file LEVEL = debug -ROUTER = file +logger.router.MODE = file [log.file] FILE_NAME = forgejo.log diff --git a/forgejo/upgrades/stable-s3-app.ini b/storage/stable-s3-app.ini similarity index 89% rename from forgejo/upgrades/stable-s3-app.ini rename to storage/stable-s3-app.ini index e8c48ae2..ef4ff0bd 100644 --- a/forgejo/upgrades/stable-s3-app.ini +++ b/storage/stable-s3-app.ini @@ -1,8 +1,9 @@ RUN_MODE = prod -WORK_PATH = ${WORK_PATH} +WORK_PATH = forgejo-work-path [server] APP_DATA_PATH = ${WORK_PATH}/elsewhere +DOMAIN = ${IP} HTTP_PORT = 3000 SSH_LISTEN_PORT = 2222 LFS_START_SERVER = true @@ -13,7 +14,7 @@ DB_TYPE = sqlite3 [log] MODE = file LEVEL = debug -ROUTER = file +logger.router.MODE = file [log.file] FILE_NAME = forgejo.log diff --git a/storage/storage.sh b/storage/storage.sh new file mode 100755 index 00000000..8fdb64fc --- /dev/null +++ b/storage/storage.sh @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: MIT + +STORAGE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +STORAGE_PATHS="attachments avatars lfs packages repo-archive repo-avatars" + +function storage_reset() { + local config=$1 + reset_forgejo $STORAGE_DIR/$config-app.ini + reset_minio + reset_garage +} + +function verify_storage() { + local work_path=$DIR/forgejo-work-path + + for path in ${STORAGE_PATHS}; do + test -d $work_path/data/$path + done +} + +function cleanup_storage() { + local work_path=$DIR/forgejo-work-path + + for path in ${STORAGE_PATHS}; do + rm -fr $work_path/data/$path + done +} + +function test_storage_stable_s3() { + local work_path=$DIR/forgejo-work-path + local s3_backend=${1:-minio} + + for version in $RELEASE_NUMBERS; do + log_info "Forgejo $version & $s3_backend" + stop + storage_reset stable-s3 + start $version $s3_backend + fixture_create + for fun in ${STORAGE_FUN}; do + fixture_${fun}_assert_s3 + done + done +} + +function test_storage() { + run test_storage_stable_s3 minio + run test_storage_stable_s3 garage +} diff --git a/forgejo/upgrades/legagy-relative-app.ini b/upgrade/default-app.ini similarity index 62% rename from forgejo/upgrades/legagy-relative-app.ini rename to upgrade/default-app.ini index 130294a4..49674738 100644 --- a/forgejo/upgrades/legagy-relative-app.ini +++ b/upgrade/default-app.ini @@ -1,12 +1,19 @@ RUN_MODE = prod -WORK_PATH = ${WORK_PATH} +WORK_PATH = forgejo-work-path [server] APP_DATA_PATH = ${WORK_PATH}/data +DOMAIN = ${IP} HTTP_PORT = 3000 SSH_LISTEN_PORT = 2222 LFS_START_SERVER = true -LFS_CONTENT_PATH = relative-lfs +ENABLE_PPROF = true + +[repository] +ROOT = ${WORK_PATH}/data/forgejo-repositories + +[queue] +TYPE = immediate [database] DB_TYPE = sqlite3 @@ -14,8 +21,8 @@ PATH = ${WORK_PATH}/forgejo.db [log] MODE = file -LEVEL = debug -ROUTER = file +LEVEL = trace +logger.router.MODE = file [log.file] FILE_NAME = forgejo.log @@ -27,6 +34,5 @@ INSTALL_LOCK = true ENABLE_PUSH_CREATE_USER = true DEFAULT_PUSH_CREATE_PRIVATE = false -[picture] -AVATAR_UPLOAD_PATH = relative-avatars -REPOSITORY_AVATAR_UPLOAD_PATH = relative-repo-avatars +[actions] +ENABLED = true diff --git a/upgrade/test-pprof-upload.sh b/upgrade/test-pprof-upload.sh new file mode 100644 index 00000000..4495891a --- /dev/null +++ b/upgrade/test-pprof-upload.sh @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: MIT + +function test_upload_profiles() { + FORGEJO_URL="http://localhost:6060" + PROFILECLI_URL="http://0.0.0.0:4040" + + endpoints=("/debug/pprof/allocs" "/debug/pprof/block" "/debug/pprof/goroutine" "/debug/pprof/mutex" "/debug/pprof/profile?seconds=5") + curl -fL https://github.com/grafana/pyroscope/releases/download/v1.1.5/profilecli_1.1.5_linux_amd64.tar.gz -o profilecli.tar.gz + tar xzf profilecli.tar.gz + + for endpoint in "${endpoints[@]}"; do + output=$(basename "$endpoint") + if [[ $endpoint == *"/profile"* ]]; then + output="profile" + fi + output="${output}.pprof" + # Download the content and save it to a file + curl -s "${FORGEJO_URL}${endpoint}" -o "${output}" + ./profilecli upload ${output} --url=${PROFILECLI_URL} + + rm ${output} + done +} + +PYROSCOPE_VERSION=1.12.1 # renovate: datasource=docker depName=data.forgejo.org/oci/pyroscope + +function test_forgejo_pprof() { + stop + docker rm -f test_pyroscope + docker run --name test_pyroscope --rm -d -p 4040:4040 data.forgejo.org/oci/pyroscope:$PYROSCOPE_VERSION + + reset_forgejo $UPGRADE_DIR/default-app.ini + + for version in $RELEASE_NUMBERS; do + log_info "run $version" + start $version + test_upload_profiles + stop + done + + docker stop test_pyroscope +} diff --git a/upgrade/upgrade.sh b/upgrade/upgrade.sh new file mode 100755 index 00000000..29142499 --- /dev/null +++ b/upgrade/upgrade.sh @@ -0,0 +1,110 @@ +# SPDX-License-Identifier: MIT + +UPGRADE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +function upgrade_reset() { + local config=$1 + reset_forgejo $config + reset_minio +} + +function verify_storage() { + local work_path=$DIR/forgejo-work-path + + for path in ${STORAGE_PATHS}; do + test -d $work_path/data/$path + done +} + +function cleanup_storage() { + local work_path=$DIR/forgejo-work-path + + for path in ${STORAGE_PATHS}; do + rm -fr $work_path/data/$path + done +} + +function test_successful_upgrades() { + stop + for config in $UPGRADE_DIR/default-app.ini; do + log_info "using $config" + upgrade_reset $config + + set $RELEASE_NUMBERS + version="$1" + shift + log_info "run $version" + cleanup_storage + start $version + fixture_create + fixture_assert + doctor_run $config + + for version in $@; do + stop + log_info "run $version" + start $version + verify_storage + fixture_assert + doctor_run $config + done + + migration_assert + done +} + +function migration_assert() { + local work_path=$DIR/forgejo-work-path + local logfile=$work_path/log/forgejo.log + + grep --quiet 'ORM engine initialization successful' $logfile + if grep 'serveInstalled() \[[EW]\] Table' $logfile; then + echo "unexpected warnings in database initialization" + return 1 + fi + if grep 'Migrate() \[[EW]\]' $logfile; then + echo "unexpected warnings in database migration" + return 1 + fi +} + +function test_gitea_upgrades() { + local config=$UPGRADE_DIR/default-app.ini + # The Forgejo target migration version must be 10.0 because it is the last supported. + # https://forgejo.org/2024-12-gitea-compatibility/ + ( + echo gitea 1.21 forgejo 10.0 + echo gitea 1.22 forgejo 10.0 + ) | while read gitea gitea_version forgejo forgejo_version; do + log_info "upgrading from Gitea $gitea_version to Forgejo $forgejo_version" + stop + upgrade_reset $config + + log_info "run Gitea $gitea_version" + cleanup_storage + start_s3 minio + start_gitea $gitea_version $config + fixture_create + fixture_assert + doctor_run $config + + stop + log_info "run Forgejo $forgejo_version" + start $forgejo_version + verify_storage + fixture_assert + doctor_run $config + + migration_assert + done +} + +source $UPGRADE_DIR/test-pprof-upload.sh + +function test_upgrades() { + run dependencies + + run test_successful_upgrades + run test_forgejo_pprof + run test_gitea_upgrades +}