Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c66de4df2 | ||
|
|
9de33d4252 | ||
|
|
ff8375c6e1 | ||
| 3e22214bbd | |||
| b4e90db372 | |||
| c6b9e0c2d1 | |||
| aefab79307 |
@@ -1,85 +0,0 @@
|
||||
---
|
||||
name: release-nightly
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
env:
|
||||
DOCKER_ORG: gitea
|
||||
DOCKER_LATEST: nightly
|
||||
|
||||
jobs:
|
||||
goreleaser:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
- name: goreleaser
|
||||
uses: goreleaser/goreleaser-action@v6
|
||||
with:
|
||||
distribution: goreleaser-pro
|
||||
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 }}
|
||||
GORELEASER_FORCE_TOKEN: "gitea"
|
||||
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
release-image:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
variant:
|
||||
- target: basic
|
||||
tag_suffix: ""
|
||||
- target: dind
|
||||
tag_suffix: "-dind"
|
||||
- target: dind-rootless
|
||||
tag_suffix: "-dind-rootless"
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # all history for all branches and tags
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker BuildX
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Echo the tag
|
||||
run: echo "${{ env.DOCKER_ORG }}/act_runner:nightly${{ matrix.variant.tag_suffix }}"
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
target: ${{ matrix.variant.target }}
|
||||
platforms: |
|
||||
linux/amd64
|
||||
linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.DOCKER_ORG }}/act_runner:nightly${{ matrix.variant.tag_suffix }}
|
||||
@@ -1,111 +1,76 @@
|
||||
name: release-tag
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
goreleaser:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- goos: linux
|
||||
goarch: amd64
|
||||
- goos: linux
|
||||
goarch: arm64
|
||||
- goos: darwin
|
||||
goarch: amd64
|
||||
- goos: darwin
|
||||
goarch: arm64
|
||||
- goos: windows
|
||||
goarch: amd64
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # all history for all branches and tags
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
- name: Import GPG key
|
||||
id: import_gpg
|
||||
uses: crazy-max/ghaction-import-gpg@v6
|
||||
with:
|
||||
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
passphrase: ${{ secrets.PASSPHRASE }}
|
||||
fingerprint: CC64B1DB67ABBEECAB24B6455FC346329753F4B0
|
||||
- name: goreleaser
|
||||
uses: goreleaser/goreleaser-action@v6
|
||||
with:
|
||||
distribution: goreleaser-pro
|
||||
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@v4
|
||||
with:
|
||||
fetch-depth: 0 # all history for all branches and tags
|
||||
go-version-file: 'go.mod'
|
||||
cache: false
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker BuildX
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Get Meta
|
||||
id: meta
|
||||
- name: Build
|
||||
run: |
|
||||
echo REPO_NAME=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $2}') >> $GITHUB_OUTPUT
|
||||
echo REPO_VERSION=${GITHUB_REF_NAME#v} >> $GITHUB_OUTPUT
|
||||
VERSION=${GITHUB_REF_NAME#v}
|
||||
EXT=""
|
||||
if [ "${{ matrix.goos }}" = "windows" ]; then
|
||||
EXT=".exe"
|
||||
fi
|
||||
CGO_ENABLED=0 GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} \
|
||||
go build -ldflags "-X gitea.com/gitea/act_runner/internal/pkg/ver.version=${VERSION}" \
|
||||
-o act_runner-${{ matrix.goos }}-${{ matrix.goarch }}${EXT}
|
||||
env:
|
||||
GOPRIVATE: git.marketally.com
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
target: basic
|
||||
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: act_runner-${{ matrix.goos }}-${{ matrix.goarch }}
|
||||
path: act_runner-*
|
||||
|
||||
- name: Build and push dind
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
target: dind
|
||||
platforms: |
|
||||
linux/amd64
|
||||
linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.REPO_VERSION }}-dind
|
||||
${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ env.DOCKER_LATEST }}-dind
|
||||
release:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build and push dind-rootless
|
||||
uses: docker/build-push-action@v5
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
target: dind-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
|
||||
path: artifacts
|
||||
|
||||
- name: Prepare release files
|
||||
run: |
|
||||
mkdir -p release
|
||||
find artifacts -type f -name 'act_runner-*' -exec mv {} release/ \;
|
||||
cd release && sha256sum * > checksums.txt
|
||||
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: release/*
|
||||
generate_release_notes: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -1,20 +1,33 @@
|
||||
name: checks
|
||||
name: CI
|
||||
|
||||
on:
|
||||
- push
|
||||
- pull_request
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: check and test
|
||||
build-and-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: 'go.mod'
|
||||
- name: vet checks
|
||||
cache: false
|
||||
|
||||
- name: Vet
|
||||
run: make vet
|
||||
- name: build
|
||||
env:
|
||||
GOPRIVATE: git.marketally.com
|
||||
|
||||
- name: Build
|
||||
run: make build
|
||||
- name: test
|
||||
env:
|
||||
GOPRIVATE: git.marketally.com
|
||||
|
||||
- name: Test
|
||||
run: make test
|
||||
env:
|
||||
GOPRIVATE: git.marketally.com
|
||||
|
||||
221
README.md
221
README.md
@@ -1,108 +1,195 @@
|
||||
# act runner
|
||||
# GitCaddy Act 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 Gitea Actions runner with enhanced capability detection and reporting for AI-friendly workflow generation.
|
||||
|
||||
> **This is a GitCaddy fork** of [gitea.com/gitea/act_runner](https://gitea.com/gitea/act_runner) with runner capability discovery features.
|
||||
|
||||
## Overview
|
||||
|
||||
Act Runner executes Gitea Actions workflows using [act](https://github.com/nektos/act). This fork adds automatic capability detection, enabling Gitea to expose runner capabilities via API for AI tools to query before generating workflows.
|
||||
|
||||
## Key Features
|
||||
|
||||
- **Capability Detection**: Automatically detects OS, architecture, Docker support, available shells, and installed tools
|
||||
- **Capability Reporting**: Reports capabilities to Gitea server during runner declaration
|
||||
- **Full Compatibility**: Drop-in replacement for standard act_runner
|
||||
- **Multi-Platform**: Supports Linux, macOS, and Windows
|
||||
|
||||
## Installation
|
||||
|
||||
### Prerequisites
|
||||
### Download Pre-built Binary
|
||||
|
||||
Docker Engine Community version is required for docker mode. To install Docker CE, follow the official [install instructions](https://docs.docker.com/engine/install/).
|
||||
|
||||
### Download pre-built binary
|
||||
|
||||
Visit [here](https://dl.gitea.com/act_runner/) and download the right version for your platform.
|
||||
|
||||
### Build from source
|
||||
Download from [Releases](https://git.marketally.com/gitcaddy/act_runner/releases):
|
||||
|
||||
```bash
|
||||
# Linux (amd64)
|
||||
curl -L -o act_runner https://git.marketally.com/gitcaddy/act_runner/releases/download/v0.3.1-gitcaddy/act_runner-linux-amd64
|
||||
chmod +x act_runner
|
||||
|
||||
# macOS (Apple Silicon)
|
||||
curl -L -o act_runner https://git.marketally.com/gitcaddy/act_runner/releases/download/v0.3.1-gitcaddy/act_runner-darwin-arm64
|
||||
chmod +x act_runner
|
||||
```
|
||||
|
||||
### Build from Source
|
||||
|
||||
```bash
|
||||
git clone https://git.marketally.com/gitcaddy/act_runner.git
|
||||
cd act_runner
|
||||
make build
|
||||
```
|
||||
|
||||
### Build a docker image
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
make docker
|
||||
```
|
||||
### 1. Enable Actions in Gitea
|
||||
|
||||
## Quickstart
|
||||
Add to your Gitea `app.ini`:
|
||||
|
||||
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
|
||||
ENABLED = true
|
||||
```
|
||||
|
||||
### Register
|
||||
### 2. Register the Runner
|
||||
|
||||
```bash
|
||||
./act_runner register
|
||||
./act_runner register \
|
||||
--instance https://your-gitea-instance.com \
|
||||
--token YOUR_RUNNER_TOKEN \
|
||||
--name my-runner \
|
||||
--labels ubuntu-latest,docker
|
||||
```
|
||||
|
||||
And you will be asked to input:
|
||||
|
||||
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/actions/runners`;
|
||||
3. Runner name, you can just leave it blank;
|
||||
4. Runner labels, you can just leave it blank.
|
||||
|
||||
The process looks like:
|
||||
|
||||
```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):
|
||||
|
||||
INFO Enter the runner labels, leave blank to use the default labels (comma-separated, for example, ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest):
|
||||
|
||||
INFO Registering runner, name=Test.local, instance=http://192.168.8.8:3000/, labels=[ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest ubuntu-22.04:docker://docker.gitea.com/runner-images:ubuntu-22.04 ubuntu-20.04:docker://docker.gitea.com/runner-images:ubuntu-20.04].
|
||||
DEBU Successfully pinged the Gitea instance server
|
||||
INFO Runner registered successfully.
|
||||
```
|
||||
|
||||
You can also register with command line arguments.
|
||||
|
||||
```bash
|
||||
./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.
|
||||
|
||||
### Run
|
||||
### 3. Start the Runner
|
||||
|
||||
```bash
|
||||
./act_runner daemon
|
||||
```
|
||||
|
||||
### Run with docker
|
||||
On startup, the runner will:
|
||||
1. Detect system capabilities (OS, arch, Docker, shells, tools)
|
||||
2. Report capabilities to Gitea via the Declare API
|
||||
3. Begin polling for jobs
|
||||
|
||||
```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/act_runner:nightly
|
||||
## Capability Detection
|
||||
|
||||
The runner automatically detects:
|
||||
|
||||
| Category | Examples |
|
||||
|----------|----------|
|
||||
| **OS/Arch** | linux/amd64, darwin/arm64, windows/amd64 |
|
||||
| **Container Runtime** | Docker, Podman |
|
||||
| **Shells** | bash, sh, zsh, powershell, cmd |
|
||||
| **Tools** | Node.js, Go, Python, Java, .NET, Rust |
|
||||
| **Features** | Cache support, Docker Compose |
|
||||
|
||||
### Example Capabilities JSON
|
||||
|
||||
```json
|
||||
{
|
||||
"os": "linux",
|
||||
"arch": "amd64",
|
||||
"docker": true,
|
||||
"docker_compose": true,
|
||||
"container_runtime": "docker",
|
||||
"shell": ["bash", "sh"],
|
||||
"tools": {
|
||||
"node": ["18.19.0"],
|
||||
"go": ["1.21.5"],
|
||||
"python": ["3.11.6"]
|
||||
},
|
||||
"features": {
|
||||
"cache": true,
|
||||
"docker_services": true
|
||||
},
|
||||
"limitations": []
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration
|
||||
## 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 `./act_runner generate-config`.
|
||||
Create a config file or use command-line flags:
|
||||
|
||||
```bash
|
||||
./act_runner generate-config > config.yaml
|
||||
./act_runner -c config.yaml daemon
|
||||
```
|
||||
|
||||
You can specify the configuration file path with `-c`/`--config` argument.
|
||||
Example configuration:
|
||||
|
||||
```yaml
|
||||
log:
|
||||
level: info
|
||||
|
||||
runner:
|
||||
file: .runner
|
||||
capacity: 1
|
||||
timeout: 3h
|
||||
labels:
|
||||
- ubuntu-latest:docker://node:18-bullseye
|
||||
- ubuntu-22.04:docker://ubuntu:22.04
|
||||
|
||||
container:
|
||||
docker_host: ""
|
||||
force_pull: false
|
||||
privileged: false
|
||||
|
||||
cache:
|
||||
enabled: true
|
||||
dir: ~/.cache/actcache
|
||||
```
|
||||
|
||||
## Docker Deployment
|
||||
|
||||
```bash
|
||||
./act_runner -c config.yaml register # register with config file
|
||||
./act_runner -c config.yaml daemon # run with config file
|
||||
docker run -d \
|
||||
--name act_runner \
|
||||
-e GITEA_INSTANCE_URL=https://your-gitea.com \
|
||||
-e GITEA_RUNNER_REGISTRATION_TOKEN=<token> \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v ./data:/data \
|
||||
gitcaddy/act_runner:latest
|
||||
```
|
||||
|
||||
You can read the latest version of the configuration file online at [config.example.yaml](internal/pkg/config/config.example.yaml).
|
||||
## GitCaddy Integration
|
||||
|
||||
### Example Deployments
|
||||
This runner is designed to work with the [GitCaddy Gitea fork](https://git.marketally.com/gitcaddy/gitea), which provides:
|
||||
|
||||
Check out the [examples](examples) directory for sample deployment types.
|
||||
- **Runner Capabilities API** (`/api/v2/repos/{owner}/{repo}/actions/runners/capabilities`)
|
||||
- **Workflow Validation API** for pre-flight checks
|
||||
- **Action Compatibility Database** for GitHub Actions mapping
|
||||
|
||||
### How It Works
|
||||
|
||||
```
|
||||
|
||||
act_runner Gitea AI Tool
|
||||
| | |
|
||||
| Declare + Capabilities | |
|
||||
|---------------------------->| |
|
||||
| | |
|
||||
| | GET /api/v2/.../caps |
|
||||
| |<------------------------|
|
||||
| | |
|
||||
| | Runner capabilities |
|
||||
| |------------------------>|
|
||||
| | |
|
||||
| | Generates workflow |
|
||||
| | with correct config |
|
||||
|
||||
```
|
||||
|
||||
## Related Projects
|
||||
|
||||
| Project | Description |
|
||||
|---------|-------------|
|
||||
| [gitcaddy/gitea](https://git.marketally.com/gitcaddy/gitea) | Gitea with AI-friendly enhancements |
|
||||
| [gitcaddy/actions-proto-go](https://git.marketally.com/gitcaddy/actions-proto-go) | Protocol definitions with capability support |
|
||||
|
||||
## Upstream
|
||||
|
||||
This project is a fork of [gitea.com/gitea/act_runner](https://gitea.com/gitea/act_runner). We contribute enhancements back to upstream where appropriate.
|
||||
|
||||
## License
|
||||
|
||||
MIT License - see [LICENSE](LICENSE) for details.
|
||||
|
||||
7
go.mod
7
go.mod
@@ -5,7 +5,7 @@ go 1.24.0
|
||||
toolchain go1.24.11
|
||||
|
||||
require (
|
||||
code.gitea.io/actions-proto-go v0.5.0
|
||||
code.gitea.io/actions-proto-go v0.5.2
|
||||
code.gitea.io/gitea-vet v0.2.3
|
||||
connectrpc.com/connect v1.16.2
|
||||
github.com/avast/retry-go/v4 v4.6.0
|
||||
@@ -23,6 +23,8 @@ require (
|
||||
gotest.tools/v3 v3.5.1
|
||||
)
|
||||
|
||||
require golang.org/x/sys v0.37.0
|
||||
|
||||
require (
|
||||
cyphar.com/go-pathrs v0.2.1 // indirect
|
||||
dario.cat/mergo v1.0.0 // indirect
|
||||
@@ -96,7 +98,6 @@ require (
|
||||
golang.org/x/crypto v0.43.0 // indirect
|
||||
golang.org/x/net v0.45.0 // indirect
|
||||
golang.org/x/sync v0.16.0 // indirect
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
golang.org/x/tools v0.23.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
@@ -110,4 +111,4 @@ replace github.com/go-git/go-git/v5 => github.com/go-git/go-git/v5 v5.16.2
|
||||
replace github.com/distribution/reference v0.6.0 => github.com/distribution/reference v0.5.0
|
||||
|
||||
// Use GitCaddy fork with capability support
|
||||
replace code.gitea.io/actions-proto-go => git.marketally.com/gitcaddy/actions-proto-go v0.5.0
|
||||
replace code.gitea.io/actions-proto-go => git.marketally.com/gitcaddy/actions-proto-go v0.5.6
|
||||
|
||||
4
go.sum
4
go.sum
@@ -6,8 +6,8 @@ cyphar.com/go-pathrs v0.2.1 h1:9nx1vOgwVvX1mNBWDu93+vaceedpbsDqo+XuBGL40b8=
|
||||
cyphar.com/go-pathrs v0.2.1/go.mod h1:y8f1EMG7r+hCuFf/rXsKqMJrJAUoADZGNh5/vZPKcGc=
|
||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
git.marketally.com/gitcaddy/actions-proto-go v0.5.0 h1:D2loMnqTXiaJL6TMfOOUJz4/3Vpv0AnMDSJVuiqMNrM=
|
||||
git.marketally.com/gitcaddy/actions-proto-go v0.5.0/go.mod h1:li5RzZsj1sV8a0SXzXWsGNwv0dYw7Wj829AgloZqF5o=
|
||||
git.marketally.com/gitcaddy/actions-proto-go v0.5.6 h1:G7T0vpx8HyCFWd0YMJ9sp8rCsWtzFrCJK4BMdOFJa1A=
|
||||
git.marketally.com/gitcaddy/actions-proto-go v0.5.6/go.mod h1:RPu21UoRD3zSAujoZR6LJwuVNa2uFRBveadslczCRfQ=
|
||||
gitea.com/gitea/act v0.261.7-0.20251202193638-5417d3ac6742 h1:ulcquQluJbmNASkh6ina70LvcHEa9eWYfQ+DeAZ0VEE=
|
||||
gitea.com/gitea/act v0.261.7-0.20251202193638-5417d3ac6742/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
|
||||
|
||||
@@ -30,6 +30,15 @@ import (
|
||||
"gitea.com/gitea/act_runner/internal/pkg/ver"
|
||||
)
|
||||
|
||||
const (
|
||||
// DiskSpaceWarningThreshold is the percentage at which to warn about low disk space
|
||||
DiskSpaceWarningThreshold = 85.0
|
||||
// DiskSpaceCriticalThreshold is the percentage at which to log critical warnings
|
||||
DiskSpaceCriticalThreshold = 95.0
|
||||
// CapabilitiesUpdateInterval is how often to update capabilities (including disk space)
|
||||
CapabilitiesUpdateInterval = 5 * time.Minute
|
||||
)
|
||||
|
||||
func runDaemon(ctx context.Context, daemArgs *daemonArgs, configFile *string) func(cmd *cobra.Command, args []string) error {
|
||||
return func(cmd *cobra.Command, args []string) error {
|
||||
cfg, err := config.LoadDefault(*configFile)
|
||||
@@ -147,6 +156,9 @@ func runDaemon(ctx context.Context, daemArgs *daemonArgs, configFile *string) fu
|
||||
capabilitiesJson := capabilities.ToJSON()
|
||||
log.Infof("detected capabilities: %s", capabilitiesJson)
|
||||
|
||||
// Check disk space and warn if low
|
||||
checkDiskSpaceWarnings(capabilities)
|
||||
|
||||
// declare the labels of the runner before fetching tasks
|
||||
resp, err := runner.Declare(ctx, ls.Names(), capabilitiesJson)
|
||||
if err != nil && connect.CodeOf(err) == connect.CodeUnimplemented {
|
||||
@@ -160,6 +172,9 @@ func runDaemon(ctx context.Context, daemArgs *daemonArgs, configFile *string) fu
|
||||
resp.Msg.Runner.Name, resp.Msg.Runner.Version, resp.Msg.Runner.Labels)
|
||||
}
|
||||
|
||||
// Start periodic capabilities update goroutine
|
||||
go periodicCapabilitiesUpdate(ctx, runner, ls.Names(), dockerHost)
|
||||
|
||||
poller := poll.New(cfg, cli, runner)
|
||||
|
||||
if daemArgs.Once || reg.Ephemeral {
|
||||
@@ -194,6 +209,53 @@ func runDaemon(ctx context.Context, daemArgs *daemonArgs, configFile *string) fu
|
||||
}
|
||||
}
|
||||
|
||||
// checkDiskSpaceWarnings logs warnings if disk space is low
|
||||
func checkDiskSpaceWarnings(capabilities *envcheck.RunnerCapabilities) {
|
||||
if capabilities.Disk == nil {
|
||||
return
|
||||
}
|
||||
|
||||
usedPercent := capabilities.Disk.UsedPercent
|
||||
freeGB := float64(capabilities.Disk.Free) / (1024 * 1024 * 1024)
|
||||
|
||||
if usedPercent >= DiskSpaceCriticalThreshold {
|
||||
log.Errorf("CRITICAL: Disk space critically low! %.1f%% used, only %.2f GB free. Runner may fail to execute jobs!", usedPercent, freeGB)
|
||||
} else if usedPercent >= DiskSpaceWarningThreshold {
|
||||
log.Warnf("WARNING: Disk space running low. %.1f%% used, %.2f GB free. Consider cleaning up disk space.", usedPercent, freeGB)
|
||||
}
|
||||
}
|
||||
|
||||
// periodicCapabilitiesUpdate periodically updates capabilities including disk space
|
||||
func periodicCapabilitiesUpdate(ctx context.Context, runner *run.Runner, labelNames []string, dockerHost string) {
|
||||
ticker := time.NewTicker(CapabilitiesUpdateInterval)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
log.Debug("stopping periodic capabilities update")
|
||||
return
|
||||
case <-ticker.C:
|
||||
// Detect updated capabilities (disk space changes over time)
|
||||
capabilities := envcheck.DetectCapabilities(ctx, dockerHost)
|
||||
capabilitiesJson := capabilities.ToJSON()
|
||||
|
||||
// Check for disk space warnings
|
||||
checkDiskSpaceWarnings(capabilities)
|
||||
|
||||
// Send updated capabilities to server
|
||||
_, err := runner.Declare(ctx, labelNames, capabilitiesJson)
|
||||
if err != nil {
|
||||
log.WithError(err).Debug("failed to update capabilities")
|
||||
} else {
|
||||
log.Debugf("capabilities updated: disk %.1f%% used, %.2f GB free",
|
||||
capabilities.Disk.UsedPercent,
|
||||
float64(capabilities.Disk.Free)/(1024*1024*1024))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type daemonArgs struct {
|
||||
Once bool
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"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"
|
||||
)
|
||||
|
||||
type Poller struct {
|
||||
@@ -157,11 +158,17 @@ func (p *Poller) fetchTask(ctx context.Context) (*runnerv1.Task, bool) {
|
||||
reqCtx, cancel := context.WithTimeout(ctx, p.cfg.Runner.FetchTimeout)
|
||||
defer cancel()
|
||||
|
||||
// Detect capabilities including current disk space
|
||||
caps := envcheck.DetectCapabilities(ctx, p.cfg.Container.DockerHost)
|
||||
capsJson := caps.ToJSON()
|
||||
|
||||
// Load the version value that was in the cache when the request was sent.
|
||||
v := p.tasksVersion.Load()
|
||||
resp, err := p.client.FetchTask(reqCtx, connect.NewRequest(&runnerv1.FetchTaskRequest{
|
||||
TasksVersion: v,
|
||||
}))
|
||||
fetchReq := &runnerv1.FetchTaskRequest{
|
||||
TasksVersion: v,
|
||||
CapabilitiesJson: capsJson,
|
||||
}
|
||||
resp, err := p.client.FetchTask(reqCtx, connect.NewRequest(fetchReq))
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
err = nil
|
||||
}
|
||||
@@ -182,7 +189,7 @@ func (p *Poller) fetchTask(ctx context.Context) (*runnerv1.Task, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// got a task, set `tasksVersion` to zero to focre query db in next request.
|
||||
// got a task, set tasksVersion to zero to force query db in next request.
|
||||
p.tasksVersion.CompareAndSwap(resp.Msg.TasksVersion, 0)
|
||||
|
||||
return resp.Msg.Task, true
|
||||
|
||||
@@ -12,8 +12,17 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/client"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// DiskInfo holds disk space information
|
||||
type DiskInfo struct {
|
||||
Total uint64 `json:"total_bytes"`
|
||||
Free uint64 `json:"free_bytes"`
|
||||
Used uint64 `json:"used_bytes"`
|
||||
UsedPercent float64 `json:"used_percent"`
|
||||
}
|
||||
|
||||
// RunnerCapabilities represents the capabilities of a runner for AI consumption
|
||||
type RunnerCapabilities struct {
|
||||
OS string `json:"os"`
|
||||
@@ -25,6 +34,7 @@ type RunnerCapabilities struct {
|
||||
Tools map[string][]string `json:"tools,omitempty"`
|
||||
Features *CapabilityFeatures `json:"features,omitempty"`
|
||||
Limitations []string `json:"limitations,omitempty"`
|
||||
Disk *DiskInfo `json:"disk,omitempty"`
|
||||
}
|
||||
|
||||
// CapabilityFeatures represents feature support flags
|
||||
@@ -38,10 +48,10 @@ type CapabilityFeatures struct {
|
||||
// DetectCapabilities detects the runner's capabilities
|
||||
func DetectCapabilities(ctx context.Context, dockerHost string) *RunnerCapabilities {
|
||||
cap := &RunnerCapabilities{
|
||||
OS: runtime.GOOS,
|
||||
Arch: runtime.GOARCH,
|
||||
Tools: make(map[string][]string),
|
||||
Shell: detectShells(),
|
||||
OS: runtime.GOOS,
|
||||
Arch: runtime.GOARCH,
|
||||
Tools: make(map[string][]string),
|
||||
Shell: detectShells(),
|
||||
Features: &CapabilityFeatures{
|
||||
ArtifactsV4: false, // Gitea doesn't support v4 artifacts
|
||||
Cache: true,
|
||||
@@ -64,9 +74,40 @@ func DetectCapabilities(ctx context.Context, dockerHost string) *RunnerCapabilit
|
||||
// Detect common tools
|
||||
detectTools(ctx, cap)
|
||||
|
||||
// Detect disk space
|
||||
cap.Disk = detectDiskSpace()
|
||||
|
||||
return cap
|
||||
}
|
||||
|
||||
// detectDiskSpace detects disk space on the root filesystem
|
||||
func detectDiskSpace() *DiskInfo {
|
||||
var stat unix.Statfs_t
|
||||
|
||||
// Get stats for root filesystem (or current working directory)
|
||||
path := "/"
|
||||
if runtime.GOOS == "windows" {
|
||||
path = "C:\\"
|
||||
}
|
||||
|
||||
err := unix.Statfs(path, &stat)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
total := stat.Blocks * uint64(stat.Bsize)
|
||||
free := stat.Bavail * uint64(stat.Bsize)
|
||||
used := total - free
|
||||
usedPercent := float64(used) / float64(total) * 100
|
||||
|
||||
return &DiskInfo{
|
||||
Total: total,
|
||||
Free: free,
|
||||
Used: used,
|
||||
UsedPercent: usedPercent,
|
||||
}
|
||||
}
|
||||
|
||||
// ToJSON converts capabilities to JSON string for transmission
|
||||
func (c *RunnerCapabilities) ToJSON() string {
|
||||
data, err := json.Marshal(c)
|
||||
|
||||
Reference in New Issue
Block a user