5 Commits

Author SHA1 Message Date
Renovate Bot
589db33e70 fix(deps): update module github.com/docker/cli to v25.0.7+incompatible (#855)
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [github.com/docker/cli](https://github.com/docker/cli) | `v25.0.3+incompatible` → `v25.0.7+incompatible` | ![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2fdocker%2fcli/v25.0.7+incompatible?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2fdocker%2fcli/v25.0.3+incompatible/v25.0.7+incompatible?slim=true) |

---

### Release Notes

<details>
<summary>docker/cli (github.com/docker/cli)</summary>

### [`v25.0.7+incompatible`](https://github.com/docker/cli/compare/v25.0.6...v25.0.7)

[Compare Source](https://github.com/docker/cli/compare/v25.0.6...v25.0.7)

### [`v25.0.6+incompatible`](https://github.com/docker/cli/compare/v25.0.5...v25.0.6)

[Compare Source](https://github.com/docker/cli/compare/v25.0.5...v25.0.6)

### [`v25.0.5+incompatible`](https://github.com/docker/cli/compare/v25.0.4...v25.0.5)

[Compare Source](https://github.com/docker/cli/compare/v25.0.4...v25.0.5)

### [`v25.0.4+incompatible`](https://github.com/docker/cli/compare/v25.0.3...v25.0.4)

[Compare Source](https://github.com/docker/cli/compare/v25.0.3...v25.0.4)

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xNDEuNSIsInVwZGF0ZWRJblZlciI6IjQzLjE0MS41IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://gitea.com/gitea/act_runner/pulls/855
Reviewed-by: silverwind <2021+silverwind@noreply.gitea.com>
Co-authored-by: Renovate Bot <renovate-bot@gitea.com>
Co-committed-by: Renovate Bot <renovate-bot@gitea.com>
2026-04-27 01:01:35 +00:00
Renovate Bot
1032f857a1 fix(deps): update module connectrpc.com/connect to v1.19.2 (#854)
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [connectrpc.com/connect](https://github.com/connectrpc/connect-go) | `v1.19.1` → `v1.19.2` | ![age](https://developer.mend.io/api/mc/badges/age/go/connectrpc.com%2fconnect/v1.19.2?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/connectrpc.com%2fconnect/v1.19.1/v1.19.2?slim=true) |

---

### Release Notes

<details>
<summary>connectrpc/connect-go (connectrpc.com/connect)</summary>

### [`v1.19.2`](https://github.com/connectrpc/connect-go/releases/tag/v1.19.2)

[Compare Source](https://github.com/connectrpc/connect-go/compare/v1.19.1...v1.19.2)

#### What's Changed

##### Governance

- Add [@&#8203;timostamm](https://github.com/timostamm) as a maintainer in [#&#8203;905](https://github.com/connectrpc/connect-go/pull/905) 🎉

##### Bugfixes

- Use 'deadline\_exceeded' instead of 'canceled' on HTTP/2 cancelation when appropriate by [@&#8203;jhump](https://github.com/jhump) in [#&#8203;904](https://github.com/connectrpc/connect-go/pull/904)
- Fix nil pointer deref in duplexHTTPCall under concurrent Send + CloseAndReceive by [@&#8203;simonferquel](https://github.com/simonferquel) in [#&#8203;919](https://github.com/connectrpc/connect-go/pull/919)

##### Other changes

- Refactor memhttptest to work with Go 1.25 synctest by [@&#8203;codefromthecrypt](https://github.com/codefromthecrypt) in [#&#8203;881](https://github.com/connectrpc/connect-go/pull/881)
- Doc clarifications by [@&#8203;emcfarlane](https://github.com/emcfarlane) ([#&#8203;911](https://github.com/connectrpc/connect-go/issues/911), [#&#8203;912](https://github.com/connectrpc/connect-go/issues/912)) and [@&#8203;stefanvanburen](https://github.com/stefanvanburen) ([#&#8203;906](https://github.com/connectrpc/connect-go/issues/906))

#### New Contributors

- [@&#8203;codefromthecrypt](https://github.com/codefromthecrypt) made their first contribution in [#&#8203;881](https://github.com/connectrpc/connect-go/pull/881)
- [@&#8203;simonferquel](https://github.com/simonferquel) made their first contribution in [#&#8203;919](https://github.com/connectrpc/connect-go/pull/919)

**Full Changelog**:

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xNDEuNSIsInVwZGF0ZWRJblZlciI6IjQzLjE0MS41IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://gitea.com/gitea/act_runner/pulls/854
Reviewed-by: silverwind <2021+silverwind@noreply.gitea.com>
Co-authored-by: Renovate Bot <renovate-bot@gitea.com>
Co-committed-by: Renovate Bot <renovate-bot@gitea.com>
2026-04-27 01:01:16 +00:00
silverwind
e56b984c04 fix: wait for docker supervise dir before s6-svwait (#851)
`s6-svscan` starts services in parallel, so `act_runner/run` could invoke `s6-svwait` before s6 had created the docker service's `supervise/` directory, failing with `s6-svwait: fatal: unable to s6_svstatus_read: No such file or directory`. Poll for the directory before waiting.

Fixes #760

---
This PR was written with the help of Claude Opus 4.7

Reviewed-on: https://gitea.com/gitea/runner/pulls/851
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-committed-by: silverwind <me@silverwind.io>
2026-04-26 22:50:48 +00:00
silverwind
fa5334eb24 fix: Heartbeat ReportState for long-running silent jobs (#852)
Fixes #826.

Regressed in f2d54556 (#819, "perf: reduce runner-to-server connection load with adaptive reporting and polling"). That change added an early-return in `ReportState` whenever there was no state change and no pending outputs, so jobs that produce no log output and no step transitions for many minutes (e.g. a Linux kernel build) stop heartbeating. The server eventually marks the task as orphaned and cancels it while the runner is still executing.

The fix tracks the last successful `UpdateTask` time in an atomic and keeps the no-op skip only while the previous report is younger than `stateReportInterval`. The periodic state ticker fires at exactly `stateReportInterval`, so silent jobs now heartbeat each tick; redundant sends from a `stateNotify` firing right after a tick are still suppressed, preserving the perf intent of #819.

Test added: `TestReporter_StateHeartbeat` asserts the skip path within the interval and the heartbeat path after the interval elapses.

---
This PR was written with the help of Claude Opus 4.7

Reviewed-on: https://gitea.com/gitea/runner/pulls/852
Reviewed-by: Nicolas <bircni@icloud.com>
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-by: ChristopherHX <38043+christopherhx@noreply.gitea.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-committed-by: silverwind <me@silverwind.io>
2026-04-26 22:49:39 +00:00
Michael Hoang
7c6f1261d4 fix: fetch when other refs get force-pushed (#846)
Due to `NewGitCloneExecutor` fetching all the refs (rather than `GoGitActionCache`), if any refs move in a non-fast-forward fashion, this causes the entire action update to fail. As GitHub has special refs like `pull/N/merge` which are guaranteed to move in a non-fast-forward fashion, this leads actions from GitHub usually failing to update.

```
  ☁  git clone 'https://github.com/Mic92/update-flake-inputs-gitea' # ref=main
  cloning https://github.com/Mic92/update-flake-inputs-gitea to /var/lib/gitea-runner/nix0/.cache/act/9b0155f2957ac84c749f9ecc8afaec823af5ef2e67a104ac655623aee12ca5b2
Non-terminating error while running 'git clone': some refs were not updated
```

With the repo https://github.com/Mic92/update-flake-inputs-gitea, you can notice that it only has a `main` branch that moves in a fast-forward fashion and no tags that could've been force pushed.

Fixes #726

---------

Co-authored-by: Michael Hoang <enzime@users.noreply.github.com>
Reviewed-on: https://gitea.com/gitea/runner/pulls/846
Reviewed-by: silverwind <2021+silverwind@noreply.gitea.com>
Reviewed-by: Nicolas <bircni@icloud.com>
Co-authored-by: Michael Hoang <194829+enzime@noreply.gitea.com>
Co-committed-by: Michael Hoang <194829+enzime@noreply.gitea.com>
2026-04-26 11:08:23 +00:00
90 changed files with 351 additions and 232 deletions

View File

@@ -40,7 +40,7 @@ cpu.out
*.db
*.log
/runner
/act_runner
/debug
/bin

View File

@@ -69,7 +69,7 @@ jobs:
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Echo the tag
run: echo "${{ env.DOCKER_ORG }}/runner:nightly${{ matrix.variant.tag_suffix }}"
run: echo "${{ env.DOCKER_ORG }}/act_runner:nightly${{ matrix.variant.tag_suffix }}"
- name: Build and push
uses: docker/build-push-action@v6
@@ -82,4 +82,4 @@ jobs:
linux/arm64
push: true
tags: |
${{ env.DOCKER_ORG }}/runner:nightly${{ matrix.variant.tag_suffix }}
${{ env.DOCKER_ORG }}/act_runner:nightly${{ matrix.variant.tag_suffix }}

2
.gitignore vendored
View File

@@ -1,4 +1,4 @@
/runner
/act_runner
.env
.runner
coverage.txt

View File

@@ -114,7 +114,7 @@ formatters:
custom-order: true
sections:
- standard
- prefix(gitea.com/gitea/runner)
- prefix(gitea.com/gitea/act_runner)
- blank
- default
gofumpt:

View File

@@ -63,7 +63,7 @@ builds:
flags:
- -trimpath
ldflags:
- -s -w -X gitea.com/gitea/runner/internal/pkg/ver.version={{ .Summary }}
- -s -w -X gitea.com/gitea/act_runner/internal/pkg/ver.version={{ .Summary }}
binary: >-
{{ .ProjectName }}-
{{- .Version }}-
@@ -86,7 +86,7 @@ blobs:
provider: s3
bucket: "{{ .Env.S3_BUCKET }}"
region: "{{ .Env.S3_REGION }}"
directory: "runner/{{.Version}}"
directory: "act_runner/{{.Version}}"
extra_files:
- glob: ./**.xz
- glob: ./**.sha256

View File

@@ -9,8 +9,8 @@ RUN apk add --no-cache make git
ARG GOPROXY
ENV GOPROXY=${GOPROXY:-}
COPY . /opt/src/runner
WORKDIR /opt/src/runner
COPY . /opt/src/act_runner
WORKDIR /opt/src/act_runner
RUN make clean && make build
@@ -21,7 +21,7 @@ FROM docker:28-dind AS dind
RUN apk add --no-cache s6 bash git tzdata
COPY --from=builder /opt/src/runner/runner /usr/local/bin/runner
COPY --from=builder /opt/src/act_runner/act_runner /usr/local/bin/act_runner
COPY scripts/run.sh /usr/local/bin/run.sh
COPY scripts/s6 /etc/s6
@@ -37,7 +37,7 @@ FROM docker:28-dind-rootless AS dind-rootless
USER root
RUN apk add --no-cache s6 bash git tzdata
COPY --from=builder /opt/src/runner/runner /usr/local/bin/runner
COPY --from=builder /opt/src/act_runner/act_runner /usr/local/bin/act_runner
COPY scripts/run.sh /usr/local/bin/run.sh
COPY scripts/s6 /etc/s6
@@ -56,7 +56,7 @@ ENTRYPOINT ["s6-svscan","/etc/s6"]
FROM alpine AS basic
RUN apk add --no-cache tini bash git tzdata
COPY --from=builder /opt/src/runner/runner /usr/local/bin/runner
COPY --from=builder /opt/src/act_runner/act_runner /usr/local/bin/act_runner
COPY scripts/run.sh /usr/local/bin/run.sh
VOLUME /data

View File

@@ -1,5 +1,5 @@
DIST := dist
EXECUTABLE := runner
EXECUTABLE := act_runner
DIST_DIRS := $(DIST)/binaries $(DIST)/release
GO ?= go
SHASUM ?= shasum -a 256
@@ -13,7 +13,7 @@ DARWIN_ARCHS ?= darwin-12/amd64,darwin-12/arm64
WINDOWS_ARCHS ?= windows/amd64
GOFILES := $(shell find . -type f -name "*.go" -o -name "go.mod" ! -name "generated.*")
DOCKER_IMAGE ?= gitea/runner
DOCKER_IMAGE ?= gitea/act_runner
DOCKER_TAG ?= nightly
DOCKER_REF := $(DOCKER_IMAGE):$(DOCKER_TAG)
DOCKER_ROOTLESS_REF := $(DOCKER_IMAGE):$(DOCKER_TAG)-dind-rootless
@@ -67,7 +67,7 @@ else
endif
TAGS ?=
LDFLAGS ?= -X "gitea.com/gitea/runner/internal/pkg/ver.version=v$(RELASE_VERSION)"
LDFLAGS ?= -X "gitea.com/gitea/act_runner/internal/pkg/ver.version=v$(RELASE_VERSION)"
.PHONY: all
all: build
@@ -140,11 +140,11 @@ test: fmt-check security-check ## test everything
@$(GO) test -race -short -v -cover -coverprofile coverage.txt ./... && echo "\n==>\033[32m Ok\033[m\n" || exit 1
.PHONY: install
install: $(GOFILES) ## install the runner binary via `go install`
install: $(GOFILES) ## install the act_runner binary via `go install`
$(GO) install -v -tags '$(TAGS)' -ldflags '-s -w $(EXTLDFLAGS) $(LDFLAGS)'
.PHONY: build
build: go-check $(EXECUTABLE) ## build the runner binary
build: go-check $(EXECUTABLE) ## build the act_runner binary
$(EXECUTABLE): $(GOFILES)
$(GO) build -v -tags '$(TAGS)' -ldflags '-s -w $(EXTLDFLAGS) $(LDFLAGS)' -o $@

View File

@@ -10,7 +10,7 @@ Docker Engine Community version is required for docker mode. To install Docker C
### Download pre-built binary
Visit [here](https://dl.gitea.com/runner/) and download the right version for your platform.
Visit [here](https://dl.gitea.com/act_runner/) and download the right version for your platform.
### Build from source
@@ -26,8 +26,8 @@ make docker
## Quickstart
Actions are disabled by default, so you need to add the following to the configuration file of your Gitea instance to enable it:
Actions are disabled by default, so you need to add the following to the configuration file of your Gitea instance to enable it:
```ini
[actions]
ENABLED=true
@@ -36,7 +36,7 @@ ENABLED=true
### Register
```bash
./runner register
./act_runner register
```
And you will be asked to input:
@@ -68,7 +68,7 @@ INFO Runner registered successfully.
You can also register with command line arguments.
```bash
./runner register --instance http://192.168.8.8:3000 --token <my_runner_token> --no-interactive
./act_runner register --instance http://192.168.8.8:3000 --token <my_runner_token> --no-interactive
```
If the registry succeed, it will run immediately. Next time, you could run the runner directly.
@@ -76,29 +76,29 @@ If the registry succeed, it will run immediately. Next time, you could run the r
### Run
```bash
./runner daemon
./act_runner daemon
```
### Run with docker
```bash
docker run -e GITEA_INSTANCE_URL=https://your_gitea.com -e GITEA_RUNNER_REGISTRATION_TOKEN=<your_token> -v /var/run/docker.sock:/var/run/docker.sock --name my_runner gitea/runner:nightly
docker run -e GITEA_INSTANCE_URL=https://your_gitea.com -e GITEA_RUNNER_REGISTRATION_TOKEN=<your_token> -v /var/run/docker.sock:/var/run/docker.sock --name my_runner gitea/act_runner:nightly
```
### Configuration
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 `./runner generate-config`.
The configuration file is a YAML file, you can generate a sample configuration file with `./act_runner generate-config`.
```bash
./runner generate-config > config.yaml
./act_runner generate-config > config.yaml
```
You can specify the configuration file path with `-c`/`--config` argument.
```bash
./runner -c config.yaml register # register with config file
./runner -c config.yaml daemon # run with config file
./act_runner -c config.yaml register # register with config file
./act_runner -c config.yaml daemon # run with config file
```
You can read the latest version of the configuration file online at [config.example.yaml](internal/pkg/config/config.example.yaml).

View File

@@ -19,7 +19,7 @@ import (
"sync/atomic"
"time"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/act_runner/act/common"
"github.com/julienschmidt/httprouter"
"github.com/sirupsen/logrus"

View File

@@ -17,7 +17,7 @@ import (
"strings"
"time"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/act_runner/act/common"
"github.com/julienschmidt/httprouter"
)

View File

@@ -17,8 +17,8 @@ import (
"testing"
"testing/fstest"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/runner/act/runner"
"gitea.com/gitea/act_runner/act/model"
"gitea.com/gitea/act_runner/act/runner"
"github.com/julienschmidt/httprouter"
log "github.com/sirupsen/logrus"

View File

@@ -117,7 +117,7 @@ func NewParallelExecutor(parallel int, executors ...Executor) Executor {
log.Debugf("Worker %d executing task %d", workerID, taskCount)
// Recover from panics in executors to avoid crashing the worker
// goroutine which would leave the runner process hung.
// https://gitea.com/gitea/runner/issues/371
// https://gitea.com/gitea/act_runner/issues/371
errs <- func() (err error) {
defer func() {
if r := recover(); r != nil {

View File

@@ -15,7 +15,7 @@ import (
"strings"
"sync"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/act_runner/act/common"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config"
@@ -277,6 +277,7 @@ func CloneIfRequired(ctx context.Context, refName plumbing.ReferenceName, input
func gitOptions(token string) (fetchOptions git.FetchOptions, pullOptions git.PullOptions) {
fetchOptions.RefSpecs = []config.RefSpec{"refs/*:refs/*", "HEAD:refs/heads/HEAD"}
fetchOptions.Force = true
pullOptions.Force = true
if token != "" {

View File

@@ -10,6 +10,7 @@ import (
"os"
"os/exec"
"path/filepath"
"strings"
"syscall"
"testing"
@@ -220,6 +221,62 @@ func TestGitCloneExecutor(t *testing.T) {
}
}
func TestGitCloneExecutorNonFastForwardRef(t *testing.T) {
// Simulate the scenario where a remote ref (e.g. a GitHub PR head ref) changes
// non-fast-forward between two fetches. Before the fix, the fetch used Force=false,
// causing go-git to return ErrForceNeeded and short-circuit the checkout.
gitConfig()
// Create a bare "remote" repo with an initial commit on main and a feature branch.
remoteDir := t.TempDir()
require.NoError(t, gitCmd("init", "--bare", "--initial-branch=main", remoteDir))
// We need a working clone to push commits from.
workDir := t.TempDir()
require.NoError(t, gitCmd("clone", remoteDir, workDir))
require.NoError(t, gitCmd("-C", workDir, "checkout", "-b", "main"))
require.NoError(t, gitCmd("-C", workDir, "commit", "--allow-empty", "-m", "initial"))
require.NoError(t, gitCmd("-C", workDir, "push", "-u", "origin", "main"))
// Create a feature branch (simulates refs/pull/N/head).
require.NoError(t, gitCmd("-C", workDir, "checkout", "-b", "feature"))
require.NoError(t, gitCmd("-C", workDir, "commit", "--allow-empty", "-m", "feature-1"))
require.NoError(t, gitCmd("-C", workDir, "push", "origin", "feature"))
// First clone via the executor — should succeed and cache the repo.
cloneDir := t.TempDir()
clone := NewGitCloneExecutor(NewGitCloneExecutorInput{
URL: remoteDir,
Ref: "main",
Dir: cloneDir,
})
require.NoError(t, clone(context.Background()))
// Now force-push the feature branch to a non-fast-forward commit (simulates
// a PR rebase). This makes refs/heads/feature non-fast-forward.
require.NoError(t, gitCmd("-C", workDir, "checkout", "main"))
require.NoError(t, gitCmd("-C", workDir, "branch", "-D", "feature"))
require.NoError(t, gitCmd("-C", workDir, "checkout", "-b", "feature"))
require.NoError(t, gitCmd("-C", workDir, "commit", "--allow-empty", "-m", "feature-rewritten"))
require.NoError(t, gitCmd("-C", workDir, "push", "--force", "origin", "feature"))
// Also advance main so we can verify the clone picks up the new commit.
require.NoError(t, gitCmd("-C", workDir, "checkout", "main"))
require.NoError(t, gitCmd("-C", workDir, "commit", "--allow-empty", "-m", "second"))
require.NoError(t, gitCmd("-C", workDir, "push", "origin", "main"))
// Second clone to the same directory — before the fix this returned ErrForceNeeded
// and left the working tree at the old commit.
err := clone(context.Background())
require.NoError(t, err, "fetch with non-fast-forward refs must not fail when Force=true")
// Verify the working tree was actually updated to the latest main commit.
out, err := exec.Command("git", "-C", cloneDir, "log", "--oneline", "-1", "--format=%s").Output()
require.NoError(t, err)
assert.Equal(t, "second", strings.TrimSpace(string(out)), "working tree should be at the latest commit")
}
func gitConfig() {
if os.Getenv("GITHUB_ACTIONS") == "true" {
var err error

View File

@@ -8,7 +8,7 @@ import (
"context"
"io"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/act_runner/act/common"
"github.com/docker/go-connections/nat"
)

View File

@@ -10,7 +10,7 @@ import (
"context"
"strings"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/act_runner/act/common"
"github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/config/credentials"

View File

@@ -12,10 +12,11 @@ import (
"os"
"path/filepath"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/act_runner/act/common"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/archive"
// github.com/docker/docker/builder/dockerignore is deprecated
"github.com/moby/buildkit/frontend/dockerfile/dockerignore"
"github.com/moby/patternmatcher"
)

View File

@@ -9,7 +9,7 @@ package container
import (
"context"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/act_runner/act/common"
"github.com/docker/docker/api/types"
)

View File

@@ -13,7 +13,7 @@ import (
"fmt"
"strings"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/act_runner/act/common"
"github.com/distribution/reference"
"github.com/docker/docker/api/types"

View File

@@ -20,8 +20,8 @@ import (
"strconv"
"strings"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/filecollector"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/filecollector"
"github.com/Masterminds/semver"
"github.com/docker/cli/cli/compose/loader"

View File

@@ -15,7 +15,7 @@ import (
"testing"
"time"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/act_runner/act/common"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"

View File

@@ -10,7 +10,7 @@ import (
"context"
"runtime"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/act_runner/act/common"
"github.com/docker/docker/api/types"
"github.com/pkg/errors"

View File

@@ -9,7 +9,7 @@ package container
import (
"context"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/act_runner/act/common"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/volume"

View File

@@ -19,9 +19,9 @@ import (
"strings"
"time"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/filecollector"
"gitea.com/gitea/runner/act/lookpath"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/filecollector"
"gitea.com/gitea/act_runner/act/lookpath"
"github.com/go-git/go-billy/v5/helper/polyfill"
"github.com/go-git/go-billy/v5/osfs"

View File

@@ -12,7 +12,7 @@ import (
"io"
"strings"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/act_runner/act/common"
)
func parseEnvFile(e Container, srcPath string, env *map[string]string) common.Executor {

View File

@@ -18,7 +18,7 @@ import (
"strconv"
"strings"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/model"
"github.com/go-git/go-git/v5/plumbing/format/gitignore"
"github.com/rhysd/actionlint"

View File

@@ -8,7 +8,7 @@ import (
"path/filepath"
"testing"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/model"
"github.com/stretchr/testify/assert"
)

View File

@@ -12,7 +12,7 @@ import (
"reflect"
"strings"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/model"
"github.com/rhysd/actionlint"
)

View File

@@ -8,7 +8,7 @@ import (
"math"
"testing"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/model"
"github.com/stretchr/testify/assert"
)

View File

@@ -9,8 +9,8 @@ import (
"fmt"
"strings"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/common/git"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/common/git"
)
type GithubContext struct {

View File

@@ -15,7 +15,7 @@ import (
"strconv"
"strings"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/act_runner/act/common"
log "github.com/sirupsen/logrus"
"go.yaml.in/yaml/v4"

View File

@@ -18,9 +18,9 @@ import (
"runtime"
"strings"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/container"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/container"
"gitea.com/gitea/act_runner/act/model"
"github.com/kballard/go-shellquote"
)

View File

@@ -11,8 +11,8 @@ import (
"strconv"
"strings"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/model"
)
func evaluateCompositeInputAndEnv(ctx context.Context, parent *RunContext, step actionStep) map[string]string {

View File

@@ -11,7 +11,7 @@ import (
"strings"
"testing"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"

View File

@@ -9,7 +9,7 @@ import (
"regexp"
"strings"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/act_runner/act/common"
)
var commandPatternGA *regexp.Regexp

View File

@@ -11,8 +11,8 @@ import (
"os"
"testing"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/model"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"

View File

@@ -8,8 +8,8 @@ import (
"context"
"io"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/container"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/container"
"github.com/stretchr/testify/mock"
)

View File

@@ -15,10 +15,10 @@ import (
"strings"
"time"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/container"
"gitea.com/gitea/runner/act/exprparser"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/container"
"gitea.com/gitea/act_runner/act/exprparser"
"gitea.com/gitea/act_runner/act/model"
_ "embed"

View File

@@ -8,8 +8,8 @@ import (
"context"
"testing"
"gitea.com/gitea/runner/act/exprparser"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/exprparser"
"gitea.com/gitea/act_runner/act/model"
assert "github.com/stretchr/testify/assert"
yaml "go.yaml.in/yaml/v4"

View File

@@ -10,8 +10,8 @@ import (
"strconv"
"time"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/model"
)
type jobInfo interface {
@@ -137,7 +137,7 @@ func newJobExecutor(info jobInfo, sf stepFactory, rc *RunContext) common.Executo
// if !rc.IsHostEnv(ctx) && rc.Config.ContainerNetworkMode == "" {
// // clean network in docker mode only
// // if the value of `ContainerNetworkMode` is empty string,
// // it means that the network to which containers are connecting is created by `runner`,
// // it means that the network to which containers are connecting is created by `act_runner`,
// // so, we should remove the network at last.
// networkName, _ := rc.networkName()
// logger.Infof("Cleaning up network for job %s, and network name is: %s", rc.JobName, networkName)

View File

@@ -12,9 +12,9 @@ import (
"slices"
"testing"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/container"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/container"
"gitea.com/gitea/act_runner/act/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"

View File

@@ -16,7 +16,7 @@ import (
"path/filepath"
"strings"
"gitea.com/gitea/runner/act/filecollector"
"gitea.com/gitea/act_runner/act/filecollector"
)
type LocalRepositoryCache struct {

View File

@@ -13,7 +13,7 @@ import (
"strings"
"sync"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/act_runner/act/common"
"github.com/sirupsen/logrus"
"golang.org/x/term"

View File

@@ -6,7 +6,7 @@ package runner
import (
"testing"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/model"
"github.com/stretchr/testify/assert"
"go.yaml.in/yaml/v4"

View File

@@ -17,9 +17,9 @@ import (
"strings"
"sync"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/common/git"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/common/git"
"gitea.com/gitea/act_runner/act/model"
)
func newLocalReusableWorkflowExecutor(rc *RunContext) common.Executor {

View File

@@ -23,10 +23,10 @@ import (
"strings"
"time"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/container"
"gitea.com/gitea/runner/act/exprparser"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/container"
"gitea.com/gitea/act_runner/act/exprparser"
"gitea.com/gitea/act_runner/act/model"
"github.com/docker/go-connections/nat"
"github.com/opencontainers/selinux/go-selinux"
@@ -383,7 +383,7 @@ func (rc *RunContext) startJobContainer() common.Executor {
if createAndDeleteNetwork {
// clean network if it has been created by act
// if using service containers
// it means that the network to which containers are connecting is created by `runner`,
// it means that the network to which containers are connecting is created by `act_runner`,
// so, we should remove the network at last.
logger.Infof("Cleaning up network for job %s, and network name is: %s", rc.JobName, networkName)
if err := container.NewDockerNetworkRemoveExecutor(networkName)(ctx); err != nil {

View File

@@ -12,8 +12,8 @@ import (
"strings"
"testing"
"gitea.com/gitea/runner/act/exprparser"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/exprparser"
"gitea.com/gitea/act_runner/act/model"
log "github.com/sirupsen/logrus"
assert "github.com/stretchr/testify/assert"

View File

@@ -13,8 +13,8 @@ import (
"sync"
"time"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/model"
docker_container "github.com/docker/docker/api/types/container"
log "github.com/sirupsen/logrus"

View File

@@ -16,8 +16,8 @@ import (
"strings"
"testing"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/model"
"github.com/joho/godotenv"
log "github.com/sirupsen/logrus"

View File

@@ -13,10 +13,10 @@ import (
"strings"
"time"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/container"
"gitea.com/gitea/runner/act/exprparser"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/container"
"gitea.com/gitea/act_runner/act/exprparser"
"gitea.com/gitea/act_runner/act/model"
)
type step interface {

View File

@@ -15,8 +15,8 @@ import (
"path"
"path/filepath"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/model"
)
type stepActionLocal struct {

View File

@@ -12,8 +12,8 @@ import (
"strings"
"testing"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"

View File

@@ -16,9 +16,9 @@ import (
"regexp"
"strings"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/common/git"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/common/git"
"gitea.com/gitea/act_runner/act/model"
gogit "github.com/go-git/go-git/v5"
)

View File

@@ -14,9 +14,9 @@ import (
"testing"
"time"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/common/git"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/common/git"
"gitea.com/gitea/act_runner/act/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"

View File

@@ -9,9 +9,9 @@ import (
"fmt"
"strings"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/container"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/container"
"gitea.com/gitea/act_runner/act/model"
"github.com/kballard/go-shellquote"
)

View File

@@ -10,8 +10,8 @@ import (
"io"
"testing"
"gitea.com/gitea/runner/act/container"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/container"
"gitea.com/gitea/act_runner/act/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"

View File

@@ -7,7 +7,7 @@ package runner
import (
"fmt"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/model"
)
type stepFactory interface {

View File

@@ -7,7 +7,7 @@ package runner
import (
"testing"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/model"
"github.com/stretchr/testify/assert"
)

View File

@@ -11,10 +11,10 @@ import (
"runtime"
"strings"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/container"
"gitea.com/gitea/runner/act/lookpath"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/container"
"gitea.com/gitea/act_runner/act/lookpath"
"gitea.com/gitea/act_runner/act/model"
"github.com/kballard/go-shellquote"
)

View File

@@ -10,8 +10,8 @@ import (
"io"
"testing"
"gitea.com/gitea/runner/act/container"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/container"
"gitea.com/gitea/act_runner/act/model"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"

View File

@@ -8,8 +8,8 @@ import (
"context"
"testing"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/model"
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"

View File

@@ -1,4 +1,4 @@
# Usage Examples for `runner`
# Usage Examples for `act_runner`
Welcome to our collection of usage and deployment examples specifically designed for Gitea setups. Whether you're a beginner or an experienced user, you'll find practical resources here that you can directly apply to enhance your Gitea experience. We encourage you to contribute your own insights and knowledge to make this collection even more comprehensive and valuable.

View File

@@ -1,4 +1,4 @@
### Running `runner` using `docker-compose`
### Running `act_runner` using `docker-compose`
```yml
...
@@ -19,15 +19,15 @@
# - GITEA_RUNNER_REGISTRATION_TOKEN=<user-defined registration token>
runner:
image: gitea/runner
image: gitea/act_runner
restart: always
depends_on:
gitea:
# required so runner can attach to gitea, see "healthcheck"
condition: service_healthy
condition: service_healthy
restart: true
volumes:
- ./data/runner:/data
- ./data/act_runner:/data
- /var/run/docker.sock:/var/run/docker.sock
environment:
- GITEA_INSTANCE_URL=<instance url>
@@ -38,18 +38,18 @@
- GITEA_RUNNER_REGISTRATION_TOKEN=<registration token>
```
### Running `runner` using Docker-in-Docker (DIND)
### Running `act_runner` using Docker-in-Docker (DIND)
```yml
...
runner:
image: gitea/runner:latest-dind-rootless
image: gitea/act_runner:latest-dind-rootless
restart: always
privileged: true
depends_on:
- gitea
volumes:
- ./data/runner:/data
- ./data/act_runner:/data
environment:
- GITEA_INSTANCE_URL=<instance url>
- DOCKER_HOST=unix:///var/run/user/1000/docker.sock

View File

@@ -1,7 +1,7 @@
### Run `runner` in a Docker Container
### Run `act_runner` in a Docker Container
```sh
docker run -e GITEA_INSTANCE_URL=http://192.168.8.18:3000 -e GITEA_RUNNER_REGISTRATION_TOKEN=<runner_token> -v /var/run/docker.sock:/var/run/docker.sock -v $PWD/data:/data --name my_runner gitea/runner:nightly
docker run -e GITEA_INSTANCE_URL=http://192.168.8.18:3000 -e GITEA_RUNNER_REGISTRATION_TOKEN=<runner_token> -v /var/run/docker.sock:/var/run/docker.sock -v $PWD/data:/data --name my_runner gitea/act_runner:nightly
```
The `/data` directory inside the docker container contains the runner API keys after registration.

View File

@@ -1,4 +1,4 @@
## Kubernetes Docker in Docker Deployment with `runner`
## Kubernetes Docker in Docker Deployment with `act_runner`
NOTE: Docker in Docker (dind) requires elevated privileges on Kubernetes. The current way to achieve this is to set the pod `SecurityContext` to `privileged`. Keep in mind that this is a potential security issue that has the potential for a malicious application to break out of the container context.

View File

@@ -13,7 +13,7 @@ spec:
apiVersion: v1
data:
# The registration token can be obtained from the web UI, API or command-line.
# You can also set a pre-defined global runner registration token for the Gitea instance via
# You can also set a pre-defined global runner registration token for the Gitea instance via
# `GITEA_RUNNER_REGISTRATION_TOKEN`/`GITEA_RUNNER_REGISTRATION_TOKEN_FILE` environment variable.
token: << base64 encoded registration token >>
kind: Secret
@@ -48,7 +48,7 @@ spec:
claimName: act-runner-vol
containers:
- name: runner
image: gitea/runner:nightly
image: gitea/act_runner:nightly
command: ["sh", "-c", "while ! nc -z localhost 2376 </dev/null; do echo 'waiting for docker daemon...'; sleep 5; done; /sbin/tini -- run.sh"]
env:
- name: DOCKER_HOST

View File

@@ -13,7 +13,7 @@ spec:
apiVersion: v1
data:
# The registration token can be obtained from the web UI, API or command-line.
# You can also set a pre-defined global runner registration token for the Gitea instance via
# You can also set a pre-defined global runner registration token for the Gitea instance via
# `GITEA_RUNNER_REGISTRATION_TOKEN`/`GITEA_RUNNER_REGISTRATION_TOKEN_FILE` environment variable.
token: << base64 encoded registration token >>
kind: Secret
@@ -48,7 +48,7 @@ spec:
fsGroup: 1000
containers:
- name: runner
image: gitea/runner:nightly-dind-rootless
image: gitea/act_runner:nightly-dind-rootless
imagePullPolicy: Always
# command: ["sh", "-c", "while ! nc -z localhost 2376 </dev/null; do echo 'waiting for docker daemon...'; sleep 5; done; /sbin/tini -- /opt/act/run.sh"]
env:

View File

@@ -1,4 +1,4 @@
## `runner` on Virtual or Physical Servers
## `act_runner` on Virtual or Physical Servers
Files in this directory:

View File

@@ -1,12 +1,12 @@
## Using Rootless Docker with`runner`
## Using Rootless Docker with`act_runner`
Here is a simple example of how to set up `runner` with rootless Docker. It has been created with Debian, but other Linux should work the same way.
Here is a simple example of how to set up `act_runner` with rootless Docker. It has been created with Debian, but other Linux should work the same way.
Note: This procedure needs a real login shell -- using `sudo su` or other method of accessing the account will fail some of the steps below.
As `root`:
- Create a user to run both `docker` and `runner`. In this example, we use a non-privileged account called `rootless`.
- Create a user to run both `docker` and `act_runner`. In this example, we use a non-privileged account called `rootless`.
```bash
useradd -m rootless
@@ -38,36 +38,36 @@ export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock
```
- Reboot. Ensure that the Docker process is working.
- Create a directory for saving `runner` data between restarts
- Create a directory for saving `act_runner` data between restarts
`mkdir /home/rootless/runner`
`mkdir /home/rootless/act_runner`
- Register the runner from the data directory
```bash
cd /home/rootless/runner
runner register
cd /home/rootless/act_runner
act_runner register
```
- Generate a `runner` configuration file in the data directory. Edit the file to adjust for the system.
- Generate a `act_runner` configuration file in the data directory. Edit the file to adjust for the system.
```bash
runner generate-config >/home/rootless/runner/config
act_runner generate-config >/home/rootless/act_runner/config
```
- Create a new user-level`systemd` unit file as `/home/rootless/.config/systemd/user/runner.service` with the following contents:
- Create a new user-level`systemd` unit file as `/home/rootless/.config/systemd/user/act_runner.service` with the following contents:
```bash
Description=Gitea Actions runner
Documentation=https://gitea.com/gitea/runner
Documentation=https://gitea.com/gitea/act_runner
After=docker.service
[Service]
Environment=PATH=/home/rootless/bin:/sbin:/usr/sbin:/home/rootless/bin:/home/rootless/bin:/home/rootless/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
Environment=DOCKER_HOST=unix:///run/user/1001/docker.sock
ExecStart=/usr/bin/runner daemon -c /home/rootless/runner/config
ExecStart=/usr/bin/act_runner daemon -c /home/rootless/act_runner/config
ExecReload=/bin/kill -s HUP $MAINPID
WorkingDirectory=/home/rootless/runner
WorkingDirectory=/home/rootless/act_runner
TimeoutSec=0
RestartSec=2
Restart=always
@@ -88,8 +88,8 @@ export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock
- Reboot
After the system restarts, check that the`runner` is working and that the runner is connected to Gitea.
After the system restarts, check that the`act_runner` is working and that the runner is connected to Gitea.
````bash
systemctl --user status runner
journalctl --user -xeu runner
systemctl --user status act_runner
journalctl --user -xeu act_runner

6
go.mod
View File

@@ -1,10 +1,10 @@
module gitea.com/gitea/runner
module gitea.com/gitea/act_runner
go 1.26.0
require (
code.gitea.io/actions-proto-go v0.4.1
connectrpc.com/connect v1.19.1
connectrpc.com/connect v1.19.2
github.com/avast/retry-go/v4 v4.7.0
github.com/docker/docker v25.0.13+incompatible
github.com/joho/godotenv v1.5.1
@@ -24,7 +24,7 @@ require (
github.com/Masterminds/semver v1.5.0
github.com/creack/pty v1.1.24
github.com/distribution/reference v0.6.0
github.com/docker/cli v25.0.3+incompatible
github.com/docker/cli v25.0.7+incompatible
github.com/docker/go-connections v0.6.0
github.com/go-git/go-billy/v5 v5.8.0
github.com/go-git/go-git/v5 v5.18.0

4
go.sum
View File

@@ -2,6 +2,8 @@ code.gitea.io/actions-proto-go v0.4.1 h1:l0EYhjsgpUe/1VABo2eK7zcoNX2W44WOnb0MSLr
code.gitea.io/actions-proto-go v0.4.1/go.mod h1:mn7Wkqz6JbnTOHQpot3yDeHx+O5C9EGhMEE+htvHBas=
connectrpc.com/connect v1.19.1 h1:R5M57z05+90EfEvCY1b7hBxDVOUl45PrtXtAV2fOC14=
connectrpc.com/connect v1.19.1/go.mod h1:tN20fjdGlewnSFeZxLKb0xwIZ6ozc3OQs2hTXy4du9w=
connectrpc.com/connect v1.19.2 h1:McQ83FGdzL+t60peksi0gXC7MQ/iLKgLduAnThbM0mo=
connectrpc.com/connect v1.19.2/go.mod h1:tN20fjdGlewnSFeZxLKb0xwIZ6ozc3OQs2hTXy4du9w=
cyphar.com/go-pathrs v0.2.3 h1:0pH8gep37wB0BgaXrEaN1OtZhUMeS7VvaejSr6i822o=
cyphar.com/go-pathrs v0.2.3/go.mod h1:y8f1EMG7r+hCuFf/rXsKqMJrJAUoADZGNh5/vZPKcGc=
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
@@ -53,6 +55,8 @@ github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/cli v25.0.3+incompatible h1:KLeNs7zws74oFuVhgZQ5ONGZiXUUdgsdy6/EsX/6284=
github.com/docker/cli v25.0.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/cli v25.0.7+incompatible h1:scW/AbGafKmANsonsFckFHTwpz2QypoPA/zpoLnDs/E=
github.com/docker/cli v25.0.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/docker v25.0.13+incompatible h1:YeBrkUd3q0ZoRDNoEzuopwCLU+uD8GZahDHwBdsTnkU=
github.com/docker/docker v25.0.13+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.9.5 h1:EFNN8DHvaiK8zVqFA2DT6BjXE0GzfLOZ38ggPTKePkY=

View File

@@ -8,8 +8,8 @@ import (
"os"
"os/signal"
"gitea.com/gitea/runner/act/artifactcache"
"gitea.com/gitea/runner/internal/pkg/config"
"gitea.com/gitea/act_runner/act/artifactcache"
"gitea.com/gitea/act_runner/internal/pkg/config"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"

View File

@@ -8,16 +8,16 @@ import (
"fmt"
"os"
"gitea.com/gitea/runner/internal/pkg/config"
"gitea.com/gitea/runner/internal/pkg/ver"
"gitea.com/gitea/act_runner/internal/pkg/config"
"gitea.com/gitea/act_runner/internal/pkg/ver"
"github.com/spf13/cobra"
)
func Execute(ctx context.Context) {
// ./runner
// ./act_runner
rootCmd := &cobra.Command{
Use: "runner [event name to run]\nIf no event name passed, will default to \"on: push\"",
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.",
Args: cobra.MaximumNArgs(1),
Version: ver.Version(),
@@ -26,7 +26,7 @@ func Execute(ctx context.Context) {
configFile := ""
rootCmd.PersistentFlags().StringVarP(&configFile, "config", "c", "", "Config file path")
// ./runner register
// ./act_runner register
var regArgs registerArgs
registerCmd := &cobra.Command{
Use: "register",
@@ -42,7 +42,7 @@ func Execute(ctx context.Context) {
registerCmd.Flags().BoolVar(&regArgs.Ephemeral, "ephemeral", false, "Configure the runner to be ephemeral and only ever be able to pick a single job (stricter than --once)")
rootCmd.AddCommand(registerCmd)
// ./runner daemon
// ./act_runner daemon
var daemArgs daemonArgs
daemonCmd := &cobra.Command{
Use: "daemon",
@@ -53,10 +53,10 @@ func Execute(ctx context.Context) {
daemonCmd.Flags().BoolVar(&daemArgs.Once, "once", false, "Run one job then exit")
rootCmd.AddCommand(daemonCmd)
// ./runner exec
// ./act_runner exec
rootCmd.AddCommand(loadExecCmd(ctx))
// ./runner config
// ./act_runner config
rootCmd.AddCommand(&cobra.Command{
Use: "generate-config",
Short: "Generate an example config file",
@@ -66,7 +66,7 @@ func Execute(ctx context.Context) {
},
})
// ./runner cache-server
// ./act_runner cache-server
var cacheArgs cacheServerArgs
cacheCmd := &cobra.Command{
Use: "cache-server",

View File

@@ -16,14 +16,14 @@ import (
"strings"
"time"
"gitea.com/gitea/runner/internal/app/poll"
"gitea.com/gitea/runner/internal/app/run"
"gitea.com/gitea/runner/internal/pkg/client"
"gitea.com/gitea/runner/internal/pkg/config"
"gitea.com/gitea/runner/internal/pkg/envcheck"
"gitea.com/gitea/runner/internal/pkg/labels"
"gitea.com/gitea/runner/internal/pkg/metrics"
"gitea.com/gitea/runner/internal/pkg/ver"
"gitea.com/gitea/act_runner/internal/app/poll"
"gitea.com/gitea/act_runner/internal/app/run"
"gitea.com/gitea/act_runner/internal/pkg/client"
"gitea.com/gitea/act_runner/internal/pkg/config"
"gitea.com/gitea/act_runner/internal/pkg/envcheck"
"gitea.com/gitea/act_runner/internal/pkg/labels"
"gitea.com/gitea/act_runner/internal/pkg/metrics"
"gitea.com/gitea/act_runner/internal/pkg/ver"
"connectrpc.com/connect"
"github.com/mattn/go-isatty"
@@ -104,7 +104,7 @@ func runDaemon(ctx context.Context, daemArgs *daemonArgs, configFile *string) fu
}
// if dockerSocketPath passes the check, override DOCKER_HOST with dockerSocketPath
os.Setenv("DOCKER_HOST", dockerSocketPath)
// empty cfg.Container.DockerHost means runner need to find an available docker host automatically
// empty cfg.Container.DockerHost means act_runner need to find an available docker host automatically
// and assign the path to cfg.Container.DockerHost
if cfg.Container.DockerHost == "" {
cfg.Container.DockerHost = dockerSocketPath

View File

@@ -15,11 +15,11 @@ import (
"strings"
"time"
"gitea.com/gitea/runner/act/artifactcache"
"gitea.com/gitea/runner/act/artifacts"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/runner/act/runner"
"gitea.com/gitea/act_runner/act/artifactcache"
"gitea.com/gitea/act_runner/act/artifacts"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/model"
"gitea.com/gitea/act_runner/act/runner"
"github.com/docker/docker/api/types/container"
"github.com/joho/godotenv"

View File

@@ -14,10 +14,10 @@ import (
"strings"
"time"
"gitea.com/gitea/runner/internal/pkg/client"
"gitea.com/gitea/runner/internal/pkg/config"
"gitea.com/gitea/runner/internal/pkg/labels"
"gitea.com/gitea/runner/internal/pkg/ver"
"gitea.com/gitea/act_runner/internal/pkg/client"
"gitea.com/gitea/act_runner/internal/pkg/config"
"gitea.com/gitea/act_runner/internal/pkg/labels"
"gitea.com/gitea/act_runner/internal/pkg/ver"
pingv1 "code.gitea.io/actions-proto-go/ping/v1"
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"

View File

@@ -12,9 +12,9 @@ import (
"sync/atomic"
"time"
"gitea.com/gitea/runner/internal/pkg/client"
"gitea.com/gitea/runner/internal/pkg/config"
"gitea.com/gitea/runner/internal/pkg/metrics"
"gitea.com/gitea/act_runner/internal/pkg/client"
"gitea.com/gitea/act_runner/internal/pkg/config"
"gitea.com/gitea/act_runner/internal/pkg/metrics"
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
"connectrpc.com/connect"

View File

@@ -11,8 +11,8 @@ import (
"testing"
"time"
"gitea.com/gitea/runner/internal/pkg/client/mocks"
"gitea.com/gitea/runner/internal/pkg/config"
"gitea.com/gitea/act_runner/internal/pkg/client/mocks"
"gitea.com/gitea/act_runner/internal/pkg/config"
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
connect_go "connectrpc.com/connect"

View File

@@ -15,16 +15,16 @@ import (
"sync/atomic"
"time"
"gitea.com/gitea/runner/act/artifactcache"
"gitea.com/gitea/runner/act/common"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/runner/act/runner"
"gitea.com/gitea/runner/internal/pkg/client"
"gitea.com/gitea/runner/internal/pkg/config"
"gitea.com/gitea/runner/internal/pkg/labels"
"gitea.com/gitea/runner/internal/pkg/metrics"
"gitea.com/gitea/runner/internal/pkg/report"
"gitea.com/gitea/runner/internal/pkg/ver"
"gitea.com/gitea/act_runner/act/artifactcache"
"gitea.com/gitea/act_runner/act/common"
"gitea.com/gitea/act_runner/act/model"
"gitea.com/gitea/act_runner/act/runner"
"gitea.com/gitea/act_runner/internal/pkg/client"
"gitea.com/gitea/act_runner/internal/pkg/config"
"gitea.com/gitea/act_runner/internal/pkg/labels"
"gitea.com/gitea/act_runner/internal/pkg/metrics"
"gitea.com/gitea/act_runner/internal/pkg/report"
"gitea.com/gitea/act_runner/internal/pkg/ver"
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
"connectrpc.com/connect"

View File

@@ -9,7 +9,7 @@ import (
"sort"
"strings"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/model"
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
"go.yaml.in/yaml/v4"

View File

@@ -6,7 +6,7 @@ package run
import (
"testing"
"gitea.com/gitea/runner/act/model"
"gitea.com/gitea/act_runner/act/model"
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
"github.com/stretchr/testify/require"

View File

@@ -1,7 +1,7 @@
# Example configuration file, it's safe to copy this as the default config file without any modification.
# You don't have to copy this file to your instance,
# just run `./runner generate-config > config.yaml` to generate a config file.
# just run `./act_runner generate-config > config.yaml` to generate a config file.
log:
# The level of logging, can be trace, debug, info, warn, error, fatal
@@ -79,21 +79,21 @@ cache:
# 0 means to use a random available port.
port: 0
# The external cache server URL. Valid only when enable is true.
# If it's specified, runner will use this URL as the ACTIONS_CACHE_URL rather than start a server by itself.
# If it's specified, act_runner will use this URL as the ACTIONS_CACHE_URL rather than start a server by itself.
# The URL should generally end with "/".
external_server: ""
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, runner will create a network automatically.
# If it's empty, act_runner will 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
# Any other options to be used when the container is started (e.g., --add-host=my.gitea.url:host-gateway).
options:
# The parent directory of a job's working directory.
# NOTE: There is no need to add the first '/' of the path as runner will add it automatically.
# NOTE: There is no need to add the first '/' of the path as act_runner will add it automatically.
# If the path starts with '/', the '/' will be trimmed.
# For example, if the parent directory is /path/to/my/dir, workdir_parent should be path/to/my/dir
# If it's empty, /workspace will be used.
@@ -109,17 +109,17 @@ container:
# - '**'
valid_volumes: []
# Overrides the docker client host with the specified one.
# If it's empty, runner will find an available docker host automatically.
# If it's "-", runner will find an available docker host automatically, but the docker host won't be mounted to the job containers and service containers.
# If it's empty, act_runner will find an available docker host automatically.
# If it's "-", act_runner will find an available docker host automatically, but the docker host won't be mounted to the job containers and service containers.
# If it's not empty or "-", the specified docker host will be used. An error will be returned if it doesn't work.
docker_host: ""
# Pull docker image(s) even if already present
force_pull: true
# Rebuild docker image(s) even if already present
force_rebuild: false
# Always require a reachable docker daemon, even if not required by runner
# Always require a reachable docker daemon, even if not required by act_runner
require_docker: false
# Timeout to wait for the docker daemon to be reachable, if docker is required by require_docker or runner
# Timeout to wait for the docker daemon to be reachable, if docker is required by require_docker or act_runner
docker_timeout: 0s
# Bind the workspace to the host filesystem instead of using Docker volumes.
# This is required for Docker-in-Docker (DinD) setups when jobs use docker compose

View File

@@ -60,8 +60,8 @@ type Container struct {
DockerHost string `yaml:"docker_host"` // DockerHost specifies the Docker host. It overrides the value specified in environment variable DOCKER_HOST.
ForcePull bool `yaml:"force_pull"` // Pull docker image(s) even if already present
ForceRebuild bool `yaml:"force_rebuild"` // Rebuild docker image(s) even if already present
RequireDocker bool `yaml:"require_docker"` // Always require a reachable docker daemon, even if not required by runner
DockerTimeout time.Duration `yaml:"docker_timeout"` // Timeout to wait for the docker daemon to be reachable, if docker is required by require_docker or runner
RequireDocker bool `yaml:"require_docker"` // Always require a reachable docker daemon, even if not required by act_runner
DockerTimeout time.Duration `yaml:"docker_timeout"` // Timeout to wait for the docker daemon to be reachable, if docker is required by require_docker or act_runner
BindWorkdir bool `yaml:"bind_workdir"` // BindWorkdir binds the workspace to the host filesystem instead of using Docker volumes. Required for DinD when jobs use docker compose with bind mounts.
}
@@ -185,7 +185,7 @@ func LoadDefault(file string) (*Config, error) {
if cfg.Container.NetworkMode == "bridge" {
// Previously, if the value of `container.network_mode` is `bridge`, we will create a new network for job.
// But “bridge” is easily confused with the bridge network created by Docker by default.
// So we set the value of `container.network` to empty string to make `runner` automatically create a new network for job.
// So we set the value of `container.network` to empty string to make `act_runner` automatically create a new network for job.
cfg.Container.Network = ""
} else {
cfg.Container.Network = cfg.Container.NetworkMode

View File

@@ -12,8 +12,8 @@ import (
"github.com/prometheus/client_golang/prometheus/collectors"
)
// Namespace is the Prometheus namespace for all runner metrics.
const Namespace = "runner"
// Namespace is the Prometheus namespace for all act_runner metrics.
const Namespace = "act_runner"
// Label value constants for Prometheus metrics.
// Using constants prevents typos from silently creating new time-series.

View File

@@ -10,11 +10,12 @@ import (
"regexp"
"strings"
"sync"
"sync/atomic"
"time"
"gitea.com/gitea/runner/internal/pkg/client"
"gitea.com/gitea/runner/internal/pkg/config"
"gitea.com/gitea/runner/internal/pkg/metrics"
"gitea.com/gitea/act_runner/internal/pkg/client"
"gitea.com/gitea/act_runner/internal/pkg/config"
"gitea.com/gitea/act_runner/internal/pkg/metrics"
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
"connectrpc.com/connect"
@@ -48,6 +49,10 @@ type Reporter struct {
outputs sync.Map
daemon chan struct{}
// Unix-nanos of the last successful UpdateTask. Atomic so the heartbeat
// guard in ReportState reads it without contending stateMu.
lastReportedAtNanos atomic.Int64
// Adaptive batching control
logReportInterval time.Duration
logReportMaxLatency time.Duration
@@ -489,8 +494,12 @@ func (r *Reporter) ReportState(reportResult bool) error {
// Consume stateChanged atomically with the snapshot; restored on error
// below so a concurrent Fire() during UpdateTask isn't silently lost.
// Heartbeat at stateReportInterval even when nothing changed, so the server
// doesn't time out long-running silent jobs as orphaned (#826).
last := r.lastReportedAtNanos.Load()
withinHeartbeatInterval := last != 0 && time.Since(time.Unix(0, last)) < r.stateReportInterval
r.stateMu.Lock()
if !reportResult && !r.stateChanged && len(outputs) == 0 {
if !reportResult && !r.stateChanged && len(outputs) == 0 && withinHeartbeatInterval {
r.stateMu.Unlock()
return nil
}
@@ -517,6 +526,7 @@ func (r *Reporter) ReportState(reportResult bool) error {
return err
}
metrics.ReportStateTotal.WithLabelValues(metrics.LabelResultSuccess).Inc()
r.lastReportedAtNanos.Store(time.Now().UnixNano())
for _, k := range resp.Msg.SentOutputs {
r.outputs.Store(k, struct{}{})

View File

@@ -12,8 +12,8 @@ import (
"testing"
"time"
"gitea.com/gitea/runner/internal/pkg/client/mocks"
"gitea.com/gitea/runner/internal/pkg/config"
"gitea.com/gitea/act_runner/internal/pkg/client/mocks"
"gitea.com/gitea/act_runner/internal/pkg/config"
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
connect_go "connectrpc.com/connect"
@@ -220,7 +220,7 @@ func TestReporter_Fire(t *testing.T) {
}
// TestReporter_EphemeralRunnerDeletion reproduces the exact scenario from
// https://gitea.com/gitea/runner/issues/793:
// https://gitea.com/gitea/act_runner/issues/793:
//
// 1. RunDaemon calls ReportLog(false) — runner is still alive
// 2. Close() updates state to Result=FAILURE (between RunDaemon's ReportLog and ReportState)
@@ -597,3 +597,45 @@ func TestReporter_StateNotifyFlush(t *testing.T) {
}, 500*time.Millisecond, 10*time.Millisecond,
"step transition should have triggered immediate state flush via stateNotify")
}
// TestReporter_StateHeartbeat verifies that ReportState sends a heartbeat
// UpdateTask once stateReportInterval has elapsed since the last successful
// report, even when nothing has changed. Without this, long-running silent
// jobs (no log output, no step transitions) cause the server to time the
// task out and cancel it (#826).
func TestReporter_StateHeartbeat(t *testing.T) {
var updateTaskCalls atomic.Int64
client := mocks.NewClient(t)
client.On("UpdateTask", mock.Anything, mock.Anything).Return(
func(_ context.Context, _ *connect_go.Request[runnerv1.UpdateTaskRequest]) (*connect_go.Response[runnerv1.UpdateTaskResponse], error) {
updateTaskCalls.Add(1)
return connect_go.NewResponse(&runnerv1.UpdateTaskResponse{}), nil
},
)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
taskCtx, err := structpb.NewStruct(map[string]any{})
require.NoError(t, err)
cfg, _ := config.LoadDefault("")
cfg.Runner.StateReportInterval = 50 * time.Millisecond
reporter := NewReporter(ctx, cancel, client, &runnerv1.Task{Context: taskCtx}, cfg)
reporter.ResetSteps(1)
// First call has no prior report — sends to seed lastReportedAt.
reporter.stateMu.Lock()
reporter.stateChanged = true
reporter.stateMu.Unlock()
require.NoError(t, reporter.ReportState(false))
require.Equal(t, int64(1), updateTaskCalls.Load())
// Second call immediately after with nothing changed — must skip.
require.NoError(t, reporter.ReportState(false))
assert.Equal(t, int64(1), updateTaskCalls.Load(), "no-op ReportState within stateReportInterval must skip")
// After stateReportInterval elapses, a heartbeat must fire even with no changes.
time.Sleep(2 * cfg.Runner.StateReportInterval)
require.NoError(t, reporter.ReportState(false))
assert.Equal(t, int64(2), updateTaskCalls.Load(), "ReportState must heartbeat after stateReportInterval even with no state change")
}

View File

@@ -3,7 +3,7 @@
package ver
// go build -ldflags "-X gitea.com/gitea/runner/internal/pkg/ver.version=1.2.3"
// go build -ldflags "-X gitea.com/gitea/act_runner/internal/pkg/ver.version=1.2.3"
var version = "dev"
func Version() string {

View File

@@ -8,7 +8,7 @@ import (
"os/signal"
"syscall"
"gitea.com/gitea/runner/internal/app/cmd"
"gitea.com/gitea/act_runner/internal/app/cmd"
)
func main() {

View File

@@ -36,12 +36,12 @@ if [[ ! -s "$RUNNER_STATE_FILE" ]]; then
try=$((try + 1))
success=0
# The point of this loop is to make it simple, when running both runner and gitea in docker,
# for the runner to wait a moment for gitea to become available before erroring out. Within
# The point of this loop is to make it simple, when running both act_runner and gitea in docker,
# for the act_runner to wait a moment for gitea to become available before erroring out. Within
# the context of a single docker-compose, something similar could be done via healthchecks, but
# this is more flexible.
while [[ $success -eq 0 ]] && [[ $try -lt ${GITEA_MAX_REG_ATTEMPTS:-10} ]]; do
runner register \
act_runner register \
--instance "${GITEA_INSTANCE_URL}" \
--token "${GITEA_RUNNER_REGISTRATION_TOKEN}" \
--name "${GITEA_RUNNER_NAME:-`hostname`}" \
@@ -57,8 +57,8 @@ if [[ ! -s "$RUNNER_STATE_FILE" ]]; then
fi
done
fi
# Prevent reading the token from the runner process
# Prevent reading the token from the act_runner process
unset GITEA_RUNNER_REGISTRATION_TOKEN
unset GITEA_RUNNER_REGISTRATION_TOKEN_FILE
exec runner daemon ${CONFIG_ARG} ${RUN_ARGS}
exec act_runner daemon ${CONFIG_ARG} ${RUN_ARGS}

View File

@@ -1,5 +1,9 @@
#!/usr/bin/env bash
while [ ! -d /etc/s6/docker/supervise ]; do
sleep 0.1
done
s6-svwait -U /etc/s6/docker
exec run.sh