diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..7b6d2b2 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +Dockerfile +forgejo-runner diff --git a/.forgejo/workflows/build-release.yml b/.forgejo/workflows/build-release.yml new file mode 100644 index 0000000..874f733 --- /dev/null +++ b/.forgejo/workflows/build-release.yml @@ -0,0 +1,133 @@ +name: Build release + +on: + push: + tags: 'v*' + +jobs: + release: + runs-on: self-hosted + # root is used for testing, allow it + if: github.repository_owner == 'forgejo-integration' || github.repository_owner == 'root' + steps: + - uses: actions/checkout@v3 + + - id: verbose + run: | + # if there are no secrets, be verbose + if test -z "${{ secrets.TOKEN }}"; then + value=true + else + value=false + fi + echo "value=$value" >> "$GITHUB_OUTPUT" + echo "shell=set -x" >> "$GITHUB_OUTPUT" + + - id: registry + run: | + ${{ steps.verbose.outputs.shell }} + url="${{ env.GITHUB_SERVER_URL }}" + hostport=${url##http*://} + hostport=${hostport%%/} + echo "host-port=${hostport}" >> "$GITHUB_OUTPUT" + if ! [[ $url =~ ^http:// ]] ; then + exit 0 + fi + cat >> "$GITHUB_OUTPUT" <> "$GITHUB_OUTPUT" + echo "doer=${doer}" >> "$GITHUB_OUTPUT" + + - name: allow docker pull/push to forgejo + if: ${{ steps.registry.outputs.insecure }} + run: |- + mkdir /etc/docker + cat > /etc/docker/daemon.json < ~/.docker/config.json + env: + CI_REGISTRY: "${{ env.GITHUB_SERVER_URL }}${{ env.GITHUB_REPOSITORY_OWNER }}" + + - id: build + run: | + ${{ steps.verbose.outputs.shell }} + tag="${{ github.ref_name }}" + tag=${tag##*v} + echo "tag=$tag" >> "$GITHUB_OUTPUT" + echo "image=${{ steps.registry.outputs.host-port }}/${{ github.repository }}:${tag}" >> "$GITHUB_OUTPUT" + + - uses: https://github.com/docker/build-push-action@v4 + # workaround until https://github.com/docker/build-push-action/commit/d8823bfaed2a82c6f5d4799a2f8e86173c461aba is in @v4 or @v5 is released + env: + ACTIONS_RUNTIME_TOKEN: '' + with: + context: . + push: true + platforms: linux/amd64,linux/arm64 + tags: ${{ steps.build.outputs.image }} + + - run: | + ${{ steps.verbose.outputs.shell }} + mkdir -p release + for arch in amd64 arm64; do + docker create --platform linux/$arch --name runner ${{ steps.build.outputs.image }} + docker cp runner:/bin/forgejo-runner release/forgejo-runner-$arch + shasum -a 256 < release/forgejo-runner-$arch | cut -f1 -d ' ' > release/forgejo-runner-$arch.sha256 + docker rm runner + done + + - name: publish release (when TOKEN secret is NOT set) + if: ${{ secrets.TOKEN == '' }} + uses: https://code.forgejo.org/actions/forgejo-release@v1 + with: + direction: upload + release-dir: release + release-notes: "RELEASE-NOTES#${{ steps.build.outputs.tag }}" + token: ${{ steps.secrets.outputs.token }} + verbose: ${{ steps.verbose.outputs.value }} + + - name: publish release (when TOKEN secret is set) + if: ${{ secrets.TOKEN != '' }} + uses: https://code.forgejo.org/actions/forgejo-release@v1 + with: + direction: upload + release-dir: release + release-notes: "RELEASE-NOTES#${{ steps.build.outputs.tag }}" + token: ${{ secrets.TOKEN }} + verbose: ${{ steps.verbose.outputs.value }} diff --git a/.forgejo/workflows/integration.yml b/.forgejo/workflows/integration.yml new file mode 100644 index 0000000..895a4dc --- /dev/null +++ b/.forgejo/workflows/integration.yml @@ -0,0 +1,59 @@ +name: Integration tests for the release process + +on: + push: + paths: + - go.mod + - Dockerfile + - .forgejo/workflows/release.yml + - .forgejo/workflows/integration.yml + +jobs: + release-simulation: + runs-on: self-hosted + if: github.repository_owner != 'forgejo-integration' && github.repository_owner != 'forgejo-experimental' && github.repository_owner != 'forgejo-release' + steps: + - uses: actions/checkout@v3 + + - id: forgejo + uses: https://code.forgejo.org/actions/setup-forgejo@v1 + with: + user: root + password: admin1234 + image-version: 1.19 + lxc-ip-prefix: 10.0.9 + + - name: publish the runner release + run: | + set -x + + dir=$(mktemp -d) + trap "rm -fr $dir" EXIT + + url=http://root:admin1234@${{ steps.forgejo.outputs.host-port }} + export FORGEJO_RUNNER_LOGS="${{ steps.forgejo.outputs.runner-logs }}" + + # + # Create a new project with the runner and the release workflow only + # + rsync -a --exclude .git ./ $dir/ + rm $(find $dir/.forgejo/workflows/*.yml | grep -v release.yml) + forgejo-test-helper.sh push $dir $url root runner |& tee $dir/pushed + eval $(grep '^sha=' < $dir/pushed) + + # + # Push a tag to trigger the release workflow and wait for it to complete + # + forgejo-test-helper.sh api POST $url repos/root/runner/tags ${{ steps.forgejo.outputs.token }} --data-raw '{"tag_name": "v1.2.3", "target": "'$sha'"}' + LOOPS=180 forgejo-test-helper.sh wait_success "$url" root/runner $sha + + # + # Minimal sanity checks. e2e test is for the setup-forgejo action + # and the infrastructure playbook. + # + curl -L -sS $url/root/runner/releases/download/v1.2.3/forgejo-runner-amd64 > forgejo-runner + chmod +x forgejo-runner + ./forgejo-runner --version | grep 1.2.3 + curl -L -sS $url/root/runner/releases/download/v1.2.3/forgejo-runner-amd64.sha256 > forgejo-runner.one + shasum -a 256 < forgejo-runner | cut -f1 -d ' ' > forgejo-runner.two + diff forgejo-runner.one forgejo-runner.two diff --git a/.forgejo/workflows/publish-binary.yml b/.forgejo/workflows/publish-binary.yml new file mode 100644 index 0000000..68519d4 --- /dev/null +++ b/.forgejo/workflows/publish-binary.yml @@ -0,0 +1,40 @@ +name: Publish release + +on: + push: + tags: 'v*' + +jobs: + release: + runs-on: self-hosted + if: github.repository_owner == 'forgejo-release' && secrets.TOKEN != '' + steps: + + - name: install the certificate authority + run: | + apt-get install -qq -y wget + wget --no-check-certificate -O /usr/local/share/ca-certificates/enough.crt https://forgejo.octopuce.forgejo.org/forgejo/enough/raw/branch/main/certs/2023-05-13/ca.crt + update-ca-certificates --fresh + + - uses: actions/checkout@v3 + + - name: download release + uses: https://code.forgejo.org/actions/forgejo-release@v1 + with: + url: https://code.forgejo.org + repo: forgejo-integration/runner + direction: download + release-dir: release + download-retry: 60 + token: ${{ secrets.TOKEN }} + + - name: upload release + uses: https://code.forgejo.org/actions/forgejo-release@v1 + with: + url: https://code.forgejo.org + repo: forgejo/runner + direction: upload + release-dir: release + release-notes: "RELEASE-NOTES" + token: ${{ secrets.TOKEN }} + gpg-private-key: ${{ secrets.GPG }} diff --git a/.forgejo/workflows/publish-container-image.yml b/.forgejo/workflows/publish-container-image.yml new file mode 100644 index 0000000..f556ab2 --- /dev/null +++ b/.forgejo/workflows/publish-container-image.yml @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: MIT +name: copy container images from integration to the destination organization + +on: + push: + tags: 'v*' + +jobs: + builder: + runs-on: self-hosted + if: github.repository_owner == 'forgejo-release' && secrets.TOKEN != '' + steps: + + - name: apt-get install docker.io + run: | + DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -qq -y docker.io + + - name: login code.forgejo.org + uses: https://github.com/docker/login-action@v2 + with: + registry: code.forgejo.org + username: ${{ secrets.DOER }} + password: ${{ secrets.TOKEN }} + + - id: tag + run: | + tag="${{ github.ref_name }}" + tag=${tag##*v} + echo "tag=$tag" >> "$GITHUB_OUTPUT" + + - uses: https://code.forgejo.org/forgejo/forgejo-container-image@v1 + env: + VERIFY: 'false' + with: + url: https://code.forgejo.org + destination-owner: forgejo + owner: forgejo-integration + suffixes: ' ' + project: runner + tag: ${{ steps.tag.outputs.tag }} + doer: ${{ secrets.DOER }} + token: ${{ secrets.TOKEN }} + verbose: true diff --git a/.forgejo/workflows/test.yml b/.forgejo/workflows/test.yml new file mode 100644 index 0000000..636c4ad --- /dev/null +++ b/.forgejo/workflows/test.yml @@ -0,0 +1,24 @@ +name: checks +on: + - pull_request + - push + +env: + GOPROXY: https://goproxy.io,direct + +jobs: + lint: + name: check and test + if: github.repository_owner != 'forgejo-integration' && github.repository_owner != 'forgejo-experimental' && github.repository_owner != 'forgejo-release' + runs-on: ubuntu-latest + steps: + - uses: actions/setup-go@v3 + with: + go-version: 1.20 + - uses: actions/checkout@v3 + - name: vet checks + run: make vet + - name: build + run: make build + - name: test + run: make test diff --git a/.gitea/workflows/release-nightly.yml b/.gitea/workflows/release-nightly.yml deleted file mode 100644 index 053d6c7..0000000 --- a/.gitea/workflows/release-nightly.yml +++ /dev/null @@ -1,105 +0,0 @@ -name: release-nightly - -on: - push: - branches: [ main ] - -env: - GOPATH: /go_path - GOCACHE: /go_cache - -jobs: - goreleaser: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 # all history for all branches and tags - - uses: actions/setup-go@v3 - with: - go-version: '>=1.20.1' - - uses: https://gitea.com/actions/go-hashfiles@v0.0.1 - id: hash-go - with: - patterns: | - go.mod - go.sum - - name: cache go - id: cache-go - uses: https://github.com/actions/cache@v3 - with: - path: | - /go_path - /go_cache - key: go_path-${{ steps.hash-go.outputs.hash }} - - name: goreleaser - uses: https://github.com/goreleaser/goreleaser-action@v4 - with: - distribution: goreleaser-pro - version: latest - args: release --nightly - env: - GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} - AWS_REGION: ${{ secrets.AWS_REGION }} - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - S3_REGION: ${{ secrets.AWS_REGION }} - S3_BUCKET: ${{ secrets.AWS_BUCKET }} - release-image: - runs-on: ubuntu-latest - container: - image: catthehacker/ubuntu:act-latest - env: - DOCKER_ORG: gitea - DOCKER_LATEST: nightly - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 # all history for all branches and tags - - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - - name: Set up Docker BuildX - uses: docker/setup-buildx-action@v2 - - - name: Login to DockerHub - uses: docker/login-action@v2 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - - name: Get Meta - id: meta - run: | - echo REPO_NAME=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $2}') >> $GITHUB_OUTPUT - echo REPO_VERSION=$(git describe --tags --always | sed 's/^v//') >> $GITHUB_OUTPUT - - - name: Build and push - uses: docker/build-push-action@v4 - env: - ACTIONS_RUNTIME_TOKEN: '' # See https://gitea.com/gitea/act_runner/issues/119 - with: - context: . - file: ./Dockerfile - platforms: | - linux/amd64 - linux/arm64 - push: true - tags: | - ${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ env.DOCKER_LATEST }} - - - name: Build and push dind-rootless - uses: docker/build-push-action@v4 - env: - ACTIONS_RUNTIME_TOKEN: '' # See https://gitea.com/gitea/act_runner/issues/119 - with: - context: . - file: ./Dockerfile.rootless - platforms: | - linux/amd64 - linux/arm64 - push: true - tags: | - ${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ env.DOCKER_LATEST }}-dind-rootless diff --git a/.gitea/workflows/release-tag.yml b/.gitea/workflows/release-tag.yml deleted file mode 100644 index e7c1173..0000000 --- a/.gitea/workflows/release-tag.yml +++ /dev/null @@ -1,118 +0,0 @@ -name: release-tag - -on: - push: - tags: - - '*' - -env: - GOPATH: /go_path - GOCACHE: /go_cache - -jobs: - goreleaser: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 # all history for all branches and tags - - uses: actions/setup-go@v3 - with: - go-version: '>=1.20.1' - - uses: https://gitea.com/actions/go-hashfiles@v0.0.1 - id: hash-go - with: - patterns: | - go.mod - go.sum - - name: cache go - id: cache-go - uses: https://github.com/actions/cache@v3 - with: - path: | - /go_path - /go_cache - key: go_path-${{ steps.hash-go.outputs.hash }} - - name: Import GPG key - id: import_gpg - uses: https://github.com/crazy-max/ghaction-import-gpg@v5 - with: - gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} - passphrase: ${{ secrets.PASSPHRASE }} - fingerprint: CC64B1DB67ABBEECAB24B6455FC346329753F4B0 - - name: goreleaser - uses: https://github.com/goreleaser/goreleaser-action@v4 - with: - distribution: goreleaser-pro - version: latest - args: release - env: - GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} - AWS_REGION: ${{ secrets.AWS_REGION }} - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - S3_REGION: ${{ secrets.AWS_REGION }} - S3_BUCKET: ${{ secrets.AWS_BUCKET }} - GORELEASER_FORCE_TOKEN: 'gitea' - GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} - release-image: - runs-on: ubuntu-latest - container: - image: catthehacker/ubuntu:act-latest - env: - DOCKER_ORG: gitea - DOCKER_LATEST: latest - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 # all history for all branches and tags - - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - - name: Set up Docker BuildX - uses: docker/setup-buildx-action@v2 - - - name: Login to DockerHub - uses: docker/login-action@v2 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - - name: Get Meta - id: meta - run: | - echo REPO_NAME=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $2}') >> $GITHUB_OUTPUT - echo REPO_VERSION=$(git describe --tags --always | sed 's/^v//') >> $GITHUB_OUTPUT - - - name: Build and push - uses: docker/build-push-action@v4 - env: - ACTIONS_RUNTIME_TOKEN: '' # See https://gitea.com/gitea/act_runner/issues/119 - with: - context: . - file: ./Dockerfile - platforms: | - linux/amd64 - linux/arm64 - push: true - tags: | - ${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.REPO_VERSION }} - ${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ env.DOCKER_LATEST }} - - - name: Build and push dind-rootless - uses: docker/build-push-action@v4 - env: - ACTIONS_RUNTIME_TOKEN: '' # See https://gitea.com/gitea/act_runner/issues/119 - with: - context: . - file: ./Dockerfile.rootless - platforms: | - linux/amd64 - linux/arm64 - push: true - tags: | - ${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.REPO_VERSION }}-dind-rootless - ${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ env.DOCKER_LATEST }}-dind-rootless diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml deleted file mode 100644 index 73fbd00..0000000 --- a/.gitea/workflows/test.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: checks -on: - - push - - pull_request - -env: - GOPATH: /go_path - GOCACHE: /go_cache - -jobs: - lint: - name: check and test - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: '>=1.20.1' - - uses: https://gitea.com/actions/go-hashfiles@v0.0.1 - id: hash-go - with: - patterns: | - go.mod - go.sum - - name: cache go - id: cache-go - uses: https://github.com/actions/cache@v3 - with: - path: | - /go_path - /go_cache - key: go_path-${{ steps.hash-go.outputs.hash }} - - name: vet checks - run: make vet - - name: build - run: make build - - name: test - run: make test diff --git a/.gitignore b/.gitignore index 38e1b26..3a3808c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ -act_runner +*~ + +forgejo-runner .env .runner coverage.txt diff --git a/.goreleaser.checksum.sh b/.goreleaser.checksum.sh deleted file mode 100644 index a11b71d..0000000 --- a/.goreleaser.checksum.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -set -e - -if [ -z "$1" ]; then - echo "usage: $0 " - exit 1 -fi - -SUM=$(shasum -a 256 "$1" | cut -d' ' -f1) -BASENAME=$(basename "$1") -echo -n "${SUM} ${BASENAME}" > "$1".sha256 \ No newline at end of file diff --git a/.goreleaser.yaml b/.goreleaser.yaml deleted file mode 100644 index c75dad1..0000000 --- a/.goreleaser.yaml +++ /dev/null @@ -1,115 +0,0 @@ -before: - hooks: - - go mod tidy - -builds: -- env: - - CGO_ENABLED=0 - goos: - - darwin - - linux - - windows - - freebsd - goarch: - - amd64 - - arm - - arm64 - goarm: - - "5" - - "6" - - "7" - ignore: - - goos: darwin - goarch: arm - - goos: darwin - goarch: ppc64le - - goos: darwin - goarch: s390x - - goos: windows - goarch: ppc64le - - goos: windows - goarch: s390x - - goos: windows - goarch: arm - goarm: "5" - - goos: windows - goarch: arm - goarm: "6" - - goos: windows - goarch: arm - goarm: "7" - - goos: windows - goarch: arm64 - - goos: freebsd - goarch: ppc64le - - goos: freebsd - goarch: s390x - - goos: freebsd - goarch: arm - goarm: "5" - - goos: freebsd - goarch: arm - goarm: "6" - - goos: freebsd - goarch: arm - goarm: "7" - - goos: freebsd - goarch: arm64 - flags: - - -trimpath - ldflags: - - -s -w -X gitea.com/gitea/act_runner/internal/pkg/ver.version={{ .Summary }} - binary: >- - {{ .ProjectName }}- - {{- .Version }}- - {{- .Os }}- - {{- if eq .Arch "amd64" }}amd64 - {{- else if eq .Arch "amd64_v1" }}amd64 - {{- else if eq .Arch "386" }}386 - {{- else }}{{ .Arch }}{{ end }} - {{- if .Arm }}-{{ .Arm }}{{ end }} - no_unique_dist_dir: true - hooks: - post: - - cmd: xz -k -9 {{ .Path }} - dir: ./dist/ - - cmd: sh .goreleaser.checksum.sh {{ .Path }} - - cmd: sh .goreleaser.checksum.sh {{ .Path }}.xz - -blobs: - - - provider: s3 - bucket: "{{ .Env.S3_BUCKET }}" - region: "{{ .Env.S3_REGION }}" - folder: "act_runner/{{.Version}}" - extra_files: - - glob: ./**.xz - - glob: ./**.sha256 - -archives: - - format: binary - name_template: "{{ .Binary }}" - allow_different_binary_count: true - -checksum: - name_template: 'checksums.txt' - extra_files: - - glob: ./**.xz - -snapshot: - name_template: "{{ .Branch }}-devel" - -nightly: - name_template: "nightly" - -gitea_urls: - api: https://gitea.com/api/v1 - download: https://gitea.com - -release: - extra_files: - - glob: ./**.xz - - glob: ./**.xz.sha256 - -# yaml-language-server: $schema=https://goreleaser.com/static/schema-pro.json -# vim: set ts=2 sw=2 tw=0 fo=cnqoj diff --git a/Dockerfile b/Dockerfile index 478938f..eb15271 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,15 @@ -FROM golang:1.20-alpine3.18 as builder -# Do not remove `git` here, it is required for getting runner version when executing `make build` -RUN apk add --no-cache make git +#Build stage +FROM golang:1.20-alpine3.18 AS build-env -COPY . /opt/src/act_runner -WORKDIR /opt/src/act_runner +RUN apk --no-cache add build-base git -RUN make clean && make build +COPY . /srv +WORKDIR /srv +RUN make build FROM alpine:3.18 -RUN apk add --no-cache git bash tini +LABEL maintainer="contact@forgejo.org" -COPY --from=builder /opt/src/act_runner/act_runner /usr/local/bin/act_runner -COPY scripts/run.sh /opt/act/run.sh +COPY --from=build-env /srv/forgejo-runner /bin/forgejo-runner -ENTRYPOINT ["/sbin/tini","--","/opt/act/run.sh"] +ENTRYPOINT ["/bin/forgejo-runner"] diff --git a/LICENSE b/LICENSE index 4ee9327..ce49c38 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,4 @@ +Copyright (c) 2023 The Forgejo Authors Copyright (c) 2022 The Gitea Authors Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/Makefile b/Makefile index 2e6c48e..a6bac55 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ DIST := dist -EXECUTABLE := act_runner +EXECUTABLE := forgejo-runner GOFMT ?= gofumpt -l DIST := dist DIST_DIRS := $(DIST)/binaries $(DIST)/release @@ -21,11 +21,7 @@ DOCKER_TAG ?= nightly DOCKER_REF := $(DOCKER_IMAGE):$(DOCKER_TAG) DOCKER_ROOTLESS_REF := $(DOCKER_IMAGE):$(DOCKER_TAG)-dind-rootless -ifneq ($(shell uname), Darwin) - EXTLDFLAGS = -extldflags "-static" $(null) -else - EXTLDFLAGS = -endif +EXTLDFLAGS = -extldflags "-static" $(null) ifeq ($(HAS_GO), GO) GOPATH ?= $(shell $(GO) env GOPATH) @@ -117,7 +113,7 @@ install: $(GOFILES) build: go-check $(EXECUTABLE) $(EXECUTABLE): $(GOFILES) - $(GO) build -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o $@ + $(GO) build -v -tags 'netgo osusergo $(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o $@ .PHONY: deps-backend deps-backend: diff --git a/README.md b/README.md index f031dca..9590f6a 100644 --- a/README.md +++ b/README.md @@ -1,93 +1,122 @@ -# act runner +# Forgejo Runner -Act runner is a runner for Gitea based on [Gitea fork](https://gitea.com/gitea/act) of [act](https://github.com/nektos/act). +A daemon that connects to a Forgejo instance and runs jobs for continous integration. The high level [installation instructions](https://forgejo.org/docs/next/admin/actions/) are part of the Forgejo documentation. -## Installation +# Configuration -### Prerequisites +Display the usage with `forgejo-runner --help`. -Docker Engine Community version is required for docker mode. To install Docker CE, follow the official [install instructions](https://docs.docker.com/engine/install/). +For more information on the configuration file, see the [commented example](internal/pkg/config/config.example.yaml). -### Download pre-built binary +# Hacking -Visit [here](https://dl.gitea.com/act_runner/) and download the right version for your platform. +The Forgejo runner depends on [a fork of ACT](https://code.forgejo.org/forgejo/act) and is a dependency of the [setup-forgejo action](https://code.forgejo.org/actions/setup-forgejo). Together they provide a development environment with end to end testing. Each repository also has some unit testing that can be used to quickly detect the simplest mistakes such as a failure to compile or static code checking failures (vulnerability, lint, etc.). -### Build from source +Assuming the modifications to the [Forgejo runner](https://code.forgejo.org/forgejo/runner) are pushed to a fork in a branch named `wip-runner-change`, a pull request will verify it compiles and the binary is sane (running `forgejo-runner --version`). It will not verify that it is able to properly run jobs when connected to a live Forgejo instance. -```bash -make build +For end to end testing, a branch should be pushed to a fork of the [setup-forgejo action](https://code.forgejo.org/actions/setup-forgejo) with a [modification to the tests](https://code.forgejo.org/actions/setup-forgejo/src/commit/ae7f03683b7b05c7d9c6aaeacaf27843de0366a4/.forgejo/workflows/integration.yml#L10-L19), similar to: + +```yaml +# +# Uncomment the following for a shortcut to debugging the Forgejo runner. +# It will build the runner from a designated repository and branch instead of +# downloading it from a canonical release. +# +./forgejo-test-helper.sh build_runner https://code.forgejo.org/earl-warren/runner wip-runner-change ``` -### Build a docker image +Where https://code.forgejo.org/earl-warren/runner is the URL of the Forgejo runner fork and `wip-runner-change` is the branch where the changes under test were pushed. When they do the `setup-forgejo` branch can be discarded. -```bash -make docker +The runner can be released by merging the `wip-runner-change` branch and by pushing a new tag, for instance `v10.2.3`. Once published, the `setup-forgejo` action can be updated to default to this latest version knowing it already passed integration tests. + +## ACT + +Assuming the modifications to [ACT](https://code.forgejo.org/forgejo/act) are pushed to a fork in a branch named `wip-act-change`, a pull request will verify it compiles. It will not verify that the Forgejo runner can compile with it. + +For verifying it is compatible with the Forgejo runner, a branch should be pushed to a fork of the [Forgejo runner](https://code.forgejo.org/forgejo/runner) (for instance `wip-runner-change`) that uses the ACT version under test in the `wip-act-change` by modifying `go.mod` to contain something like the following and running `go mod tidy`: + +``` +replace github.com/nektos/act => code.forgejo.org/earl-warren/act wip-act-change ``` -## Quickstart +Where https://code.forgejo.org/earl-warren/act is the URL of the act fork and `wip-act-change` is the branch where the changes under test were pushed. It will not verify that it is able to properly run jobs when connected to a live Forgejo instance. The `wip-runner-change` branch must, in turn, be tested as explained above. When the Forgejo runner modified to include the changes in the `wip-act-change` branch pass the end to end test of the `setup-forgejo` action, it is ready to be released. -### Register +ACT can be released by merging the `wip-act-change` branch and by pushing a new tag, for instance `v48.8.20`. Once published, the Forgejo runner can be updated to default to this latest version knowing it already passed end to end tests with something like: -```bash -./act_runner register +``` +replace github.com/nektos/act => code.forgejo.org/forgejo/act v48.8.20 ``` -And you will be asked to input: +## Local debug -1. Gitea instance URL, like `http://192.168.8.8:3000/`. You should use your gitea instance ROOT_URL as the instance argument - and you should not use `localhost` or `127.0.0.1` as instance IP; -2. Runner token, you can get it from `http://192.168.8.8:3000/admin/runners`; -3. Runner name, you can just leave it blank; -4. Runner labels, you can just leave it blank. +The repositories are checked out in the same directory: -The process looks like: +- **runner**: [Forgejo runner](https://code.forgejo.org/forgejo/runner) +- **act**: [ACT](https://code.forgejo.org/forgejo/act) +- **setup-forgejo**: [setup-forgejo](https://code.forgejo.org/actions/setup-forgejo) -```text -INFO Registering runner, arch=amd64, os=darwin, version=0.1.5. -WARN Runner in user-mode. -INFO Enter the Gitea instance URL (for example, https://gitea.com/): -http://192.168.8.8:3000/ -INFO Enter the runner token: -fe884e8027dc292970d4e0303fe82b14xxxxxxxx -INFO Enter the runner name (if set empty, use hostname: Test.local): +### Install dependencies -INFO Enter the runner labels, leave blank to use the default labels (comma-separated, for example, ubuntu-20.04:docker://node:16-bullseye,ubuntu-18.04:docker://node:16-buster,linux_arm:host): +The dependencies are installed manually or with: -INFO Registering runner, name=Test.local, instance=http://192.168.8.8:3000/, labels=[ubuntu-latest:docker://node:16-bullseye ubuntu-22.04:docker://node:16-bullseye ubuntu-20.04:docker://node:16-bullseye ubuntu-18.04:docker://node:16-buster]. -DEBU Successfully pinged the Gitea instance server -INFO Runner registered successfully. +```shell +setup-forgejo/forgejo-dependencies.sh ``` -You can also register with command line arguments. +### Build the Forgejo runner with the local ACT -```bash -./act_runner register --instance http://192.168.8.8:3000 --token --no-interactive +The Forgejo runner is rebuilt with the ACT directory by changing the `runner/go.mod` file to: + +``` +replace github.com/nektos/act => ../act ``` -If the registry succeed, it will run immediately. Next time, you could run the runner directly. +Running: -### Run - -```bash -./act_runner daemon +``` +cd runner ; go mod tidy ``` -### Configuration +Building: -You can also configure the runner with a configuration file. -The configuration file is a YAML file, you can generate a sample configuration file with `./act_runner generate-config`. - -```bash -./act_runner generate-config > config.yaml +```shell +cd runner ; rm -f forgejo-runner ; make forgejo-runner ``` -You can specify the configuration file path with `-c`/`--config` argument. +### Run Forgejo and the runner -```bash -./act_runner -c config.yaml register # register with config file -./act_runner -c config.yaml daemon # run with config file +A Forgejo instance is launched with: + +```shell +cd setup-forgejo ; ./forgejo.sh setup +firefox http://$(cat forgejo-ip):3000 ``` -### Example Deployments +The user is `root` with password `admin1234`. The runner is registered with: -Check out the [examples](examples) directory for sample deployment types. +``` +cd setup-forgejo +docker exec --user 1000 forgejo forgejo actions generate-runner-token > forgejo-runner-token +../runner/forgejo-runner register --no-interactive --instance "http://$(cat forgejo-ip):3000/" --name runner --token $(cat forgejo-runner-token) --labels docker:docker://node:16-bullseye,self-hosted +``` + +And launched in debug mode with: + +```shell +cd setup-forgejo ; ACTIONS_STEP_DEBUG=true ../runner/forgejo-runner daemon +``` + +### Try a sample workflow + +From the Forgejo web interface, create a repository and add the following to `.forgejo/workflows/try.yaml`. It will launch the job and the result can be observed from the `actions` tab. + +```yaml +on: [push] +jobs: + ls: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: | + ls ${{ github.workspace }} +``` diff --git a/go.mod b/go.mod index 9e0c5b8..df7e9f7 100644 --- a/go.mod +++ b/go.mod @@ -89,4 +89,4 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect ) -replace github.com/nektos/act => gitea.com/gitea/act v0.246.1 +replace github.com/nektos/act => code.forgejo.org/forgejo/act v1.7.0 diff --git a/go.sum b/go.sum index a7d092c..8a340c0 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ +code.forgejo.org/forgejo/act v1.7.0 h1:BQA0jPla4khQFcNCI2Bbr+qK9PsRE1DFtG/YXSrhARU= +code.forgejo.org/forgejo/act v1.7.0/go.mod h1:oU/5klyP5O+J2psPS3t50t09+SNVg+fZ/jN4lDZAq1U= code.gitea.io/actions-proto-go v0.3.0 h1:9Tvg8+TaaCXPKi6EnWl9vVgs2VZsj1Cs5afnsHa4AmM= code.gitea.io/actions-proto-go v0.3.0/go.mod h1:00ys5QDo1iHN1tHNvvddAcy2W/g+425hQya1cCSvq9A= code.gitea.io/gitea-vet v0.2.3-0.20230113022436-2b1561217fa5 h1:daBEK2GQeqGikJESctP5Cu1i33z5ztAD4kyQWiw185M= code.gitea.io/gitea-vet v0.2.3-0.20230113022436-2b1561217fa5/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= -gitea.com/gitea/act v0.246.1 h1:/HGPW/VqpvlDYgnCQNp1/cIPKwEhiwpYxx4r+xrUwIk= -gitea.com/gitea/act v0.246.1/go.mod h1:oU/5klyP5O+J2psPS3t50t09+SNVg+fZ/jN4lDZAq1U= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= diff --git a/internal/app/cmd/cmd.go b/internal/app/cmd/cmd.go index f6d2bda..a95c473 100644 --- a/internal/app/cmd/cmd.go +++ b/internal/app/cmd/cmd.go @@ -17,8 +17,8 @@ import ( func Execute(ctx context.Context) { // ./act_runner rootCmd := &cobra.Command{ - Use: "act_runner [event name to run]\nIf no event name passed, will default to \"on: push\"", - Short: "Run GitHub actions locally by specifying the event name (e.g. `push`) or an action name directly.", + Use: "forgejo-runner [event name to run]\nIf no event name passed, will default to \"on: push\"", + Short: "Run Forgejo Actions locally by specifying the event name (e.g. `push`) or an action name directly.", Args: cobra.MaximumNArgs(1), Version: ver.Version(), SilenceUsage: true, @@ -35,7 +35,7 @@ func Execute(ctx context.Context) { RunE: runRegister(ctx, ®Args, &configFile), // must use a pointer to regArgs } registerCmd.Flags().BoolVar(®Args.NoInteractive, "no-interactive", false, "Disable interactive mode") - registerCmd.Flags().StringVar(®Args.InstanceAddr, "instance", "", "Gitea instance address") + registerCmd.Flags().StringVar(®Args.InstanceAddr, "instance", "", "Forgejo instance address") registerCmd.Flags().StringVar(®Args.Token, "token", "", "Runner token") registerCmd.Flags().StringVar(®Args.RunnerName, "name", "", "Runner name") registerCmd.Flags().StringVar(®Args.Labels, "labels", "", "Runner tags, comma separated") diff --git a/internal/app/cmd/exec.go b/internal/app/cmd/exec.go index 9317701..59f3a2c 100644 --- a/internal/app/cmd/exec.go +++ b/internal/app/cmd/exec.go @@ -404,7 +404,7 @@ func runExec(ctx context.Context, execArgs *executeArgs) func(cmd *cobra.Command NoSkipCheckout: execArgs.noSkipCheckout, // PresetGitHubContext: preset, // EventJSON: string(eventJSON), - ContainerNamePrefix: fmt.Sprintf("GITEA-ACTIONS-TASK-%s", eventName), + ContainerNamePrefix: fmt.Sprintf("FORGEJO-ACTIONS-TASK-%s", eventName), ContainerMaxLifetime: maxLifetime, ContainerNetworkMode: container.NetworkMode(execArgs.network), DefaultActionInstance: execArgs.defaultActionsUrl, @@ -458,7 +458,7 @@ func loadExecCmd(ctx context.Context) *cobra.Command { execCmd.Flags().BoolVarP(&execArg.runList, "list", "l", false, "list workflows") execCmd.Flags().StringVarP(&execArg.job, "job", "j", "", "run a specific job ID") execCmd.Flags().StringVarP(&execArg.event, "event", "E", "", "run a event name") - execCmd.PersistentFlags().StringVarP(&execArg.workflowsPath, "workflows", "W", "./.gitea/workflows/", "path to workflow file(s)") + execCmd.PersistentFlags().StringVarP(&execArg.workflowsPath, "workflows", "W", "./.forgejo/workflows/", "path to workflow file(s)") execCmd.PersistentFlags().StringVarP(&execArg.workdir, "directory", "C", ".", "working directory") execCmd.PersistentFlags().BoolVarP(&execArg.noWorkflowRecurse, "no-recurse", "", false, "Flag to disable running workflows from subdirectories of specified path in '--workflows'/'-W' flag") execCmd.Flags().BoolVarP(&execArg.autodetectEvent, "detect-event", "", false, "Use first event type from workflow as event that triggered the workflow") @@ -480,7 +480,7 @@ func loadExecCmd(ctx context.Context) *cobra.Command { execCmd.PersistentFlags().StringVarP(&execArg.artifactServerPath, "artifact-server-path", "", ".", "Defines the path where the artifact server stores uploads and retrieves downloads from. If not specified the artifact server will not start.") execCmd.PersistentFlags().StringVarP(&execArg.artifactServerAddr, "artifact-server-addr", "", "", "Defines the address where the artifact server listens") execCmd.PersistentFlags().StringVarP(&execArg.artifactServerPort, "artifact-server-port", "", "34567", "Defines the port where the artifact server listens (will only bind to localhost).") - execCmd.PersistentFlags().StringVarP(&execArg.defaultActionsUrl, "default-actions-url", "", "https://github.com", "Defines the default url of action instance.") + execCmd.PersistentFlags().StringVarP(&execArg.defaultActionsUrl, "default-actions-url", "", "https://code.forgejo.org", "Defines the default url of action instance.") execCmd.PersistentFlags().BoolVarP(&execArg.noSkipCheckout, "no-skip-checkout", "", false, "Do not skip actions/checkout") execCmd.PersistentFlags().BoolVarP(&execArg.debug, "debug", "d", false, "enable debug log") execCmd.PersistentFlags().BoolVarP(&execArg.dryrun, "dryrun", "n", false, "dryrun mode") diff --git a/internal/app/cmd/register.go b/internal/app/cmd/register.go index fcea74d..a923a32 100644 --- a/internal/app/cmd/register.go +++ b/internal/app/cmd/register.go @@ -91,10 +91,7 @@ const ( ) var defaultLabels = []string{ - "ubuntu-latest:docker://node:16-bullseye", - "ubuntu-22.04:docker://node:16-bullseye", // There's no node:16-bookworm yet - "ubuntu-20.04:docker://node:16-bullseye", - "ubuntu-18.04:docker://node:16-buster", + "docker:docker://node:16-bullseye", } type registerInputs struct { @@ -237,7 +234,7 @@ func printStageHelp(stage registerStage) { case StageOverwriteLocalConfig: log.Infoln("Runner is already registered, overwrite local config? [y/N]") case StageInputInstance: - log.Infoln("Enter the Gitea instance URL (for example, https://gitea.com/):") + log.Infoln("Enter the Forgejo instance URL (for example, https://next.forgejo.org/):") case StageInputToken: log.Infoln("Enter the runner token:") case StageInputRunnerName: @@ -315,11 +312,11 @@ func doRegister(cfg *config.Config, inputs *registerInputs) error { } if err != nil { log.WithError(err). - Errorln("Cannot ping the Gitea instance server") + Errorln("Cannot ping the Forgejo instance server") // TODO: if ping failed, retry or exit time.Sleep(time.Second) } else { - log.Debugln("Successfully pinged the Gitea instance server") + log.Debugln("Successfully pinged the Forgejo instance server") break } } diff --git a/internal/app/run/runner.go b/internal/app/run/runner.go index abbfd34..6a50194 100644 --- a/internal/app/run/runner.go +++ b/internal/app/run/runner.go @@ -48,6 +48,13 @@ func NewRunner(cfg *config.Config, reg *config.Registration, cli client.Client) ls = append(ls, l) } } + + if cfg.Runner.Envs == nil { + cfg.Runner.Envs = make(map[string]string, 10) + } + + cfg.Runner.Envs["GITHUB_SERVER_URL"] = reg.Address + envs := make(map[string]string, len(cfg.Runner.Envs)) for k, v := range cfg.Runner.Envs { envs[k] = v @@ -175,7 +182,7 @@ func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report. runnerConfig := &runner.Config{ // On Linux, Workdir will be like "///" // On Windows, Workdir will be like "\\\" - Workdir: filepath.FromSlash(fmt.Sprintf("/%s/%s", r.cfg.Container.WorkdirParent, preset.Repository)), + Workdir: filepath.FromSlash(filepath.Clean(fmt.Sprintf("/%s/%s", r.cfg.Container.WorkdirParent, preset.Repository))), BindWorkdir: false, ActionCacheDir: filepath.FromSlash(r.cfg.Host.WorkdirParent), diff --git a/internal/pkg/config/config.example.yaml b/internal/pkg/config/config.example.yaml index 773fd20..51d2006 100644 --- a/internal/pkg/config/config.example.yaml +++ b/internal/pkg/config/config.example.yaml @@ -17,14 +17,14 @@ runner: # It will be ignored if it's empty or the file doesn't exist. env_file: .env # The timeout for a job to be finished. - # Please note that the Gitea instance also has a timeout (3h by default) for the job. - # So the job could be stopped by the Gitea instance if it's timeout is shorter than this. + # Please note that the Forgejo instance also has a timeout (3h by default) for the job. + # So the job could be stopped by the Forgejo instance if it's timeout is shorter than this. timeout: 3h - # Whether skip verifying the TLS certificate of the Gitea instance. + # Whether skip verifying the TLS certificate of the Forgejo instance. insecure: false - # The timeout for fetching the job from the Gitea instance. + # The timeout for fetching the job from the Forgejo instance. fetch_timeout: 5s - # The interval for fetching the job from the Gitea instance. + # The interval for fetching the job from the Forgejo instance. fetch_interval: 2s # The labels of a runner are used to determine which jobs the runner can run, and how to run them. # Like: ["macos-arm64:host", "ubuntu-latest:docker://node:16-bullseye", "ubuntu-22.04:docker://node:16-bullseye"] @@ -49,11 +49,11 @@ cache: container: # Specifies the network to which the container will connect. # Could be host, bridge or the name of a custom network. - # If it's empty, act_runner will create a network automatically. + # If it's empty, create a network automatically. network: "" # Whether to use privileged mode or not when launching task containers (privileged mode is required for Docker-in-Docker). privileged: false - # And other options to be used when the container is started (eg, --add-host=my.gitea.url:host-gateway). + # And other options to be used when the container is started (eg, --add-host=my.forgejo.url:host-gateway). options: # The parent directory of a job's working directory. # If it's empty, /workspace will be used.