Compare commits
139 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa69213d15 | ||
|
|
f92e50f35b | ||
|
|
a792b47b41 | ||
|
|
68ec7efde0 | ||
|
|
f314ffb036 | ||
|
|
b303a83a77 | ||
|
|
66d0b1e608 | ||
|
|
48a589eb79 | ||
|
|
fef300dd5b | ||
|
|
49a0b6f167 | ||
|
|
e5fdaadbd2 | ||
|
|
ab382dc256 | ||
|
|
2c66de4df2 | ||
|
|
9de33d4252 | ||
|
|
ff8375c6e1 | ||
| 3e22214bbd | |||
| b4e90db372 | |||
| c6b9e0c2d1 | |||
| aefab79307 | |||
| a6c08576a9 | |||
|
|
90d11b8692 | ||
|
|
c4b57fbcb2 | ||
|
|
e6dbe2a1ca | ||
|
|
774f316c8b | ||
|
|
823e9489d6 | ||
|
|
dc38bf1895 | ||
|
|
96b866a3a8 | ||
|
|
3b11bac2ad | ||
|
|
47caafd037 | ||
|
|
50e0509007 | ||
|
|
8920c4a170 | ||
|
|
bbf9d7e90f | ||
|
|
46f471a900 | ||
|
|
aa28f8d99c | ||
|
|
6a7e18b124 | ||
|
|
53329c46ff | ||
|
|
6b1aea9c04 | ||
|
|
edec9a8f91 | ||
|
|
6a9a447f86 | ||
|
|
5302c25feb | ||
|
|
a616ed1a10 | ||
|
|
f0b5aff3bb | ||
|
|
44b4736703 | ||
|
|
b1ae30dda8 | ||
|
|
0d687268c7 | ||
|
|
425a570261 | ||
|
|
4c8179ee12 | ||
|
|
5ae13f0bd7 | ||
|
|
3510152e36 | ||
|
|
8dfb805c62 | ||
|
|
a7080f5457 | ||
|
|
8b72d1c7ae | ||
|
|
8bc0275e74 | ||
|
|
0348aaac59 | ||
|
|
9712481bed | ||
|
|
b5f901b2d9 | ||
|
|
0e2a3e00f5 | ||
|
|
b282356e9e | ||
|
|
b075e3a1d5 | ||
|
|
e27189ea32 | ||
|
|
59e478464e | ||
|
|
e1c7b20898 | ||
|
|
2f78411c3d | ||
|
|
d1d3cad4b0 | ||
|
|
1735b26e66 | ||
|
|
65ed62d2f5 | ||
|
|
ec03f19650 | ||
|
|
8567324a19 | ||
|
|
be2df361ef | ||
|
|
a5085dde0c | ||
|
|
cef86d1140 | ||
|
|
94c45acf6b | ||
|
|
1760899d27 | ||
|
|
a7eca813ea | ||
|
|
23ec12b8cf | ||
|
|
a1fc2b3ca7 | ||
|
|
5977042b86 | ||
|
|
6bc19cbc33 | ||
|
|
75006a59cc | ||
|
|
4da97f53de | ||
|
|
45270656df | ||
|
|
e14f42c40a | ||
|
|
e6630e2e36 | ||
|
|
f1f9142a3c | ||
|
|
f17cad1bbe | ||
|
|
daf52d0e62 | ||
|
|
8c8a8ce401 | ||
|
|
08c681be0c | ||
|
|
91bfe4c186 | ||
|
|
825c6f97b7 | ||
|
|
2f3e5c7125 | ||
|
|
4d9de6ca8c | ||
|
|
feb39666cc | ||
|
|
61cd71c9f8 | ||
|
|
0adfc1c7cc | ||
|
|
e3c68668fa | ||
|
|
f1b27d5274 | ||
|
|
655a39fd61 | ||
|
|
cca7d54117 | ||
|
|
934471813a | ||
|
|
1e940f028b | ||
|
|
2020ce79bf | ||
|
|
00e9b3d62b | ||
|
|
130b9f1877 | ||
|
|
4c35288175 | ||
|
|
990db1bfc0 | ||
|
|
d07fbfc8c3 | ||
|
|
10dc6fb60d | ||
|
|
ed35b09b8f | ||
|
|
03f0829d09 | ||
|
|
7fc1b91ba6 | ||
|
|
82c3c2df1a | ||
|
|
9fc823e4b1 | ||
|
|
12999b61dd | ||
|
|
49a2fcc138 | ||
|
|
8f88e4f15a | ||
|
|
a1bb3b56fd | ||
|
|
1a7ec5f339 | ||
|
|
5d01cb8904 | ||
|
|
dcf84d8a53 | ||
|
|
73adae040d | ||
|
|
db662b3690 | ||
|
|
cf92a979e2 | ||
|
|
87058716fb | ||
|
|
c701ba4787 | ||
|
|
57ff1df6e0 | ||
|
|
3dcfd6ea3d | ||
|
|
c6006ee699 | ||
|
|
f2629f2ea3 | ||
|
|
cf48ed88ba | ||
|
|
ccc27329dc | ||
|
|
b0bd503b11 | ||
|
|
8c14933e70 | ||
|
|
34d15f21c2 | ||
|
|
32d29f0813 | ||
|
|
2e2c0400c8 | ||
|
|
054c8d912f | ||
|
|
9e4a5f7363 | ||
|
|
ec38401097 |
@@ -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
|
|
||||||
@@ -1,118 +1,79 @@
|
|||||||
name: release-tag
|
name: Release
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- '*'
|
- 'v*'
|
||||||
|
|
||||||
env:
|
|
||||||
GOPATH: /go_path
|
|
||||||
GOCACHE: /go_cache
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
goreleaser:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: linux-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:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # all history for all branches and tags
|
fetch-depth: 0
|
||||||
- uses: actions/setup-go@v3
|
|
||||||
|
- uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: '>=1.20.1'
|
go-version-file: 'go.mod'
|
||||||
- uses: https://gitea.com/actions/go-hashfiles@v0.0.1
|
cache: false
|
||||||
id: hash-go
|
|
||||||
with:
|
- name: Build
|
||||||
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:
|
env:
|
||||||
GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
|
GOPRIVATE: git.marketally.com
|
||||||
AWS_REGION: ${{ secrets.AWS_REGION }}
|
VERSION: ${{ github.ref_name }}
|
||||||
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: |
|
run: |
|
||||||
echo REPO_NAME=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $2}') >> $GITHUB_OUTPUT
|
# Strip the v prefix from tag
|
||||||
echo REPO_VERSION=$(git describe --tags --always | sed 's/^v//') >> $GITHUB_OUTPUT
|
VERSION="${VERSION#v}"
|
||||||
|
EXT=""
|
||||||
|
if [ "${{ matrix.goos }}" = "windows" ]; then
|
||||||
|
EXT=".exe"
|
||||||
|
fi
|
||||||
|
echo "Building version: ${VERSION}"
|
||||||
|
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}
|
||||||
|
|
||||||
- name: Build and push
|
- name: Upload artifact
|
||||||
uses: docker/build-push-action@v4
|
uses: actions/upload-artifact@v3
|
||||||
env:
|
|
||||||
ACTIONS_RUNTIME_TOKEN: '' # See https://gitea.com/gitea/act_runner/issues/119
|
|
||||||
with:
|
with:
|
||||||
context: .
|
name: act_runner-${{ matrix.goos }}-${{ matrix.goarch }}
|
||||||
file: ./Dockerfile
|
path: act_runner-*
|
||||||
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
|
release:
|
||||||
uses: docker/build-push-action@v4
|
needs: build
|
||||||
env:
|
runs-on: linux-latest
|
||||||
ACTIONS_RUNTIME_TOKEN: '' # See https://gitea.com/gitea/act_runner/issues/119
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Download all artifacts
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
context: .
|
path: artifacts
|
||||||
file: ./Dockerfile.rootless
|
|
||||||
platforms: |
|
- name: Prepare release files
|
||||||
linux/amd64
|
run: |
|
||||||
linux/arm64
|
mkdir -p release
|
||||||
push: true
|
find artifacts -type f -name 'act_runner-*' -exec mv {} release/ \;
|
||||||
tags: |
|
cd release && sha256sum * > checksums.txt
|
||||||
${{ 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
|
- name: Create Release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
files: release/*
|
||||||
|
generate_release_notes: true
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
@@ -1,38 +1,33 @@
|
|||||||
name: checks
|
name: CI
|
||||||
on:
|
|
||||||
- push
|
|
||||||
- pull_request
|
|
||||||
|
|
||||||
env:
|
on:
|
||||||
GOPATH: /go_path
|
push:
|
||||||
GOCACHE: /go_cache
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
build-and-test:
|
||||||
name: check and test
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v3
|
|
||||||
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '>=1.20.1'
|
go-version-file: 'go.mod'
|
||||||
- uses: https://gitea.com/actions/go-hashfiles@v0.0.1
|
cache: false
|
||||||
id: hash-go
|
|
||||||
with:
|
- name: Vet
|
||||||
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
|
run: make vet
|
||||||
- name: build
|
env:
|
||||||
|
GOPRIVATE: git.marketally.com
|
||||||
|
|
||||||
|
- name: Build
|
||||||
run: make build
|
run: make build
|
||||||
- name: test
|
env:
|
||||||
|
GOPRIVATE: git.marketally.com
|
||||||
|
|
||||||
|
- name: Test
|
||||||
run: make test
|
run: make test
|
||||||
|
env:
|
||||||
|
GOPRIVATE: git.marketally.com
|
||||||
|
|||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,10 +1,12 @@
|
|||||||
act_runner
|
/act_runner
|
||||||
.env
|
.env
|
||||||
.runner
|
.runner
|
||||||
coverage.txt
|
coverage.txt
|
||||||
/gitea-vet
|
/gitea-vet
|
||||||
/config.yaml
|
/config.yaml
|
||||||
|
|
||||||
|
# Jetbrains
|
||||||
|
.idea
|
||||||
# MS VSCode
|
# MS VSCode
|
||||||
.vscode
|
.vscode
|
||||||
__debug_bin
|
__debug_bin
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
linters:
|
linters:
|
||||||
enable:
|
enable:
|
||||||
- gosimple
|
- gosimple
|
||||||
- deadcode
|
|
||||||
- typecheck
|
- typecheck
|
||||||
- govet
|
- govet
|
||||||
- errcheck
|
- errcheck
|
||||||
- staticcheck
|
- staticcheck
|
||||||
- unused
|
- unused
|
||||||
- structcheck
|
|
||||||
- varcheck
|
|
||||||
- dupl
|
- dupl
|
||||||
#- gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time.
|
#- gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time.
|
||||||
- gofmt
|
- gofmt
|
||||||
@@ -112,7 +109,6 @@ issues:
|
|||||||
- gocritic
|
- gocritic
|
||||||
- linters:
|
- linters:
|
||||||
- unused
|
- unused
|
||||||
- deadcode
|
|
||||||
text: "swagger"
|
text: "swagger"
|
||||||
- path: contrib/pr/checkout.go
|
- path: contrib/pr/checkout.go
|
||||||
linters:
|
linters:
|
||||||
@@ -154,9 +150,6 @@ issues:
|
|||||||
- path: cmd/dump.go
|
- path: cmd/dump.go
|
||||||
linters:
|
linters:
|
||||||
- dupl
|
- dupl
|
||||||
- path: services/webhook/webhook.go
|
|
||||||
linters:
|
|
||||||
- structcheck
|
|
||||||
- text: "commentFormatting: put a space between `//` and comment text"
|
- text: "commentFormatting: put a space between `//` and comment text"
|
||||||
linters:
|
linters:
|
||||||
- gocritic
|
- gocritic
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
version: 2
|
||||||
|
|
||||||
before:
|
before:
|
||||||
hooks:
|
hooks:
|
||||||
- go mod tidy
|
- go mod tidy
|
||||||
@@ -14,6 +16,9 @@ builds:
|
|||||||
- amd64
|
- amd64
|
||||||
- arm
|
- arm
|
||||||
- arm64
|
- arm64
|
||||||
|
- loong64
|
||||||
|
- s390x
|
||||||
|
- riscv64
|
||||||
goarm:
|
goarm:
|
||||||
- "5"
|
- "5"
|
||||||
- "6"
|
- "6"
|
||||||
@@ -81,7 +86,7 @@ blobs:
|
|||||||
provider: s3
|
provider: s3
|
||||||
bucket: "{{ .Env.S3_BUCKET }}"
|
bucket: "{{ .Env.S3_BUCKET }}"
|
||||||
region: "{{ .Env.S3_REGION }}"
|
region: "{{ .Env.S3_REGION }}"
|
||||||
folder: "act_runner/{{.Version}}"
|
directory: "act_runner/{{.Version}}"
|
||||||
extra_files:
|
extra_files:
|
||||||
- glob: ./**.xz
|
- glob: ./**.xz
|
||||||
- glob: ./**.sha256
|
- glob: ./**.sha256
|
||||||
@@ -97,10 +102,10 @@ checksum:
|
|||||||
- glob: ./**.xz
|
- glob: ./**.xz
|
||||||
|
|
||||||
snapshot:
|
snapshot:
|
||||||
name_template: "{{ .Branch }}-devel"
|
version_template: "{{ .Branch }}-devel"
|
||||||
|
|
||||||
nightly:
|
nightly:
|
||||||
name_template: "nightly"
|
version_template: "nightly"
|
||||||
|
|
||||||
gitea_urls:
|
gitea_urls:
|
||||||
api: https://gitea.com/api/v1
|
api: https://gitea.com/api/v1
|
||||||
|
|||||||
58
Dockerfile
58
Dockerfile
@@ -1,16 +1,64 @@
|
|||||||
FROM golang:1.20-alpine3.18 as builder
|
### BUILDER STAGE
|
||||||
|
#
|
||||||
|
#
|
||||||
|
FROM golang:1.24-alpine AS builder
|
||||||
|
|
||||||
# Do not remove `git` here, it is required for getting runner version when executing `make build`
|
# Do not remove `git` here, it is required for getting runner version when executing `make build`
|
||||||
RUN apk add --no-cache make git
|
RUN apk add --no-cache make git
|
||||||
|
|
||||||
|
ARG GOPROXY
|
||||||
|
ENV GOPROXY=${GOPROXY:-}
|
||||||
|
|
||||||
COPY . /opt/src/act_runner
|
COPY . /opt/src/act_runner
|
||||||
WORKDIR /opt/src/act_runner
|
WORKDIR /opt/src/act_runner
|
||||||
|
|
||||||
RUN make clean && make build
|
RUN make clean && make build
|
||||||
|
|
||||||
FROM alpine:3.18
|
### DIND VARIANT
|
||||||
RUN apk add --no-cache git bash tini
|
#
|
||||||
|
#
|
||||||
|
FROM docker:28-dind AS dind
|
||||||
|
|
||||||
|
RUN apk add --no-cache s6 bash git tzdata
|
||||||
|
|
||||||
COPY --from=builder /opt/src/act_runner/act_runner /usr/local/bin/act_runner
|
COPY --from=builder /opt/src/act_runner/act_runner /usr/local/bin/act_runner
|
||||||
COPY scripts/run.sh /opt/act/run.sh
|
COPY scripts/run.sh /usr/local/bin/run.sh
|
||||||
|
COPY scripts/s6 /etc/s6
|
||||||
|
|
||||||
ENTRYPOINT ["/sbin/tini","--","/opt/act/run.sh"]
|
VOLUME /data
|
||||||
|
|
||||||
|
ENTRYPOINT ["s6-svscan","/etc/s6"]
|
||||||
|
|
||||||
|
### DIND-ROOTLESS VARIANT
|
||||||
|
#
|
||||||
|
#
|
||||||
|
FROM docker:28-dind-rootless AS dind-rootless
|
||||||
|
|
||||||
|
USER root
|
||||||
|
RUN apk add --no-cache s6 bash git tzdata
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
VOLUME /data
|
||||||
|
|
||||||
|
RUN mkdir -p /data && chown -R rootless:rootless /etc/s6 /data
|
||||||
|
|
||||||
|
ENV DOCKER_HOST=unix:///run/user/1000/docker.sock
|
||||||
|
|
||||||
|
USER rootless
|
||||||
|
ENTRYPOINT ["s6-svscan","/etc/s6"]
|
||||||
|
|
||||||
|
### BASIC VARIANT
|
||||||
|
#
|
||||||
|
#
|
||||||
|
FROM alpine AS basic
|
||||||
|
RUN apk add --no-cache tini bash git tzdata
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ENTRYPOINT ["/sbin/tini","--","run.sh"]
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
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
|
|
||||||
|
|
||||||
COPY . /opt/src/act_runner
|
|
||||||
WORKDIR /opt/src/act_runner
|
|
||||||
|
|
||||||
RUN make clean && make build
|
|
||||||
|
|
||||||
FROM docker:dind-rootless
|
|
||||||
USER root
|
|
||||||
RUN apk add --no-cache \
|
|
||||||
git bash supervisor
|
|
||||||
|
|
||||||
COPY --from=builder /opt/src/act_runner/act_runner /usr/local/bin/act_runner
|
|
||||||
COPY /scripts/supervisord.conf /etc/supervisord.conf
|
|
||||||
COPY /scripts/run.sh /opt/act/run.sh
|
|
||||||
COPY /scripts/rootless.sh /opt/act/rootless.sh
|
|
||||||
|
|
||||||
RUN mkdir /data \
|
|
||||||
&& chown rootless:rootless /data
|
|
||||||
|
|
||||||
USER rootless
|
|
||||||
ENTRYPOINT ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]
|
|
||||||
121
HOWTOSTART.md
Normal file
121
HOWTOSTART.md
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
# How to Start a GitCaddy Runner
|
||||||
|
|
||||||
|
This guide explains how to set up and start a GitCaddy Actions runner (act_runner) to execute your CI/CD workflows.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- A Linux, macOS, or Windows machine
|
||||||
|
- Network access to your GitCaddy/Gitea instance
|
||||||
|
- (Optional) Docker installed for container-based workflows
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### 1. Download the Runner
|
||||||
|
|
||||||
|
Download the latest release from the [releases page](https://git.marketally.com/gitcaddy/act_runner/releases) or build from source:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.marketally.com/gitcaddy/act_runner.git
|
||||||
|
cd act_runner
|
||||||
|
make build
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Register the Runner
|
||||||
|
|
||||||
|
Get a registration token from your GitCaddy instance:
|
||||||
|
- **Global runners**: Admin Area → Actions → Runners → Create Runner
|
||||||
|
- **Organization runners**: Organization Settings → Actions → Runners
|
||||||
|
- **Repository runners**: Repository Settings → Actions → Runners
|
||||||
|
|
||||||
|
Then register:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./act_runner register --no-interactive \
|
||||||
|
--instance https://your-gitea-instance.com \
|
||||||
|
--token YOUR_REGISTRATION_TOKEN \
|
||||||
|
--name my-runner \
|
||||||
|
--labels linux,ubuntu-latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Start the Runner
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./act_runner daemon
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration Options
|
||||||
|
|
||||||
|
### Runner Labels
|
||||||
|
|
||||||
|
Labels determine which jobs the runner can execute. Configure labels during registration or edit them in the admin UI.
|
||||||
|
|
||||||
|
Common labels:
|
||||||
|
- `linux`, `linux-latest` - Linux runners
|
||||||
|
- `windows`, `windows-latest` - Windows runners
|
||||||
|
- `macos`, `macos-latest` - macOS runners
|
||||||
|
- `ubuntu`, `ubuntu-latest` - Ubuntu-specific
|
||||||
|
- `self-hosted` - Self-hosted runners
|
||||||
|
|
||||||
|
### Running as a Service
|
||||||
|
|
||||||
|
#### Linux (systemd)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo cat > /etc/systemd/system/act_runner.service << 'SERVICE'
|
||||||
|
[Unit]
|
||||||
|
Description=GitCaddy Actions Runner
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=runner
|
||||||
|
WorkingDirectory=/opt/act_runner
|
||||||
|
ExecStart=/opt/act_runner/act_runner daemon
|
||||||
|
Restart=always
|
||||||
|
RestartSec=10
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
SERVICE
|
||||||
|
|
||||||
|
sudo systemctl enable act_runner
|
||||||
|
sudo systemctl start act_runner
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker Support
|
||||||
|
|
||||||
|
For workflows that use container actions, ensure Docker is installed and the runner user has access:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo usermod -aG docker $USER
|
||||||
|
```
|
||||||
|
|
||||||
|
## Capabilities Detection
|
||||||
|
|
||||||
|
The runner automatically detects and reports:
|
||||||
|
- Operating system and architecture
|
||||||
|
- Available shells (bash, sh, powershell)
|
||||||
|
- Installed tools (node, python, go, etc.)
|
||||||
|
- Docker availability
|
||||||
|
- Disk space and network bandwidth
|
||||||
|
|
||||||
|
These capabilities help admins understand what each runner can handle.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Runner not connecting
|
||||||
|
|
||||||
|
1. Check network connectivity to your GitCaddy instance
|
||||||
|
2. Verify the registration token is valid
|
||||||
|
3. Check firewall rules allow outbound HTTPS
|
||||||
|
|
||||||
|
### Jobs not running
|
||||||
|
|
||||||
|
1. Verify runner labels match the job's `runs-on` requirement
|
||||||
|
2. Check runner is online in the admin panel
|
||||||
|
3. Review runner logs: `journalctl -u act_runner -f`
|
||||||
|
|
||||||
|
## More Information
|
||||||
|
|
||||||
|
- [act_runner Repository](https://git.marketally.com/gitcaddy/act_runner)
|
||||||
|
- [GitCaddy Documentation](https://git.marketally.com/gitcaddy/gitea)
|
||||||
16
Makefile
16
Makefile
@@ -1,13 +1,12 @@
|
|||||||
DIST := dist
|
DIST := dist
|
||||||
EXECUTABLE := act_runner
|
EXECUTABLE := act_runner
|
||||||
GOFMT ?= gofumpt -l
|
GOFMT ?= gofumpt -l
|
||||||
DIST := dist
|
|
||||||
DIST_DIRS := $(DIST)/binaries $(DIST)/release
|
DIST_DIRS := $(DIST)/binaries $(DIST)/release
|
||||||
GO ?= go
|
GO ?= go
|
||||||
SHASUM ?= shasum -a 256
|
SHASUM ?= shasum -a 256
|
||||||
HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
|
HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
|
||||||
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
||||||
XGO_VERSION := go-1.18.x
|
XGO_VERSION := go-1.24.x
|
||||||
GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.10
|
GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.10
|
||||||
|
|
||||||
LINUX_ARCHS ?= linux/amd64,linux/arm64
|
LINUX_ARCHS ?= linux/amd64,linux/arm64
|
||||||
@@ -21,6 +20,8 @@ DOCKER_TAG ?= nightly
|
|||||||
DOCKER_REF := $(DOCKER_IMAGE):$(DOCKER_TAG)
|
DOCKER_REF := $(DOCKER_IMAGE):$(DOCKER_TAG)
|
||||||
DOCKER_ROOTLESS_REF := $(DOCKER_IMAGE):$(DOCKER_TAG)-dind-rootless
|
DOCKER_ROOTLESS_REF := $(DOCKER_IMAGE):$(DOCKER_TAG)-dind-rootless
|
||||||
|
|
||||||
|
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1
|
||||||
|
|
||||||
ifneq ($(shell uname), Darwin)
|
ifneq ($(shell uname), Darwin)
|
||||||
EXTLDFLAGS = -extldflags "-static" $(null)
|
EXTLDFLAGS = -extldflags "-static" $(null)
|
||||||
else
|
else
|
||||||
@@ -102,7 +103,15 @@ fmt-check:
|
|||||||
exit 1; \
|
exit 1; \
|
||||||
fi;
|
fi;
|
||||||
|
|
||||||
test: fmt-check
|
.PHONY: deps-tools
|
||||||
|
deps-tools: ## install tool dependencies
|
||||||
|
$(GO) install $(GOVULNCHECK_PACKAGE)
|
||||||
|
|
||||||
|
.PHONY: security-check
|
||||||
|
security-check: deps-tools
|
||||||
|
GOEXPERIMENT= $(GO) run $(GOVULNCHECK_PACKAGE) -show color ./...
|
||||||
|
|
||||||
|
test: fmt-check security-check
|
||||||
@$(GO) test -v -cover -coverprofile coverage.txt ./... && echo "\n==>\033[32m Ok\033[m\n" || exit 1
|
@$(GO) test -v -cover -coverprofile coverage.txt ./... && echo "\n==>\033[32m Ok\033[m\n" || exit 1
|
||||||
|
|
||||||
.PHONY: vet
|
.PHONY: vet
|
||||||
@@ -170,7 +179,6 @@ docker:
|
|||||||
ARG_DISABLE_CONTENT_TRUST=--disable-content-trust=false; \
|
ARG_DISABLE_CONTENT_TRUST=--disable-content-trust=false; \
|
||||||
fi; \
|
fi; \
|
||||||
docker build $${ARG_DISABLE_CONTENT_TRUST} -t $(DOCKER_REF) .
|
docker build $${ARG_DISABLE_CONTENT_TRUST} -t $(DOCKER_REF) .
|
||||||
docker build $${ARG_DISABLE_CONTENT_TRUST} -t $(DOCKER_ROOTLESS_REF) -f Dockerfile.rootless .
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(GO) clean -x -i ./...
|
$(GO) clean -x -i ./...
|
||||||
|
|||||||
228
README.md
228
README.md
@@ -1,93 +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
|
## 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 from [Releases](https://git.marketally.com/gitcaddy/act_runner/releases):
|
||||||
|
|
||||||
### Download pre-built binary
|
|
||||||
|
|
||||||
Visit [here](https://dl.gitea.com/act_runner/) and download the right version for your platform.
|
|
||||||
|
|
||||||
### Build from source
|
|
||||||
|
|
||||||
```bash
|
```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
|
make build
|
||||||
```
|
```
|
||||||
|
|
||||||
### Build a docker image
|
## Quick Start
|
||||||
|
|
||||||
|
### 1. Enable Actions in Gitea
|
||||||
|
|
||||||
|
Add to your Gitea `app.ini`:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[actions]
|
||||||
|
ENABLED = true
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Register the Runner
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make docker
|
./act_runner register \
|
||||||
|
--instance https://your-gitea-instance.com \
|
||||||
|
--token YOUR_RUNNER_TOKEN \
|
||||||
|
--name my-runner \
|
||||||
|
--labels ubuntu-latest,docker
|
||||||
```
|
```
|
||||||
|
|
||||||
## Quickstart
|
### 3. Start the Runner
|
||||||
|
|
||||||
### Register
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./act_runner register
|
|
||||||
```
|
|
||||||
|
|
||||||
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/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-20.04:docker://node:16-bullseye,ubuntu-18.04:docker://node:16-buster,linux_arm:host):
|
|
||||||
|
|
||||||
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.
|
|
||||||
```
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./act_runner daemon
|
./act_runner daemon
|
||||||
```
|
```
|
||||||
|
|
||||||
### Configuration
|
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
|
||||||
|
|
||||||
You can also configure the runner with a configuration file.
|
## Capability Detection
|
||||||
The configuration file is a YAML file, you can generate a sample configuration file with `./act_runner generate-config`.
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Create a config file or use command-line flags:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./act_runner generate-config > config.yaml
|
./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
|
```bash
|
||||||
./act_runner -c config.yaml register # register with config file
|
docker run -d \
|
||||||
./act_runner -c config.yaml daemon # run with config file
|
--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
|
||||||
```
|
```
|
||||||
|
|
||||||
### Example Deployments
|
## GitCaddy Integration
|
||||||
|
|
||||||
Check out the [examples](examples) directory for sample deployment types.
|
This runner is designed to work with the [GitCaddy Gitea fork](https://git.marketally.com/gitcaddy/gitea), which provides:
|
||||||
|
|
||||||
|
- **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.
|
||||||
|
|||||||
BIN
act_runner-darwin-amd64
Executable file
BIN
act_runner-darwin-amd64
Executable file
Binary file not shown.
BIN
act_runner-darwin-arm64
Executable file
BIN
act_runner-darwin-arm64
Executable file
Binary file not shown.
BIN
act_runner-linux-amd64
Executable file
BIN
act_runner-linux-amd64
Executable file
Binary file not shown.
BIN
act_runner-windows-amd64.exe
Executable file
BIN
act_runner-windows-amd64.exe
Executable file
Binary file not shown.
BIN
act_runner_test
Executable file
BIN
act_runner_test
Executable file
Binary file not shown.
@@ -5,16 +5,57 @@
|
|||||||
gitea:
|
gitea:
|
||||||
image: gitea/gitea
|
image: gitea/gitea
|
||||||
...
|
...
|
||||||
|
healthcheck:
|
||||||
|
# checks availability of Gitea's front-end with curl
|
||||||
|
test: ["CMD", "curl", "-f", "<instance_url>"]
|
||||||
|
interval: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 30s
|
||||||
|
timeout: 10s
|
||||||
|
environment:
|
||||||
|
# GITEA_RUNNER_REGISTRATION_TOKEN can be used to set a global runner registration token.
|
||||||
|
# The Gitea version must be v1.23 or higher.
|
||||||
|
# It's also possible to use GITEA_RUNNER_REGISTRATION_TOKEN_FILE to pass the location.
|
||||||
|
# - GITEA_RUNNER_REGISTRATION_TOKEN=<user-defined registration token>
|
||||||
|
|
||||||
runner:
|
runner:
|
||||||
image: gitea/act_runner
|
image: gitea/act_runner
|
||||||
restart: always
|
restart: always
|
||||||
depends_on:
|
depends_on:
|
||||||
- gitea
|
gitea:
|
||||||
|
# required so runner can attach to gitea, see "healthcheck"
|
||||||
|
condition: service_healthy
|
||||||
|
restart: true
|
||||||
volumes:
|
volumes:
|
||||||
- ./data/act_runner:/data
|
- ./data/act_runner:/data
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
environment:
|
environment:
|
||||||
- GITEA_INSTANCE_URL=<instance url>
|
- GITEA_INSTANCE_URL=<instance url>
|
||||||
|
# When using Docker Secrets, it's also possible to use
|
||||||
|
# GITEA_RUNNER_REGISTRATION_TOKEN_FILE to pass the location.
|
||||||
|
# The env var takes precedence.
|
||||||
|
# Needed only for the first start.
|
||||||
|
- GITEA_RUNNER_REGISTRATION_TOKEN=<registration token>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Running `act_runner` using Docker-in-Docker (DIND)
|
||||||
|
|
||||||
|
```yml
|
||||||
|
...
|
||||||
|
runner:
|
||||||
|
image: gitea/act_runner:latest-dind-rootless
|
||||||
|
restart: always
|
||||||
|
privileged: true
|
||||||
|
depends_on:
|
||||||
|
- gitea
|
||||||
|
volumes:
|
||||||
|
- ./data/act_runner:/data
|
||||||
|
environment:
|
||||||
|
- GITEA_INSTANCE_URL=<instance url>
|
||||||
|
- DOCKER_HOST=unix:///var/run/user/1000/docker.sock
|
||||||
|
# When using Docker Secrets, it's also possible to use
|
||||||
|
# GITEA_RUNNER_REGISTRATION_TOKEN_FILE to pass the location.
|
||||||
|
# The env var takes precedence.
|
||||||
|
# Needed only for the first start.
|
||||||
- GITEA_RUNNER_REGISTRATION_TOKEN=<registration token>
|
- GITEA_RUNNER_REGISTRATION_TOKEN=<registration token>
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ spec:
|
|||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
data:
|
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
|
||||||
|
# `GITEA_RUNNER_REGISTRATION_TOKEN`/`GITEA_RUNNER_REGISTRATION_TOKEN_FILE` environment variable.
|
||||||
token: << base64 encoded registration token >>
|
token: << base64 encoded registration token >>
|
||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
@@ -46,7 +49,7 @@ spec:
|
|||||||
containers:
|
containers:
|
||||||
- name: runner
|
- name: runner
|
||||||
image: gitea/act_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 -- /opt/act/run.sh"]
|
command: ["sh", "-c", "while ! nc -z localhost 2376 </dev/null; do echo 'waiting for docker daemon...'; sleep 5; done; /sbin/tini -- run.sh"]
|
||||||
env:
|
env:
|
||||||
- name: DOCKER_HOST
|
- name: DOCKER_HOST
|
||||||
value: tcp://localhost:2376
|
value: tcp://localhost:2376
|
||||||
|
|||||||
@@ -12,7 +12,10 @@ spec:
|
|||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
data:
|
data:
|
||||||
token: << runner registration token goes here >>
|
# 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
|
||||||
|
# `GITEA_RUNNER_REGISTRATION_TOKEN`/`GITEA_RUNNER_REGISTRATION_TOKEN_FILE` environment variable.
|
||||||
|
token: << base64 encoded registration token >>
|
||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
name: runner-secret
|
name: runner-secret
|
||||||
@@ -41,6 +44,8 @@ spec:
|
|||||||
- name: runner-data
|
- name: runner-data
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
claimName: act-runner-vol
|
claimName: act-runner-vol
|
||||||
|
securityContext:
|
||||||
|
fsGroup: 1000
|
||||||
containers:
|
containers:
|
||||||
- name: runner
|
- name: runner
|
||||||
image: gitea/act_runner:nightly-dind-rootless
|
image: gitea/act_runner:nightly-dind-rootless
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ As `root`:
|
|||||||
```bash
|
```bash
|
||||||
useradd -m rootless
|
useradd -m rootless
|
||||||
passwd rootless
|
passwd rootless
|
||||||
```
|
apt-get install -y uidmap # Not mentioned but needed for docker rootless.
|
||||||
|
```
|
||||||
|
|
||||||
- Install [`docker-ce`](https://docs.docker.com/engine/install/)
|
- Install [`docker-ce`](https://docs.docker.com/engine/install/)
|
||||||
- (Recommended) Disable the system-wide Docker daemon
|
- (Recommended) Disable the system-wide Docker daemon
|
||||||
@@ -21,12 +22,19 @@ As `root`:
|
|||||||
As the `rootless` user:
|
As the `rootless` user:
|
||||||
|
|
||||||
- Follow the instructions for [enabling rootless mode](https://docs.docker.com/engine/security/rootless/)
|
- Follow the instructions for [enabling rootless mode](https://docs.docker.com/engine/security/rootless/)
|
||||||
- Add the following lines to the `/home/rootless/.bashrc`:
|
- Add the following line to the `/home/rootless/.bashrc`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export XDG_RUNTIME_DIR=/home/rootless/.docker/run
|
for f in ./.bashrc.d/*.bash; do echo "Processing $f file..."; . "$f"; done
|
||||||
export PATH=/home/rootless/bin:$PATH
|
```
|
||||||
export DOCKER_HOST=unix:///run/user/1001/docker.sock
|
|
||||||
|
- Create the .bashrc.d directory `mkdir ~/.bashrc.d`
|
||||||
|
- Add the following lines to the `/home/rootless/.bashrc.d/rootless-docker.bash`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export XDG_RUNTIME_DIR=/home/rootless/.docker/run
|
||||||
|
export PATH=/home/rootless/bin:$PATH
|
||||||
|
export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock
|
||||||
```
|
```
|
||||||
|
|
||||||
- Reboot. Ensure that the Docker process is working.
|
- Reboot. Ensure that the Docker process is working.
|
||||||
|
|||||||
136
go.mod
136
go.mod
@@ -1,90 +1,114 @@
|
|||||||
module gitea.com/gitea/act_runner
|
module gitea.com/gitea/act_runner
|
||||||
|
|
||||||
go 1.20
|
go 1.24.0
|
||||||
|
|
||||||
|
toolchain go1.24.11
|
||||||
|
|
||||||
require (
|
require (
|
||||||
code.gitea.io/actions-proto-go v0.3.0
|
code.gitea.io/actions-proto-go v0.5.2
|
||||||
code.gitea.io/gitea-vet v0.2.3-0.20230113022436-2b1561217fa5
|
code.gitea.io/gitea-vet v0.2.3
|
||||||
github.com/avast/retry-go/v4 v4.3.1
|
connectrpc.com/connect v1.16.2
|
||||||
github.com/bufbuild/connect-go v1.3.1
|
github.com/avast/retry-go/v4 v4.6.0
|
||||||
github.com/docker/docker v23.0.4+incompatible
|
github.com/docker/docker v25.0.13+incompatible
|
||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
github.com/mattn/go-isatty v0.0.18
|
github.com/mattn/go-isatty v0.0.20
|
||||||
github.com/nektos/act v0.0.0
|
github.com/nektos/act v0.0.0 // will be replaced
|
||||||
github.com/sirupsen/logrus v1.9.0
|
github.com/sirupsen/logrus v1.9.3
|
||||||
github.com/spf13/cobra v1.7.0
|
github.com/spf13/cobra v1.8.1
|
||||||
github.com/stretchr/testify v1.8.2
|
github.com/stretchr/testify v1.11.1
|
||||||
golang.org/x/term v0.7.0
|
golang.org/x/term v0.36.0
|
||||||
golang.org/x/time v0.1.0
|
golang.org/x/time v0.12.0
|
||||||
google.golang.org/protobuf v1.28.1
|
google.golang.org/protobuf v1.35.2
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
gotest.tools/v3 v3.4.0
|
gotest.tools/v3 v3.5.1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require golang.org/x/sys v0.37.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
|
cyphar.com/go-pathrs v0.2.1 // indirect
|
||||||
|
dario.cat/mergo v1.0.0 // indirect
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
||||||
github.com/Masterminds/semver v1.5.0 // indirect
|
github.com/Masterminds/semver v1.5.0 // indirect
|
||||||
github.com/Microsoft/go-winio v0.5.2 // indirect
|
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||||
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect
|
github.com/ProtonMail/go-crypto v1.1.6 // indirect
|
||||||
github.com/acomagu/bufpipe v1.0.4 // indirect
|
github.com/cloudflare/circl v1.6.1 // indirect
|
||||||
github.com/cloudflare/circl v1.1.0 // indirect
|
github.com/containerd/containerd v1.7.29 // indirect
|
||||||
github.com/containerd/containerd v1.6.20 // indirect
|
github.com/containerd/log v0.1.0 // indirect
|
||||||
github.com/creack/pty v1.1.18 // indirect
|
github.com/creack/pty v1.1.21 // indirect
|
||||||
|
github.com/cyphar/filepath-securejoin v0.6.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/docker/cli v23.0.4+incompatible // indirect
|
github.com/distribution/reference v0.6.0 // indirect
|
||||||
github.com/docker/distribution v2.8.1+incompatible // indirect
|
github.com/docker/cli v25.0.3+incompatible // indirect
|
||||||
github.com/docker/docker-credential-helpers v0.7.0 // indirect
|
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||||
github.com/docker/go-connections v0.4.0 // indirect
|
github.com/docker/docker-credential-helpers v0.8.2 // indirect
|
||||||
|
github.com/docker/go-connections v0.5.0 // indirect
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
github.com/emirpasic/gods v1.18.1 // indirect
|
github.com/emirpasic/gods v1.18.1 // indirect
|
||||||
github.com/fatih/color v1.15.0 // indirect
|
github.com/fatih/color v1.17.0 // indirect
|
||||||
github.com/go-git/gcfg v1.5.0 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/go-git/go-billy/v5 v5.4.1 // indirect
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||||
github.com/go-git/go-git/v5 v5.6.2-0.20230411180853-ce62f3e9ff86 // indirect
|
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||||
|
github.com/go-git/go-git/v5 v5.12.0 // indirect
|
||||||
|
github.com/go-logr/logr v1.4.2 // indirect
|
||||||
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
|
github.com/gobwas/glob v0.2.3 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||||
|
github.com/google/go-cmp v0.7.0 // indirect
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||||
github.com/imdario/mergo v0.3.15 // indirect
|
github.com/imdario/mergo v0.3.16 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||||
github.com/julienschmidt/httprouter v1.3.0 // indirect
|
github.com/julienschmidt/httprouter v1.3.0 // indirect
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||||
github.com/klauspost/compress v1.15.12 // indirect
|
github.com/klauspost/compress v1.17.9 // indirect
|
||||||
github.com/kr/pretty v0.3.0 // indirect
|
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/moby/buildkit v0.11.6 // indirect
|
github.com/moby/buildkit v0.12.5 // indirect
|
||||||
github.com/moby/patternmatcher v0.5.0 // indirect
|
github.com/moby/patternmatcher v0.6.0 // indirect
|
||||||
github.com/moby/sys/sequential v0.5.0 // indirect
|
github.com/moby/sys/sequential v0.5.0 // indirect
|
||||||
|
github.com/moby/sys/user v0.3.0 // indirect
|
||||||
|
github.com/moby/sys/userns v0.1.0 // indirect
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b // indirect
|
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||||
github.com/opencontainers/runc v1.1.5 // indirect
|
github.com/opencontainers/selinux v1.13.0 // indirect
|
||||||
github.com/opencontainers/selinux v1.11.0 // indirect
|
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
||||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/rhysd/actionlint v1.6.24 // indirect
|
github.com/rhysd/actionlint v1.7.1 // indirect
|
||||||
github.com/rivo/uniseg v0.4.4 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/robfig/cron v1.2.0 // indirect
|
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||||
github.com/sergi/go-diff v1.2.0 // indirect
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||||
github.com/skeema/knownhosts v1.1.0 // indirect
|
github.com/skeema/knownhosts v1.3.1 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/stretchr/objx v0.5.0 // indirect
|
github.com/stretchr/objx v0.5.2 // indirect
|
||||||
github.com/timshannon/bolthold v0.0.0-20210913165410-232392fc8a6a // indirect
|
github.com/timshannon/bolthold v0.0.0-20240314194003-30aac6950928 // indirect
|
||||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||||
go.etcd.io/bbolt v1.3.7 // indirect
|
go.etcd.io/bbolt v1.3.10 // indirect
|
||||||
golang.org/x/crypto v0.6.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
|
||||||
golang.org/x/net v0.9.0 // indirect
|
go.opentelemetry.io/otel v1.28.0 // indirect
|
||||||
golang.org/x/sync v0.1.0 // indirect
|
go.opentelemetry.io/otel/metric v1.28.0 // indirect
|
||||||
golang.org/x/sys v0.7.0 // indirect
|
go.opentelemetry.io/otel/trace v1.28.0 // indirect
|
||||||
golang.org/x/tools v0.8.0 // indirect
|
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/tools v0.23.0 // indirect
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/nektos/act => gitea.com/gitea/act v0.245.2-0.20230606002131-6ce5c93cc815
|
replace github.com/nektos/act => gitea.com/gitea/act v0.261.7-0.20251202193638-5417d3ac6742
|
||||||
|
|
||||||
|
replace github.com/go-git/go-git/v5 => github.com/go-git/go-git/v5 v5.16.2
|
||||||
|
|
||||||
|
// Remove after
|
||||||
|
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.7
|
||||||
|
|||||||
391
go.sum
391
go.sum
@@ -1,96 +1,107 @@
|
|||||||
code.gitea.io/actions-proto-go v0.3.0 h1:9Tvg8+TaaCXPKi6EnWl9vVgs2VZsj1Cs5afnsHa4AmM=
|
code.gitea.io/gitea-vet v0.2.3 h1:gdFmm6WOTM65rE8FUBTRzeQZYzXePKSSB1+r574hWwI=
|
||||||
code.gitea.io/actions-proto-go v0.3.0/go.mod h1:00ys5QDo1iHN1tHNvvddAcy2W/g+425hQya1cCSvq9A=
|
code.gitea.io/gitea-vet v0.2.3/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
|
||||||
code.gitea.io/gitea-vet v0.2.3-0.20230113022436-2b1561217fa5 h1:daBEK2GQeqGikJESctP5Cu1i33z5ztAD4kyQWiw185M=
|
connectrpc.com/connect v1.16.2 h1:ybd6y+ls7GOlb7Bh5C8+ghA6SvCBajHwxssO2CGFjqE=
|
||||||
code.gitea.io/gitea-vet v0.2.3-0.20230113022436-2b1561217fa5/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
|
connectrpc.com/connect v1.16.2/go.mod h1:n2kgwskMHXC+lVqb18wngEpF95ldBHXjZYJussz5FRc=
|
||||||
gitea.com/gitea/act v0.245.2-0.20230606002131-6ce5c93cc815 h1:u4rHwJLJnH6mej1BjEc4iubwknVeJmRVq9xQP9cAMeQ=
|
cyphar.com/go-pathrs v0.2.1 h1:9nx1vOgwVvX1mNBWDu93+vaceedpbsDqo+XuBGL40b8=
|
||||||
gitea.com/gitea/act v0.245.2-0.20230606002131-6ce5c93cc815/go.mod h1:1ffiGQZAZCLuk9QEBDdbRuQj1GL4uAQk6GNNtcEnPmI=
|
cyphar.com/go-pathrs v0.2.1/go.mod h1:y8f1EMG7r+hCuFf/rXsKqMJrJAUoADZGNh5/vZPKcGc=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
|
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
git.marketally.com/gitcaddy/actions-proto-go v0.5.7 h1:RUbafr3Vkw2l4WfSwa+oF+Ihakbm05W0FlAmXuQrDJc=
|
||||||
|
git.marketally.com/gitcaddy/actions-proto-go v0.5.7/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=
|
||||||
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||||
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
|
|
||||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||||
github.com/Microsoft/hcsshim v0.9.8 h1:lf7xxK2+Ikbj9sVf2QZsouGjRjEp2STj1yDHgoVtU5k=
|
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||||
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA=
|
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||||
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g=
|
github.com/Microsoft/hcsshim v0.11.7 h1:vl/nj3Bar/CvJSYo7gIQPyRWc9f3c6IeSNavBTSZNZQ=
|
||||||
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
|
github.com/Microsoft/hcsshim v0.11.7/go.mod h1:MV8xMfmECjl5HdO7U/3/hFVnkmSBjAjmA09d4bExKcU=
|
||||||
github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
|
github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw=
|
||||||
|
github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||||
github.com/avast/retry-go/v4 v4.3.1 h1:Mtg11F9PdAIMkMiio2RKcYauoVHjl2aB3zQJJlzD4cE=
|
github.com/avast/retry-go/v4 v4.6.0 h1:K9xNA+KeB8HHc2aWFuLb25Offp+0iVRXEvFx8IinRJA=
|
||||||
github.com/avast/retry-go/v4 v4.3.1/go.mod h1:rg6XFaiuFYII0Xu3RDbZQkxCofFwruZKW8oEF1jpWiU=
|
github.com/avast/retry-go/v4 v4.6.0/go.mod h1:gvWlPhBVsvBbLkVGDg/KwvBv0bEkCOLRRSHKIr2PyOE=
|
||||||
github.com/bufbuild/connect-go v1.3.1 h1:doJP6Q8Ypg6haUT2IAZJPWHUN9rAUp+F9MfK7yhu1zs=
|
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||||
github.com/bufbuild/connect-go v1.3.1/go.mod h1:9iNvh/NOsfhNBUH5CtvXeVUskQO1xsrEviH7ZArwZ3I=
|
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
||||||
github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
|
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||||
github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA=
|
github.com/containerd/containerd v1.7.29 h1:90fWABQsaN9mJhGkoVnuzEY+o1XDPbg9BTC9QTAHnuE=
|
||||||
github.com/cloudflare/circl v1.1.0 h1:bZgT/A+cikZnKIwn7xL2OBj012Bmvho/o6RpRvv3GKY=
|
github.com/containerd/containerd v1.7.29/go.mod h1:azUkWcOvHrWvaiUjSQH0fjzuHIwSPg1WL5PshGP4Szs=
|
||||||
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
|
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||||
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
|
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||||
github.com/containerd/containerd v1.6.20 h1:+itjwpdqXpzHB/QAiWc/BZCjjVfcNgw69w/oIeF4Oy0=
|
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
github.com/containerd/containerd v1.6.20/go.mod h1:apei1/i5Ux2FzrK6+DM/suEsGuK/MeVOfy8tR2q7Wnw=
|
github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
|
||||||
github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg=
|
github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/cyphar/filepath-securejoin v0.6.0 h1:BtGB77njd6SVO6VztOHfPxKitJvd/VPT+OFBFMOi1Is=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cyphar/filepath-securejoin v0.6.0/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
|
||||||
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
|
||||||
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
|
||||||
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/docker/cli v23.0.4+incompatible h1:xClB7PsiATttDHj8ce5qvJcikiApNy7teRR1XkoBZGs=
|
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
|
||||||
github.com/docker/cli v23.0.4+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||||
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
|
github.com/docker/cli v25.0.3+incompatible h1:KLeNs7zws74oFuVhgZQ5ONGZiXUUdgsdy6/EsX/6284=
|
||||||
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
github.com/docker/cli v25.0.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||||
github.com/docker/docker v23.0.4+incompatible h1:Kd3Bh9V/rO+XpTP/BLqM+gx8z7+Yb0AA2Ibj+nNo4ek=
|
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||||
github.com/docker/docker v23.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
|
github.com/docker/docker v25.0.13+incompatible h1:YeBrkUd3q0ZoRDNoEzuopwCLU+uD8GZahDHwBdsTnkU=
|
||||||
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
|
github.com/docker/docker v25.0.13+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
|
||||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
||||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||||
|
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
|
github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
|
||||||
|
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
|
||||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
|
||||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
|
||||||
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
|
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
||||||
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
|
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
||||||
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||||
github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||||
github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4=
|
github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
|
||||||
github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg=
|
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
|
||||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8=
|
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo=
|
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||||
github.com/go-git/go-git/v5 v5.6.2-0.20230411180853-ce62f3e9ff86 h1:vbnwVQwGOr4xwrtcZ1lrhWHPMIgWkhNv+2+smiA2HHk=
|
github.com/go-git/go-git/v5 v5.16.2 h1:fT6ZIOjE5iEnkzKyxTHK1W4HGAsPhqEqiSAssSO77hM=
|
||||||
github.com/go-git/go-git/v5 v5.6.2-0.20230411180853-ce62f3e9ff86/go.mod h1:Q3/DKr39xeJ3oEAVC8Q1+BlJK3OMsOQsksNb3s+9M1A=
|
github.com/go-git/go-git/v5 v5.16.2/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||||
|
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
|
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||||
|
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||||
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
|
||||||
github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
|
||||||
github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
|
||||||
|
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
|
||||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
|
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
|
||||||
@@ -101,85 +112,78 @@ github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4
|
|||||||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM=
|
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||||
github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
|
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
|
|
||||||
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||||
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/mmcloughlin/avo v0.5.0/go.mod h1:ChHFdoV7ql95Wi7vuq2YT1bwCJqiWdZrQ1im3VujLYM=
|
github.com/moby/buildkit v0.12.5 h1:RNHH1l3HDhYyZafr5EgstEu8aGNCwyfvMtrQDtjH9T0=
|
||||||
github.com/moby/buildkit v0.11.6 h1:VYNdoKk5TVxN7k4RvZgdeM4GOyRvIi4Z8MXOY7xvyUs=
|
github.com/moby/buildkit v0.12.5/go.mod h1:YGwjA2loqyiYfZeEo8FtI7z4x5XponAaIWsWcSjWwso=
|
||||||
github.com/moby/buildkit v0.11.6/go.mod h1:GCqKfHhz+pddzfgaR7WmHVEE3nKKZMMDPpK8mh3ZLv4=
|
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
||||||
github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo=
|
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||||
github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
|
||||||
github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
|
|
||||||
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
|
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
|
||||||
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
|
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
|
||||||
|
github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
|
||||||
|
github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
|
||||||
|
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
|
||||||
|
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
|
||||||
github.com/moby/term v0.0.0-20200312100748-672ec06f55cd h1:aY7OQNf2XqY/JQ6qREWamhI/81os/agb2BAGpcx5yWI=
|
github.com/moby/term v0.0.0-20200312100748-672ec06f55cd h1:aY7OQNf2XqY/JQ6qREWamhI/81os/agb2BAGpcx5yWI=
|
||||||
|
github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
|
||||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||||
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
|
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||||
|
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b h1:YWuSjZCQAPM8UUBLkYUk1e+rZcvWHJmFb6i6rM44Xs8=
|
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||||
github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ=
|
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
||||||
github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/GDEs=
|
github.com/opencontainers/selinux v1.13.0 h1:Zza88GWezyT7RLql12URvoxsbLfjFx988+LGaWfbL84=
|
||||||
github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg=
|
github.com/opencontainers/selinux v1.13.0/go.mod h1:XxWTed+A/s5NNq4GmYScVy+9jzXhGBVEOAyucdRUY8s=
|
||||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
|
||||||
github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
|
github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
|
||||||
github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU=
|
|
||||||
github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
|
|
||||||
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
|
||||||
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
|
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/rhysd/actionlint v1.6.24 h1:5f61cF5ssP2pzG0jws5bEsfZBNhbBcO9nl7vTzVKjzs=
|
github.com/rhysd/actionlint v1.7.1 h1:WJaDzyT1StBWVKGSsZPYnbV0HF9Y9/vD6KFdZQL42qE=
|
||||||
github.com/rhysd/actionlint v1.6.24/go.mod h1:gQmz9r2wlcpLy+VdbzK0GINJQnAK5/sNH3BpwW4Mt5I=
|
github.com/rhysd/actionlint v1.7.1/go.mod h1:lNjNNlZY0BdBl8l837Z9ZiBpu8v+5lzfoJQFdSk4xss=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||||
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
|
||||||
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
|
||||||
github.com/skeema/knownhosts v1.1.0 h1:Wvr9V0MxhjRbl3f9nMnKnFfiWTJmtECJ9Njkea3ysW0=
|
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
|
||||||
github.com/skeema/knownhosts v1.1.0/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXijpFO6roag=
|
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||||
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||||
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||||
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
@@ -187,18 +191,15 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
github.com/timshannon/bolthold v0.0.0-20240314194003-30aac6950928 h1:zjNCuOOhh1TKRU0Ru3PPPJt80z7eReswCao91gBLk00=
|
||||||
github.com/timshannon/bolthold v0.0.0-20210913165410-232392fc8a6a h1:oIi7H/bwFUYKYhzKbHc+3MvHRWqhQwXVB4LweLMiVy0=
|
github.com/timshannon/bolthold v0.0.0-20240314194003-30aac6950928/go.mod h1:PCFYfAEfKT+Nd6zWvUpsXduMR1bXFLf0uGSlEF05MCI=
|
||||||
github.com/timshannon/bolthold v0.0.0-20210913165410-232392fc8a6a/go.mod h1:iSvujNDmpZ6eQX+bg/0X3lF7LEmZ8N77g2a/J/+Zt2U=
|
|
||||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
|
||||||
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
|
||||||
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
|
|
||||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
|
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||||
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||||
@@ -206,127 +207,107 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ
|
|||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
||||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0=
|
||||||
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
|
go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ=
|
||||||
go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
go.etcd.io/gofail v0.1.0/go.mod h1:VZBCXYGZhHAinaBiiqYvuDynvahNsAyLFwB3kEHKz1M=
|
||||||
golang.org/x/arch v0.1.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
|
||||||
|
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
|
||||||
|
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
|
||||||
|
go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
|
||||||
|
go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
|
||||||
|
go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
|
||||||
|
go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
|
||||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||||
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
|
||||||
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
|
||||||
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
|
||||||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
||||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
|
||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
|
||||||
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
|
|
||||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||||
|
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
||||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
|
||||||
golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
|
|
||||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||||
golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
|
|
||||||
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
|
||||||
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
|
||||||
golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y=
|
|
||||||
golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3 h1:1hfbdAfFbkmpg41000wDVqr7jUpK/Yo+LPnIxxGzmkg=
|
||||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f h1:2yNACc1O40tTnrsbk9Cv6oxiW8pxI/pXj0wRtdlYmgY=
|
||||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f/go.mod h1:Uy9bTZJqmfrw2rIBxgGLnamc78euZULUBrLZ9XTITKI=
|
||||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
|
||||||
|
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
|
||||||
|
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
|
||||||
|
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
|
||||||
|
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
|
||||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
|
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
||||||
gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g=
|
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
|
||||||
|
|||||||
69
internal/app/cmd/cache-server.go
Normal file
69
internal/app/cmd/cache-server.go
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
|
||||||
|
"gitea.com/gitea/act_runner/internal/pkg/config"
|
||||||
|
|
||||||
|
"github.com/nektos/act/pkg/artifactcache"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
type cacheServerArgs struct {
|
||||||
|
Dir string
|
||||||
|
Host string
|
||||||
|
Port uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
func runCacheServer(ctx context.Context, configFile *string, cacheArgs *cacheServerArgs) func(cmd *cobra.Command, args []string) error {
|
||||||
|
return func(cmd *cobra.Command, args []string) error {
|
||||||
|
cfg, err := config.LoadDefault(*configFile)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid configuration: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
initLogging(cfg)
|
||||||
|
|
||||||
|
var (
|
||||||
|
dir = cfg.Cache.Dir
|
||||||
|
host = cfg.Cache.Host
|
||||||
|
port = cfg.Cache.Port
|
||||||
|
)
|
||||||
|
|
||||||
|
// cacheArgs has higher priority
|
||||||
|
if cacheArgs.Dir != "" {
|
||||||
|
dir = cacheArgs.Dir
|
||||||
|
}
|
||||||
|
if cacheArgs.Host != "" {
|
||||||
|
host = cacheArgs.Host
|
||||||
|
}
|
||||||
|
if cacheArgs.Port != 0 {
|
||||||
|
port = cacheArgs.Port
|
||||||
|
}
|
||||||
|
|
||||||
|
cacheHandler, err := artifactcache.StartHandler(
|
||||||
|
dir,
|
||||||
|
host,
|
||||||
|
port,
|
||||||
|
log.StandardLogger().WithField("module", "cache_request"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("cache server is listening on %v", cacheHandler.ExternalURL())
|
||||||
|
|
||||||
|
c := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(c, os.Interrupt)
|
||||||
|
<-c
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,15 +39,18 @@ func Execute(ctx context.Context) {
|
|||||||
registerCmd.Flags().StringVar(®Args.Token, "token", "", "Runner token")
|
registerCmd.Flags().StringVar(®Args.Token, "token", "", "Runner token")
|
||||||
registerCmd.Flags().StringVar(®Args.RunnerName, "name", "", "Runner name")
|
registerCmd.Flags().StringVar(®Args.RunnerName, "name", "", "Runner name")
|
||||||
registerCmd.Flags().StringVar(®Args.Labels, "labels", "", "Runner tags, comma separated")
|
registerCmd.Flags().StringVar(®Args.Labels, "labels", "", "Runner tags, comma separated")
|
||||||
|
registerCmd.Flags().BoolVar(®Args.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)
|
rootCmd.AddCommand(registerCmd)
|
||||||
|
|
||||||
// ./act_runner daemon
|
// ./act_runner daemon
|
||||||
|
var daemArgs daemonArgs
|
||||||
daemonCmd := &cobra.Command{
|
daemonCmd := &cobra.Command{
|
||||||
Use: "daemon",
|
Use: "daemon",
|
||||||
Short: "Run as a runner daemon",
|
Short: "Run as a runner daemon",
|
||||||
Args: cobra.MaximumNArgs(1),
|
Args: cobra.MaximumNArgs(0),
|
||||||
RunE: runDaemon(ctx, &configFile),
|
RunE: runDaemon(ctx, &daemArgs, &configFile),
|
||||||
}
|
}
|
||||||
|
daemonCmd.Flags().BoolVar(&daemArgs.Once, "once", false, "Run one job then exit")
|
||||||
rootCmd.AddCommand(daemonCmd)
|
rootCmd.AddCommand(daemonCmd)
|
||||||
|
|
||||||
// ./act_runner exec
|
// ./act_runner exec
|
||||||
@@ -63,6 +66,19 @@ func Execute(ctx context.Context) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// ./act_runner cache-server
|
||||||
|
var cacheArgs cacheServerArgs
|
||||||
|
cacheCmd := &cobra.Command{
|
||||||
|
Use: "cache-server",
|
||||||
|
Short: "Start a cache server for the cache action",
|
||||||
|
Args: cobra.MaximumNArgs(0),
|
||||||
|
RunE: runCacheServer(ctx, &configFile, &cacheArgs),
|
||||||
|
}
|
||||||
|
cacheCmd.Flags().StringVarP(&cacheArgs.Dir, "dir", "d", "", "Cache directory")
|
||||||
|
cacheCmd.Flags().StringVarP(&cacheArgs.Host, "host", "s", "", "Host of the cache server")
|
||||||
|
cacheCmd.Flags().Uint16VarP(&cacheArgs.Port, "port", "p", 0, "Port of the cache server")
|
||||||
|
rootCmd.AddCommand(cacheCmd)
|
||||||
|
|
||||||
// hide completion command
|
// hide completion command
|
||||||
rootCmd.CompletionOptions.HiddenDefaultCmd = true
|
rootCmd.CompletionOptions.HiddenDefaultCmd = true
|
||||||
|
|
||||||
|
|||||||
@@ -5,14 +5,18 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/bufbuild/connect-go"
|
"connectrpc.com/connect"
|
||||||
"github.com/mattn/go-isatty"
|
"github.com/mattn/go-isatty"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -26,7 +30,21 @@ import (
|
|||||||
"gitea.com/gitea/act_runner/internal/pkg/ver"
|
"gitea.com/gitea/act_runner/internal/pkg/ver"
|
||||||
)
|
)
|
||||||
|
|
||||||
func runDaemon(ctx context.Context, configFile *string) func(cmd *cobra.Command, args []string) error {
|
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
|
||||||
|
// BandwidthTestInterval is how often to run bandwidth tests (hourly)
|
||||||
|
BandwidthTestInterval = 1 * time.Hour
|
||||||
|
)
|
||||||
|
|
||||||
|
// Global bandwidth manager - accessible for triggering manual tests
|
||||||
|
var bandwidthManager *envcheck.BandwidthManager
|
||||||
|
|
||||||
|
func runDaemon(ctx context.Context, daemArgs *daemonArgs, configFile *string) func(cmd *cobra.Command, args []string) error {
|
||||||
return func(cmd *cobra.Command, args []string) error {
|
return func(cmd *cobra.Command, args []string) error {
|
||||||
cfg, err := config.LoadDefault(*configFile)
|
cfg, err := config.LoadDefault(*configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -62,10 +80,64 @@ func runDaemon(ctx context.Context, configFile *string) func(cmd *cobra.Command,
|
|||||||
log.Warn("no labels configured, runner may not be able to pick up jobs")
|
log.Warn("no labels configured, runner may not be able to pick up jobs")
|
||||||
}
|
}
|
||||||
|
|
||||||
if ls.RequireDocker() {
|
if ls.RequireDocker() || cfg.Container.RequireDocker {
|
||||||
if err := envcheck.CheckIfDockerRunning(ctx); err != nil {
|
// Wait for dockerd be ready
|
||||||
|
if timeout := cfg.Container.DockerTimeout; timeout > 0 {
|
||||||
|
tctx, cancel := context.WithTimeout(ctx, timeout)
|
||||||
|
defer cancel()
|
||||||
|
keepRunning := true
|
||||||
|
for keepRunning {
|
||||||
|
dockerSocketPath, err := getDockerSocketPath(cfg.Container.DockerHost)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to get socket path: %s", err.Error())
|
||||||
|
} else if err = envcheck.CheckIfDockerRunning(tctx, dockerSocketPath); errors.Is(err, context.Canceled) {
|
||||||
|
log.Infof("Docker wait timeout of %s expired", timeout.String())
|
||||||
|
break
|
||||||
|
} else if err != nil {
|
||||||
|
log.Errorf("Docker connection failed: %s", err.Error())
|
||||||
|
} else {
|
||||||
|
log.Infof("Docker is ready")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
case <-tctx.Done():
|
||||||
|
log.Infof("Docker wait timeout of %s expired", timeout.String())
|
||||||
|
keepRunning = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Require dockerd be ready
|
||||||
|
dockerSocketPath, err := getDockerSocketPath(cfg.Container.DockerHost)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := envcheck.CheckIfDockerRunning(ctx, dockerSocketPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// if dockerSocketPath passes the check, override DOCKER_HOST with dockerSocketPath
|
||||||
|
os.Setenv("DOCKER_HOST", dockerSocketPath)
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
// check the scheme, if the scheme is not npipe or unix
|
||||||
|
// set cfg.Container.DockerHost to "-" because it can't be mounted to the job container
|
||||||
|
if protoIndex := strings.Index(cfg.Container.DockerHost, "://"); protoIndex != -1 {
|
||||||
|
scheme := cfg.Container.DockerHost[:protoIndex]
|
||||||
|
if !strings.EqualFold(scheme, "npipe") && !strings.EqualFold(scheme, "unix") {
|
||||||
|
cfg.Container.DockerHost = "-"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !slices.Equal(reg.Labels, ls.ToStrings()) {
|
||||||
|
reg.Labels = ls.ToStrings()
|
||||||
|
if err := config.SaveRegistration(cfg.Runner.File, reg); err != nil {
|
||||||
|
return fmt.Errorf("failed to save runner config: %w", err)
|
||||||
|
}
|
||||||
|
log.Infof("labels updated to: %v", reg.Labels)
|
||||||
}
|
}
|
||||||
|
|
||||||
cli := client.New(
|
cli := client.New(
|
||||||
@@ -77,66 +149,232 @@ func runDaemon(ctx context.Context, configFile *string) func(cmd *cobra.Command,
|
|||||||
)
|
)
|
||||||
|
|
||||||
runner := run.NewRunner(cfg, reg, cli)
|
runner := run.NewRunner(cfg, reg, cli)
|
||||||
|
|
||||||
|
// Detect runner capabilities for AI-friendly workflow generation
|
||||||
|
dockerHost := cfg.Container.DockerHost
|
||||||
|
if dockerHost == "" {
|
||||||
|
if dh, err := getDockerSocketPath(""); err == nil {
|
||||||
|
dockerHost = dh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize bandwidth manager with the Gitea server address
|
||||||
|
bandwidthManager = envcheck.NewBandwidthManager(reg.Address, BandwidthTestInterval)
|
||||||
|
bandwidthManager.Start(ctx)
|
||||||
|
log.Infof("bandwidth manager started, testing against: %s", reg.Address)
|
||||||
|
|
||||||
|
capabilities := envcheck.DetectCapabilities(ctx, dockerHost, cfg.Container.WorkdirParent)
|
||||||
|
// Include initial bandwidth result if available
|
||||||
|
capabilities.Bandwidth = bandwidthManager.GetLastResult()
|
||||||
|
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
|
// declare the labels of the runner before fetching tasks
|
||||||
resp, err := runner.Declare(ctx, ls.Names())
|
resp, err := runner.Declare(ctx, ls.Names(), capabilitiesJson)
|
||||||
if err != nil && connect.CodeOf(err) == connect.CodeUnimplemented {
|
if err != nil && connect.CodeOf(err) == connect.CodeUnimplemented {
|
||||||
// Gitea instance is older version. skip declare step.
|
log.Errorf("Your Gitea version is too old to support runner declare, please upgrade to v1.21 or later")
|
||||||
log.Warn("Because the Gitea instance is an old version, skip declare labels and version.")
|
return err
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
log.WithError(err).Error("fail to invoke Declare")
|
log.WithError(err).Error("fail to invoke Declare")
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
log.Infof("runner: %s, with version: %s, with labels: %v, declare successfully",
|
log.Infof("runner: %s, with version: %s, with labels: %v, declare successfully",
|
||||||
resp.Msg.Runner.Name, resp.Msg.Runner.Version, resp.Msg.Runner.Labels)
|
resp.Msg.Runner.Name, resp.Msg.Runner.Version, resp.Msg.Runner.Labels)
|
||||||
// if declare successfully, override the labels in the.runner file with valid labels in the config file (if specified)
|
|
||||||
reg.Labels = ls.ToStrings()
|
|
||||||
if err := config.SaveRegistration(cfg.Runner.File, reg); err != nil {
|
|
||||||
return fmt.Errorf("failed to save runner config: %w", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
poller := poll.New(cfg, cli, runner)
|
// Start periodic capabilities update goroutine
|
||||||
|
go periodicCapabilitiesUpdate(ctx, runner, ls.Names(), dockerHost, cfg.Container.WorkdirParent)
|
||||||
|
// Start periodic stale job cache cleanup (every hour, remove caches older than 2 hours)
|
||||||
|
go func() {
|
||||||
|
ticker := time.NewTicker(1 * time.Hour)
|
||||||
|
defer ticker.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case <-ticker.C:
|
||||||
|
runner.CleanStaleJobCaches(2 * time.Hour)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
poller.Poll(ctx)
|
poller := poll.New(cfg, cli, runner)
|
||||||
|
poller.SetBandwidthManager(bandwidthManager)
|
||||||
|
|
||||||
|
if daemArgs.Once || reg.Ephemeral {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
defer close(done)
|
||||||
|
poller.PollOnce()
|
||||||
|
}()
|
||||||
|
|
||||||
|
// shutdown when we complete a job or cancel is requested
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
case <-done:
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
go poller.Poll()
|
||||||
|
|
||||||
|
<-ctx.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("runner: %s shutdown initiated, waiting %s for running jobs to complete before shutting down", resp.Msg.Runner.Name, cfg.Runner.ShutdownTimeout)
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), cfg.Runner.ShutdownTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
err = poller.Shutdown(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("runner: %s cancelled in progress jobs during shutdown", resp.Msg.Runner.Name)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// initLogging setup the global logrus logger.
|
// checkDiskSpaceWarnings logs warnings if disk space is low
|
||||||
func initLogging(cfg *config.Config) {
|
func checkDiskSpaceWarnings(capabilities *envcheck.RunnerCapabilities) {
|
||||||
isTerm := isatty.IsTerminal(os.Stdout.Fd())
|
if capabilities.Disk == nil {
|
||||||
format := &log.TextFormatter{
|
return
|
||||||
DisableColors: !isTerm,
|
|
||||||
FullTimestamp: true,
|
|
||||||
}
|
}
|
||||||
log.SetFormatter(format)
|
|
||||||
|
|
||||||
if l := cfg.Log.Level; l != "" {
|
usedPercent := capabilities.Disk.UsedPercent
|
||||||
level, err := log.ParseLevel(l)
|
freeGB := float64(capabilities.Disk.Free) / (1024 * 1024 * 1024)
|
||||||
if err != nil {
|
|
||||||
log.WithError(err).
|
|
||||||
Errorf("invalid log level: %q", l)
|
|
||||||
}
|
|
||||||
|
|
||||||
// debug level
|
if usedPercent >= DiskSpaceCriticalThreshold {
|
||||||
if level == log.DebugLevel {
|
log.Errorf("CRITICAL: Disk space critically low! %.1f%% used, only %.2f GB free. Runner may fail to execute jobs!", usedPercent, freeGB)
|
||||||
log.SetReportCaller(true)
|
} else if usedPercent >= DiskSpaceWarningThreshold {
|
||||||
format.CallerPrettyfier = func(f *runtime.Frame) (string, string) {
|
log.Warnf("WARNING: Disk space running low. %.1f%% used, %.2f GB free. Consider cleaning up disk space.", usedPercent, freeGB)
|
||||||
// get function name
|
}
|
||||||
s := strings.Split(f.Function, ".")
|
}
|
||||||
funcname := "[" + s[len(s)-1] + "]"
|
|
||||||
// get file name and line number
|
// periodicCapabilitiesUpdate periodically updates capabilities including disk space and bandwidth
|
||||||
_, filename := path.Split(f.File)
|
func periodicCapabilitiesUpdate(ctx context.Context, runner *run.Runner, labelNames []string, dockerHost string, workingDir string) {
|
||||||
filename = "[" + filename + ":" + strconv.Itoa(f.Line) + "]"
|
ticker := time.NewTicker(CapabilitiesUpdateInterval)
|
||||||
return funcname, filename
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
log.Debug("stopping periodic capabilities update")
|
||||||
|
if bandwidthManager != nil {
|
||||||
|
bandwidthManager.Stop()
|
||||||
}
|
}
|
||||||
log.SetFormatter(format)
|
return
|
||||||
}
|
case <-ticker.C:
|
||||||
|
// Detect updated capabilities (disk space changes over time)
|
||||||
|
capabilities := envcheck.DetectCapabilities(ctx, dockerHost, workingDir)
|
||||||
|
|
||||||
if log.GetLevel() != level {
|
// Include latest bandwidth result
|
||||||
log.Infof("log level changed to %v", level)
|
if bandwidthManager != nil {
|
||||||
log.SetLevel(level)
|
capabilities.Bandwidth = bandwidthManager.GetLastResult()
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
bandwidthInfo := ""
|
||||||
|
if capabilities.Bandwidth != nil {
|
||||||
|
bandwidthInfo = fmt.Sprintf(", bandwidth: %.1f Mbps", capabilities.Bandwidth.DownloadMbps)
|
||||||
|
}
|
||||||
|
log.Debugf("capabilities updated: disk %.1f%% used, %.2f GB free%s",
|
||||||
|
capabilities.Disk.UsedPercent,
|
||||||
|
float64(capabilities.Disk.Free)/(1024*1024*1024),
|
||||||
|
bandwidthInfo)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type daemonArgs struct {
|
||||||
|
Once bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// initLogging setup the global logrus logger.
|
||||||
|
func initLogging(cfg *config.Config) {
|
||||||
|
callPrettyfier := func(f *runtime.Frame) (string, string) {
|
||||||
|
// get function name
|
||||||
|
s := strings.Split(f.Function, ".")
|
||||||
|
funcname := "[" + s[len(s)-1] + "]"
|
||||||
|
// get file name and line number
|
||||||
|
_, filename := path.Split(f.File)
|
||||||
|
filename = "[" + filename + ":" + strconv.Itoa(f.Line) + "]"
|
||||||
|
return funcname, filename
|
||||||
|
}
|
||||||
|
|
||||||
|
isTerm := isatty.IsTerminal(os.Stdout.Fd())
|
||||||
|
format := &log.TextFormatter{
|
||||||
|
DisableColors: !isTerm,
|
||||||
|
FullTimestamp: true,
|
||||||
|
CallerPrettyfier: callPrettyfier,
|
||||||
|
}
|
||||||
|
log.SetFormatter(format)
|
||||||
|
|
||||||
|
l := cfg.Log.Level
|
||||||
|
if l == "" {
|
||||||
|
log.Infof("Log level not set, sticking to info")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
level, err := log.ParseLevel(l)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).
|
||||||
|
Errorf("invalid log level: %q", l)
|
||||||
|
}
|
||||||
|
|
||||||
|
// debug level
|
||||||
|
switch level {
|
||||||
|
case log.DebugLevel, log.TraceLevel:
|
||||||
|
log.SetReportCaller(true) // Only in debug or trace because it takes a performance toll
|
||||||
|
log.Infof("Log level %s requested, setting up report caller for further debugging", level)
|
||||||
|
}
|
||||||
|
|
||||||
|
if log.GetLevel() != level {
|
||||||
|
log.Infof("log level set to %v", level)
|
||||||
|
log.SetLevel(level)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var commonSocketPaths = []string{
|
||||||
|
"/var/run/docker.sock",
|
||||||
|
"/run/podman/podman.sock",
|
||||||
|
"$HOME/.colima/docker.sock",
|
||||||
|
"$XDG_RUNTIME_DIR/docker.sock",
|
||||||
|
"$XDG_RUNTIME_DIR/podman/podman.sock",
|
||||||
|
`\\.\pipe\docker_engine`,
|
||||||
|
"$HOME/.docker/run/docker.sock",
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDockerSocketPath(configDockerHost string) (string, error) {
|
||||||
|
// a `-` means don't mount the docker socket to job containers
|
||||||
|
if configDockerHost != "" && configDockerHost != "-" {
|
||||||
|
return configDockerHost, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
socket, found := os.LookupEnv("DOCKER_HOST")
|
||||||
|
if found {
|
||||||
|
return socket, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range commonSocketPaths {
|
||||||
|
if _, err := os.Lstat(os.ExpandEnv(p)); err == nil {
|
||||||
|
if strings.HasPrefix(p, `\\.\`) {
|
||||||
|
return "npipe://" + filepath.ToSlash(os.ExpandEnv(p)), nil
|
||||||
|
}
|
||||||
|
return "unix://" + filepath.ToSlash(os.ExpandEnv(p)), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("daemon Docker Engine socket not found and docker_host config was invalid")
|
||||||
|
}
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ type executeArgs struct {
|
|||||||
envs []string
|
envs []string
|
||||||
envfile string
|
envfile string
|
||||||
secrets []string
|
secrets []string
|
||||||
defaultActionsUrls []string
|
vars []string
|
||||||
|
defaultActionsURL string
|
||||||
insecureSecrets bool
|
insecureSecrets bool
|
||||||
privileged bool
|
privileged bool
|
||||||
usernsMode string
|
usernsMode string
|
||||||
@@ -58,6 +59,7 @@ type executeArgs struct {
|
|||||||
image string
|
image string
|
||||||
cacheHandler *artifactcache.Handler
|
cacheHandler *artifactcache.Handler
|
||||||
network string
|
network string
|
||||||
|
githubInstance string
|
||||||
}
|
}
|
||||||
|
|
||||||
// WorkflowsPath returns path to workflow file(s)
|
// WorkflowsPath returns path to workflow file(s)
|
||||||
@@ -129,6 +131,22 @@ func (i *executeArgs) LoadEnvs() map[string]string {
|
|||||||
return envs
|
return envs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *executeArgs) LoadVars() map[string]string {
|
||||||
|
vars := make(map[string]string)
|
||||||
|
if i.vars != nil {
|
||||||
|
for _, runVar := range i.vars {
|
||||||
|
e := strings.SplitN(runVar, `=`, 2)
|
||||||
|
if len(e) == 2 {
|
||||||
|
vars[e[0]] = e[1]
|
||||||
|
} else {
|
||||||
|
vars[e[0]] = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vars
|
||||||
|
}
|
||||||
|
|
||||||
// Workdir returns path to workdir
|
// Workdir returns path to workdir
|
||||||
func (i *executeArgs) Workdir() string {
|
func (i *executeArgs) Workdir() string {
|
||||||
return i.resolve(".")
|
return i.resolve(".")
|
||||||
@@ -251,7 +269,7 @@ func runExecList(ctx context.Context, planner model.WorkflowPlanner, execArgs *e
|
|||||||
var filterPlan *model.Plan
|
var filterPlan *model.Plan
|
||||||
|
|
||||||
// Determine the event name to be filtered
|
// Determine the event name to be filtered
|
||||||
var filterEventName string = ""
|
var filterEventName string
|
||||||
|
|
||||||
if len(execArgs.event) > 0 {
|
if len(execArgs.event) > 0 {
|
||||||
log.Infof("Using chosed event for filtering: %s", execArgs.event)
|
log.Infof("Using chosed event for filtering: %s", execArgs.event)
|
||||||
@@ -288,7 +306,7 @@ func runExecList(ctx context.Context, planner model.WorkflowPlanner, execArgs *e
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printList(filterPlan)
|
_ = printList(filterPlan)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -358,11 +376,11 @@ func runExec(ctx context.Context, execArgs *executeArgs) func(cmd *cobra.Command
|
|||||||
execArgs.cacheHandler = handler
|
execArgs.cacheHandler = handler
|
||||||
|
|
||||||
if len(execArgs.artifactServerAddr) == 0 {
|
if len(execArgs.artifactServerAddr) == 0 {
|
||||||
if ip := common.GetOutboundIP(); ip == nil {
|
ip := common.GetOutboundIP()
|
||||||
|
if ip == nil {
|
||||||
return fmt.Errorf("unable to determine outbound IP address")
|
return fmt.Errorf("unable to determine outbound IP address")
|
||||||
} else {
|
|
||||||
execArgs.artifactServerAddr = ip.String()
|
|
||||||
}
|
}
|
||||||
|
execArgs.artifactServerAddr = ip.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(execArgs.artifactServerPath) == 0 {
|
if len(execArgs.artifactServerPath) == 0 {
|
||||||
@@ -385,6 +403,7 @@ func runExec(ctx context.Context, execArgs *executeArgs) func(cmd *cobra.Command
|
|||||||
LogOutput: true,
|
LogOutput: true,
|
||||||
JSONLogger: execArgs.jsonLogger,
|
JSONLogger: execArgs.jsonLogger,
|
||||||
Env: execArgs.LoadEnvs(),
|
Env: execArgs.LoadEnvs(),
|
||||||
|
Vars: execArgs.LoadVars(),
|
||||||
Secrets: execArgs.LoadSecrets(),
|
Secrets: execArgs.LoadSecrets(),
|
||||||
InsecureSecrets: execArgs.insecureSecrets,
|
InsecureSecrets: execArgs.insecureSecrets,
|
||||||
Privileged: execArgs.privileged,
|
Privileged: execArgs.privileged,
|
||||||
@@ -392,28 +411,37 @@ func runExec(ctx context.Context, execArgs *executeArgs) func(cmd *cobra.Command
|
|||||||
ContainerArchitecture: execArgs.containerArchitecture,
|
ContainerArchitecture: execArgs.containerArchitecture,
|
||||||
ContainerDaemonSocket: execArgs.containerDaemonSocket,
|
ContainerDaemonSocket: execArgs.containerDaemonSocket,
|
||||||
UseGitIgnore: execArgs.useGitIgnore,
|
UseGitIgnore: execArgs.useGitIgnore,
|
||||||
// GitHubInstance: t.client.Address(),
|
GitHubInstance: execArgs.githubInstance,
|
||||||
ContainerCapAdd: execArgs.containerCapAdd,
|
ContainerCapAdd: execArgs.containerCapAdd,
|
||||||
ContainerCapDrop: execArgs.containerCapDrop,
|
ContainerCapDrop: execArgs.containerCapDrop,
|
||||||
ContainerOptions: execArgs.containerOptions,
|
ContainerOptions: execArgs.containerOptions,
|
||||||
AutoRemove: true,
|
AutoRemove: true,
|
||||||
ArtifactServerPath: execArgs.artifactServerPath,
|
ArtifactServerPath: execArgs.artifactServerPath,
|
||||||
ArtifactServerPort: execArgs.artifactServerPort,
|
ArtifactServerPort: execArgs.artifactServerPort,
|
||||||
ArtifactServerAddr: execArgs.artifactServerAddr,
|
ArtifactServerAddr: execArgs.artifactServerAddr,
|
||||||
NoSkipCheckout: execArgs.noSkipCheckout,
|
NoSkipCheckout: execArgs.noSkipCheckout,
|
||||||
// PresetGitHubContext: preset,
|
// PresetGitHubContext: preset,
|
||||||
// EventJSON: string(eventJSON),
|
// EventJSON: string(eventJSON),
|
||||||
ContainerNamePrefix: fmt.Sprintf("GITEA-ACTIONS-TASK-%s", eventName),
|
ContainerNamePrefix: fmt.Sprintf("GITEA-ACTIONS-TASK-%s", eventName),
|
||||||
ContainerMaxLifetime: maxLifetime,
|
ContainerMaxLifetime: maxLifetime,
|
||||||
ContainerNetworkMode: container.NetworkMode(execArgs.network),
|
ContainerNetworkMode: container.NetworkMode(execArgs.network),
|
||||||
DefaultActionsURLs: execArgs.defaultActionsUrls,
|
DefaultActionInstance: execArgs.defaultActionsURL,
|
||||||
PlatformPicker: func(_ []string) string {
|
PlatformPicker: func(_ []string) string {
|
||||||
return execArgs.image
|
return execArgs.image
|
||||||
},
|
},
|
||||||
|
ValidVolumes: []string{"**"}, // All volumes are allowed for `exec` command
|
||||||
|
}
|
||||||
|
|
||||||
|
config.Env["ACT_EXEC"] = "true"
|
||||||
|
|
||||||
|
if t := config.Secrets["GITEA_TOKEN"]; t != "" {
|
||||||
|
config.Token = t
|
||||||
|
} else if t := config.Secrets["GITHUB_TOKEN"]; t != "" {
|
||||||
|
config.Token = t
|
||||||
}
|
}
|
||||||
|
|
||||||
if !execArgs.debug {
|
if !execArgs.debug {
|
||||||
logLevel := log.Level(log.InfoLevel)
|
logLevel := log.InfoLevel
|
||||||
config.JobLoggerLevel = &logLevel
|
config.JobLoggerLevel = &logLevel
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,6 +486,7 @@ func loadExecCmd(ctx context.Context) *cobra.Command {
|
|||||||
execCmd.Flags().StringArrayVarP(&execArg.envs, "env", "", []string{}, "env to make available to actions with optional value (e.g. --env myenv=foo or --env myenv)")
|
execCmd.Flags().StringArrayVarP(&execArg.envs, "env", "", []string{}, "env to make available to actions with optional value (e.g. --env myenv=foo or --env myenv)")
|
||||||
execCmd.PersistentFlags().StringVarP(&execArg.envfile, "env-file", "", ".env", "environment file to read and use as env in the containers")
|
execCmd.PersistentFlags().StringVarP(&execArg.envfile, "env-file", "", ".env", "environment file to read and use as env in the containers")
|
||||||
execCmd.Flags().StringArrayVarP(&execArg.secrets, "secret", "s", []string{}, "secret to make available to actions with optional value (e.g. -s mysecret=foo or -s mysecret)")
|
execCmd.Flags().StringArrayVarP(&execArg.secrets, "secret", "s", []string{}, "secret to make available to actions with optional value (e.g. -s mysecret=foo or -s mysecret)")
|
||||||
|
execCmd.Flags().StringArrayVarP(&execArg.vars, "var", "", []string{}, "variable to make available to actions with optional value (e.g. --var myvar=foo or --var myvar)")
|
||||||
execCmd.PersistentFlags().BoolVarP(&execArg.insecureSecrets, "insecure-secrets", "", false, "NOT RECOMMENDED! Doesn't hide secrets while printing logs.")
|
execCmd.PersistentFlags().BoolVarP(&execArg.insecureSecrets, "insecure-secrets", "", false, "NOT RECOMMENDED! Doesn't hide secrets while printing logs.")
|
||||||
execCmd.Flags().BoolVar(&execArg.privileged, "privileged", false, "use privileged mode")
|
execCmd.Flags().BoolVar(&execArg.privileged, "privileged", false, "use privileged mode")
|
||||||
execCmd.Flags().StringVar(&execArg.usernsMode, "userns", "", "user namespace to use")
|
execCmd.Flags().StringVar(&execArg.usernsMode, "userns", "", "user namespace to use")
|
||||||
@@ -470,12 +499,13 @@ 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.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.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.artifactServerPort, "artifact-server-port", "", "34567", "Defines the port where the artifact server listens (will only bind to localhost).")
|
||||||
execCmd.PersistentFlags().StringArrayVarP(&execArg.defaultActionsUrls, "default-actions-url", "", []string{"https://gitea.com", "https://github.com"}, "Defines the default url list of action instance.")
|
execCmd.PersistentFlags().StringVarP(&execArg.defaultActionsURL, "default-actions-url", "", "https://github.com", "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.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.debug, "debug", "d", false, "enable debug log")
|
||||||
execCmd.PersistentFlags().BoolVarP(&execArg.dryrun, "dryrun", "n", false, "dryrun mode")
|
execCmd.PersistentFlags().BoolVarP(&execArg.dryrun, "dryrun", "n", false, "dryrun mode")
|
||||||
execCmd.PersistentFlags().StringVarP(&execArg.image, "image", "i", "node:16-bullseye", "docker image to use")
|
execCmd.PersistentFlags().StringVarP(&execArg.image, "image", "i", "docker.gitea.com/runner-images:ubuntu-latest", "Docker image to use. Use \"-self-hosted\" to run directly on the host.")
|
||||||
execCmd.PersistentFlags().StringVarP(&execArg.network, "network", "", "", "Specify the network to which the container will connect")
|
execCmd.PersistentFlags().StringVarP(&execArg.network, "network", "", "", "Specify the network to which the container will connect")
|
||||||
|
execCmd.PersistentFlags().StringVarP(&execArg.githubInstance, "gitea-instance", "", "", "Gitea instance to use.")
|
||||||
|
|
||||||
return execCmd
|
return execCmd
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
|
|
||||||
pingv1 "code.gitea.io/actions-proto-go/ping/v1"
|
pingv1 "code.gitea.io/actions-proto-go/ping/v1"
|
||||||
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
|
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
|
||||||
"github.com/bufbuild/connect-go"
|
"connectrpc.com/connect"
|
||||||
"github.com/mattn/go-isatty"
|
"github.com/mattn/go-isatty"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -47,12 +47,12 @@ func runRegister(ctx context.Context, regArgs *registerArgs, configFile *string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if regArgs.NoInteractive {
|
if regArgs.NoInteractive {
|
||||||
if err := registerNoInteractive(*configFile, regArgs); err != nil {
|
if err := registerNoInteractive(ctx, *configFile, regArgs); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
go func() {
|
go func() {
|
||||||
if err := registerInteractive(*configFile); err != nil {
|
if err := registerInteractive(ctx, *configFile, regArgs); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -75,6 +75,7 @@ type registerArgs struct {
|
|||||||
Token string
|
Token string
|
||||||
RunnerName string
|
RunnerName string
|
||||||
Labels string
|
Labels string
|
||||||
|
Ephemeral bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type registerStage int8
|
type registerStage int8
|
||||||
@@ -91,10 +92,9 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var defaultLabels = []string{
|
var defaultLabels = []string{
|
||||||
"ubuntu-latest:docker://node:16-bullseye",
|
"ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest",
|
||||||
"ubuntu-22.04:docker://node:16-bullseye", // There's no node:16-bookworm yet
|
"ubuntu-24.04:docker://docker.gitea.com/runner-images:ubuntu-24.04",
|
||||||
"ubuntu-20.04:docker://node:16-bullseye",
|
"ubuntu-22.04:docker://docker.gitea.com/runner-images:ubuntu-22.04",
|
||||||
"ubuntu-18.04:docker://node:16-buster",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type registerInputs struct {
|
type registerInputs struct {
|
||||||
@@ -102,6 +102,7 @@ type registerInputs struct {
|
|||||||
Token string
|
Token string
|
||||||
RunnerName string
|
RunnerName string
|
||||||
Labels []string
|
Labels []string
|
||||||
|
Ephemeral bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *registerInputs) validate() error {
|
func (r *registerInputs) validate() error {
|
||||||
@@ -126,6 +127,22 @@ func validateLabels(ls []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *registerInputs) stageValue(stage registerStage) string {
|
||||||
|
switch stage {
|
||||||
|
case StageInputInstance:
|
||||||
|
return r.InstanceAddr
|
||||||
|
case StageInputToken:
|
||||||
|
return r.Token
|
||||||
|
case StageInputRunnerName:
|
||||||
|
return r.RunnerName
|
||||||
|
case StageInputLabels:
|
||||||
|
if len(r.Labels) > 0 {
|
||||||
|
return strings.Join(r.Labels, ",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func (r *registerInputs) assignToNext(stage registerStage, value string, cfg *config.Config) registerStage {
|
func (r *registerInputs) assignToNext(stage registerStage, value string, cfg *config.Config) registerStage {
|
||||||
// must set instance address and token.
|
// must set instance address and token.
|
||||||
// if empty, keep current stage.
|
// if empty, keep current stage.
|
||||||
@@ -179,7 +196,8 @@ func (r *registerInputs) assignToNext(stage registerStage, value string, cfg *co
|
|||||||
}
|
}
|
||||||
|
|
||||||
if validateLabels(r.Labels) != nil {
|
if validateLabels(r.Labels) != nil {
|
||||||
log.Infoln("Invalid labels, please input again, leave blank to use the default labels (for example, ubuntu-20.04:docker://node:16-bullseye,ubuntu-18.04:docker://node:16-buster,linux_arm:host)")
|
log.Infoln("Invalid labels, please input again, leave blank to use the default labels (for example, ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest)")
|
||||||
|
r.Labels = nil
|
||||||
return StageInputLabels
|
return StageInputLabels
|
||||||
}
|
}
|
||||||
return StageWaitingForRegistration
|
return StageWaitingForRegistration
|
||||||
@@ -187,11 +205,25 @@ func (r *registerInputs) assignToNext(stage registerStage, value string, cfg *co
|
|||||||
return StageUnknown
|
return StageUnknown
|
||||||
}
|
}
|
||||||
|
|
||||||
func registerInteractive(configFile string) error {
|
func initInputs(regArgs *registerArgs) *registerInputs {
|
||||||
|
inputs := ®isterInputs{
|
||||||
|
InstanceAddr: regArgs.InstanceAddr,
|
||||||
|
Token: regArgs.Token,
|
||||||
|
RunnerName: regArgs.RunnerName,
|
||||||
|
Ephemeral: regArgs.Ephemeral,
|
||||||
|
}
|
||||||
|
regArgs.Labels = strings.TrimSpace(regArgs.Labels)
|
||||||
|
// command line flag.
|
||||||
|
if regArgs.Labels != "" {
|
||||||
|
inputs.Labels = strings.Split(regArgs.Labels, ",")
|
||||||
|
}
|
||||||
|
return inputs
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerInteractive(ctx context.Context, configFile string, regArgs *registerArgs) error {
|
||||||
var (
|
var (
|
||||||
reader = bufio.NewReader(os.Stdin)
|
reader = bufio.NewReader(os.Stdin)
|
||||||
stage = StageInputInstance
|
stage = StageInputInstance
|
||||||
inputs = new(registerInputs)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
cfg, err := config.LoadDefault(configFile)
|
cfg, err := config.LoadDefault(configFile)
|
||||||
@@ -201,23 +233,26 @@ func registerInteractive(configFile string) error {
|
|||||||
if f, err := os.Stat(cfg.Runner.File); err == nil && !f.IsDir() {
|
if f, err := os.Stat(cfg.Runner.File); err == nil && !f.IsDir() {
|
||||||
stage = StageOverwriteLocalConfig
|
stage = StageOverwriteLocalConfig
|
||||||
}
|
}
|
||||||
|
inputs := initInputs(regArgs)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
printStageHelp(stage)
|
cmdString := inputs.stageValue(stage)
|
||||||
|
if cmdString == "" {
|
||||||
cmdString, err := reader.ReadString('\n')
|
printStageHelp(stage)
|
||||||
if err != nil {
|
var err error
|
||||||
return err
|
cmdString, err = reader.ReadString('\n')
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
stage = inputs.assignToNext(stage, strings.TrimSpace(cmdString), cfg)
|
stage = inputs.assignToNext(stage, strings.TrimSpace(cmdString), cfg)
|
||||||
|
|
||||||
if stage == StageWaitingForRegistration {
|
if stage == StageWaitingForRegistration {
|
||||||
log.Infof("Registering runner, name=%s, instance=%s, labels=%v.", inputs.RunnerName, inputs.InstanceAddr, inputs.Labels)
|
log.Infof("Registering runner, name=%s, instance=%s, labels=%v.", inputs.RunnerName, inputs.InstanceAddr, inputs.Labels)
|
||||||
if err := doRegister(cfg, inputs); err != nil {
|
if err := doRegister(ctx, cfg, inputs); err != nil {
|
||||||
return fmt.Errorf("Failed to register runner: %w", err)
|
return fmt.Errorf("Failed to register runner: %w", err)
|
||||||
} else {
|
|
||||||
log.Infof("Runner registered successfully.")
|
|
||||||
}
|
}
|
||||||
|
log.Infof("Runner registered successfully.")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,28 +279,18 @@ func printStageHelp(stage registerStage) {
|
|||||||
hostname, _ := os.Hostname()
|
hostname, _ := os.Hostname()
|
||||||
log.Infof("Enter the runner name (if set empty, use hostname: %s):\n", hostname)
|
log.Infof("Enter the runner name (if set empty, use hostname: %s):\n", hostname)
|
||||||
case StageInputLabels:
|
case StageInputLabels:
|
||||||
log.Infoln("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):")
|
log.Infoln("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):")
|
||||||
case StageWaitingForRegistration:
|
case StageWaitingForRegistration:
|
||||||
log.Infoln("Waiting for registration...")
|
log.Infoln("Waiting for registration...")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func registerNoInteractive(configFile string, regArgs *registerArgs) error {
|
func registerNoInteractive(ctx context.Context, configFile string, regArgs *registerArgs) error {
|
||||||
cfg, err := config.LoadDefault(configFile)
|
cfg, err := config.LoadDefault(configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
inputs := ®isterInputs{
|
inputs := initInputs(regArgs)
|
||||||
InstanceAddr: regArgs.InstanceAddr,
|
|
||||||
Token: regArgs.Token,
|
|
||||||
RunnerName: regArgs.RunnerName,
|
|
||||||
Labels: defaultLabels,
|
|
||||||
}
|
|
||||||
regArgs.Labels = strings.TrimSpace(regArgs.Labels)
|
|
||||||
// command line flag.
|
|
||||||
if regArgs.Labels != "" {
|
|
||||||
inputs.Labels = strings.Split(regArgs.Labels, ",")
|
|
||||||
}
|
|
||||||
// specify labels in config file.
|
// specify labels in config file.
|
||||||
if len(cfg.Runner.Labels) > 0 {
|
if len(cfg.Runner.Labels) > 0 {
|
||||||
if regArgs.Labels != "" {
|
if regArgs.Labels != "" {
|
||||||
@@ -273,6 +298,9 @@ func registerNoInteractive(configFile string, regArgs *registerArgs) error {
|
|||||||
}
|
}
|
||||||
inputs.Labels = cfg.Runner.Labels
|
inputs.Labels = cfg.Runner.Labels
|
||||||
}
|
}
|
||||||
|
if len(inputs.Labels) == 0 {
|
||||||
|
inputs.Labels = defaultLabels
|
||||||
|
}
|
||||||
|
|
||||||
if inputs.RunnerName == "" {
|
if inputs.RunnerName == "" {
|
||||||
inputs.RunnerName, _ = os.Hostname()
|
inputs.RunnerName, _ = os.Hostname()
|
||||||
@@ -280,18 +308,16 @@ func registerNoInteractive(configFile string, regArgs *registerArgs) error {
|
|||||||
}
|
}
|
||||||
if err := inputs.validate(); err != nil {
|
if err := inputs.validate(); err != nil {
|
||||||
log.WithError(err).Errorf("Invalid input, please re-run act command.")
|
log.WithError(err).Errorf("Invalid input, please re-run act command.")
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
if err := doRegister(cfg, inputs); err != nil {
|
if err := doRegister(ctx, cfg, inputs); err != nil {
|
||||||
return fmt.Errorf("Failed to register runner: %w", err)
|
return fmt.Errorf("Failed to register runner: %w", err)
|
||||||
}
|
}
|
||||||
log.Infof("Runner registered successfully.")
|
log.Infof("Runner registered successfully.")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func doRegister(cfg *config.Config, inputs *registerInputs) error {
|
func doRegister(ctx context.Context, cfg *config.Config, inputs *registerInputs) error {
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
// initial http client
|
// initial http client
|
||||||
cli := client.New(
|
cli := client.New(
|
||||||
inputs.InstanceAddr,
|
inputs.InstanceAddr,
|
||||||
@@ -307,7 +333,7 @@ func doRegister(cfg *config.Config, inputs *registerInputs) error {
|
|||||||
}))
|
}))
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return nil
|
return ctx.Err()
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
if ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
@@ -325,10 +351,11 @@ func doRegister(cfg *config.Config, inputs *registerInputs) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
reg := &config.Registration{
|
reg := &config.Registration{
|
||||||
Name: inputs.RunnerName,
|
Name: inputs.RunnerName,
|
||||||
Token: inputs.Token,
|
Token: inputs.Token,
|
||||||
Address: inputs.InstanceAddr,
|
Address: inputs.InstanceAddr,
|
||||||
Labels: inputs.Labels,
|
Labels: inputs.Labels,
|
||||||
|
Ephemeral: inputs.Ephemeral,
|
||||||
}
|
}
|
||||||
|
|
||||||
ls := make([]string, len(reg.Labels))
|
ls := make([]string, len(reg.Labels))
|
||||||
@@ -343,6 +370,7 @@ func doRegister(cfg *config.Config, inputs *registerInputs) error {
|
|||||||
Version: ver.Version(),
|
Version: ver.Version(),
|
||||||
AgentLabels: ls, // Could be removed after Gitea 1.20
|
AgentLabels: ls, // Could be removed after Gitea 1.20
|
||||||
Labels: ls,
|
Labels: ls,
|
||||||
|
Ephemeral: reg.Ephemeral,
|
||||||
}))
|
}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Error("poller: cannot register new runner")
|
log.WithError(err).Error("poller: cannot register new runner")
|
||||||
@@ -354,6 +382,11 @@ func doRegister(cfg *config.Config, inputs *registerInputs) error {
|
|||||||
reg.Name = resp.Msg.Runner.Name
|
reg.Name = resp.Msg.Runner.Name
|
||||||
reg.Token = resp.Msg.Runner.Token
|
reg.Token = resp.Msg.Runner.Token
|
||||||
|
|
||||||
|
if inputs.Ephemeral != resp.Msg.Runner.Ephemeral {
|
||||||
|
// TODO we cannot remove the configuration via runner api, if we return an error here we just fill the database
|
||||||
|
log.Error("poller: cannot register new runner as ephemeral upgrade Gitea to gain security, run-once will be used automatically")
|
||||||
|
}
|
||||||
|
|
||||||
if err := config.SaveRegistration(cfg.Runner.File, reg); err != nil {
|
if err := config.SaveRegistration(cfg.Runner.File, reg); err != nil {
|
||||||
return fmt.Errorf("failed to save runner config: %w", err)
|
return fmt.Errorf("failed to save runner config: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
19
internal/app/cmd/register_test.go
Normal file
19
internal/app/cmd/register_test.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gotest.tools/v3/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRegisterNonInteractiveReturnsLabelValidationError(t *testing.T) {
|
||||||
|
err := registerNoInteractive(t.Context(), "", ®isterArgs{
|
||||||
|
Labels: "label:invalid",
|
||||||
|
Token: "token",
|
||||||
|
InstanceAddr: "http://localhost:3000",
|
||||||
|
})
|
||||||
|
assert.Error(t, err, "unsupported schema: invalid")
|
||||||
|
}
|
||||||
@@ -6,58 +6,157 @@ package poll
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
|
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
|
||||||
"github.com/bufbuild/connect-go"
|
"connectrpc.com/connect"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"golang.org/x/time/rate"
|
"golang.org/x/time/rate"
|
||||||
|
|
||||||
"gitea.com/gitea/act_runner/internal/app/run"
|
"gitea.com/gitea/act_runner/internal/app/run"
|
||||||
"gitea.com/gitea/act_runner/internal/pkg/client"
|
"gitea.com/gitea/act_runner/internal/pkg/client"
|
||||||
"gitea.com/gitea/act_runner/internal/pkg/config"
|
"gitea.com/gitea/act_runner/internal/pkg/config"
|
||||||
|
"gitea.com/gitea/act_runner/internal/pkg/envcheck"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Poller struct {
|
type Poller struct {
|
||||||
client client.Client
|
client client.Client
|
||||||
runner *run.Runner
|
runner *run.Runner
|
||||||
cfg *config.Config
|
cfg *config.Config
|
||||||
|
tasksVersion atomic.Int64 // tasksVersion used to store the version of the last task fetched from the Gitea.
|
||||||
|
bandwidthManager *envcheck.BandwidthManager
|
||||||
|
|
||||||
|
pollingCtx context.Context
|
||||||
|
shutdownPolling context.CancelFunc
|
||||||
|
|
||||||
|
jobsCtx context.Context
|
||||||
|
shutdownJobs context.CancelFunc
|
||||||
|
|
||||||
|
done chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg *config.Config, client client.Client, runner *run.Runner) *Poller {
|
func New(cfg *config.Config, client client.Client, runner *run.Runner) *Poller {
|
||||||
|
pollingCtx, shutdownPolling := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
jobsCtx, shutdownJobs := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
|
||||||
return &Poller{
|
return &Poller{
|
||||||
client: client,
|
client: client,
|
||||||
runner: runner,
|
runner: runner,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
|
|
||||||
|
pollingCtx: pollingCtx,
|
||||||
|
shutdownPolling: shutdownPolling,
|
||||||
|
|
||||||
|
jobsCtx: jobsCtx,
|
||||||
|
shutdownJobs: shutdownJobs,
|
||||||
|
|
||||||
|
done: done,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Poller) Poll(ctx context.Context) {
|
// SetBandwidthManager sets the bandwidth manager for on-demand testing
|
||||||
|
func (p *Poller) SetBandwidthManager(bm *envcheck.BandwidthManager) {
|
||||||
|
p.bandwidthManager = bm
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Poller) Poll() {
|
||||||
limiter := rate.NewLimiter(rate.Every(p.cfg.Runner.FetchInterval), 1)
|
limiter := rate.NewLimiter(rate.Every(p.cfg.Runner.FetchInterval), 1)
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
for i := 0; i < p.cfg.Runner.Capacity; i++ {
|
for i := 0; i < p.cfg.Runner.Capacity; i++ {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go p.poll(ctx, wg, limiter)
|
go p.poll(wg, limiter)
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
|
// signal that we shutdown
|
||||||
|
close(p.done)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Poller) poll(ctx context.Context, wg *sync.WaitGroup, limiter *rate.Limiter) {
|
func (p *Poller) PollOnce() {
|
||||||
|
limiter := rate.NewLimiter(rate.Every(p.cfg.Runner.FetchInterval), 1)
|
||||||
|
|
||||||
|
p.pollOnce(limiter)
|
||||||
|
|
||||||
|
// signal that we're done
|
||||||
|
close(p.done)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Poller) Shutdown(ctx context.Context) error {
|
||||||
|
p.shutdownPolling()
|
||||||
|
|
||||||
|
select {
|
||||||
|
// graceful shutdown completed succesfully
|
||||||
|
case <-p.done:
|
||||||
|
return nil
|
||||||
|
|
||||||
|
// our timeout for shutting down ran out
|
||||||
|
case <-ctx.Done():
|
||||||
|
// when both the timeout fires and the graceful shutdown
|
||||||
|
// completed succsfully, this branch of the select may
|
||||||
|
// fire. Do a non-blocking check here against the graceful
|
||||||
|
// shutdown status to avoid sending an error if we don't need to.
|
||||||
|
_, ok := <-p.done
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// force a shutdown of all running jobs
|
||||||
|
p.shutdownJobs()
|
||||||
|
|
||||||
|
// wait for running jobs to report their status to Gitea
|
||||||
|
_, _ = <-p.done
|
||||||
|
|
||||||
|
return ctx.Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Poller) poll(wg *sync.WaitGroup, limiter *rate.Limiter) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
for {
|
for {
|
||||||
if err := limiter.Wait(ctx); err != nil {
|
p.pollOnce(limiter)
|
||||||
if ctx.Err() != nil {
|
|
||||||
|
select {
|
||||||
|
case <-p.pollingCtx.Done():
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Poller) pollOnce(limiter *rate.Limiter) {
|
||||||
|
for {
|
||||||
|
if err := limiter.Wait(p.pollingCtx); err != nil {
|
||||||
|
if p.pollingCtx.Err() != nil {
|
||||||
log.WithError(err).Debug("limiter wait failed")
|
log.WithError(err).Debug("limiter wait failed")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
task, ok := p.fetchTask(ctx)
|
task, ok := p.fetchTask(p.pollingCtx)
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := p.runner.Run(ctx, task); err != nil {
|
|
||||||
log.WithError(err).Error("failed to run task")
|
p.runTaskWithRecover(p.jobsCtx, task)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Poller) runTaskWithRecover(ctx context.Context, task *runnerv1.Task) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
err := fmt.Errorf("panic: %v", r)
|
||||||
|
log.WithError(err).Error("panic in runTaskWithRecover")
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err := p.runner.Run(ctx, task); err != nil {
|
||||||
|
log.WithError(err).Error("failed to run task")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +164,23 @@ func (p *Poller) fetchTask(ctx context.Context) (*runnerv1.Task, bool) {
|
|||||||
reqCtx, cancel := context.WithTimeout(ctx, p.cfg.Runner.FetchTimeout)
|
reqCtx, cancel := context.WithTimeout(ctx, p.cfg.Runner.FetchTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
resp, err := p.client.FetchTask(reqCtx, connect.NewRequest(&runnerv1.FetchTaskRequest{}))
|
// Detect capabilities including current disk space
|
||||||
|
caps := envcheck.DetectCapabilities(ctx, p.cfg.Container.DockerHost, p.cfg.Container.WorkdirParent)
|
||||||
|
|
||||||
|
// Include latest bandwidth result if available
|
||||||
|
if p.bandwidthManager != nil {
|
||||||
|
caps.Bandwidth = p.bandwidthManager.GetLastResult()
|
||||||
|
}
|
||||||
|
|
||||||
|
capsJson := caps.ToJSON()
|
||||||
|
|
||||||
|
// Load the version value that was in the cache when the request was sent.
|
||||||
|
v := p.tasksVersion.Load()
|
||||||
|
fetchReq := &runnerv1.FetchTaskRequest{
|
||||||
|
TasksVersion: v,
|
||||||
|
CapabilitiesJson: capsJson,
|
||||||
|
}
|
||||||
|
resp, err := p.client.FetchTask(reqCtx, connect.NewRequest(fetchReq))
|
||||||
if errors.Is(err, context.DeadlineExceeded) {
|
if errors.Is(err, context.DeadlineExceeded) {
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
@@ -74,8 +189,32 @@ func (p *Poller) fetchTask(ctx context.Context) (*runnerv1.Task, bool) {
|
|||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp == nil || resp.Msg == nil || resp.Msg.Task == nil {
|
if resp == nil || resp.Msg == nil {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if server requested a bandwidth test
|
||||||
|
if resp.Msg.RequestBandwidthTest && p.bandwidthManager != nil {
|
||||||
|
log.Info("Server requested bandwidth test, running now...")
|
||||||
|
go func() {
|
||||||
|
result := p.bandwidthManager.RunTest(ctx)
|
||||||
|
if result != nil {
|
||||||
|
log.Infof("Bandwidth test completed: %.1f Mbps download, %.0f ms latency",
|
||||||
|
result.DownloadMbps, result.Latency)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.Msg.TasksVersion > v {
|
||||||
|
p.tasksVersion.CompareAndSwap(v, resp.Msg.TasksVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.Msg.Task == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
return resp.Msg.Task, true
|
||||||
}
|
}
|
||||||
|
|||||||
24
internal/app/run/logging.go
Normal file
24
internal/app/run/logging.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package run
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NullLogger is used to create a new JobLogger to discard logs. This
|
||||||
|
// will prevent these logs from being logged to the stdout, but
|
||||||
|
// forward them to the Reporter via its hook.
|
||||||
|
type NullLogger struct{}
|
||||||
|
|
||||||
|
// WithJobLogger creates a new logrus.Logger that will discard all logs.
|
||||||
|
func (n NullLogger) WithJobLogger() *log.Logger {
|
||||||
|
logger := log.New()
|
||||||
|
logger.SetOutput(io.Discard)
|
||||||
|
logger.SetLevel(log.TraceLevel)
|
||||||
|
|
||||||
|
return logger
|
||||||
|
}
|
||||||
@@ -7,13 +7,14 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
|
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
|
||||||
"github.com/bufbuild/connect-go"
|
"connectrpc.com/connect"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/nektos/act/pkg/artifactcache"
|
"github.com/nektos/act/pkg/artifactcache"
|
||||||
"github.com/nektos/act/pkg/common"
|
"github.com/nektos/act/pkg/common"
|
||||||
@@ -41,6 +42,48 @@ type Runner struct {
|
|||||||
runningTasks sync.Map
|
runningTasks sync.Map
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getJobCacheDir returns a job-isolated cache directory
|
||||||
|
func (r *Runner) getJobCacheDir(taskID int64) string {
|
||||||
|
return filepath.Join(r.cfg.Host.WorkdirParent, "jobs", fmt.Sprintf("%d", taskID))
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanupJobCache removes the job-specific cache directory after completion
|
||||||
|
func (r *Runner) cleanupJobCache(taskID int64) {
|
||||||
|
jobCacheDir := r.getJobCacheDir(taskID)
|
||||||
|
if err := os.RemoveAll(jobCacheDir); err != nil {
|
||||||
|
log.Warnf("failed to cleanup job cache %s: %v", jobCacheDir, err)
|
||||||
|
} else {
|
||||||
|
log.Infof("cleaned up job cache: %s", jobCacheDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CleanStaleJobCaches removes job cache directories older than maxAge
|
||||||
|
func (r *Runner) CleanStaleJobCaches(maxAge time.Duration) {
|
||||||
|
jobsDir := filepath.Join(r.cfg.Host.WorkdirParent, "jobs")
|
||||||
|
entries, err := os.ReadDir(jobsDir)
|
||||||
|
if err != nil {
|
||||||
|
return // directory may not exist yet
|
||||||
|
}
|
||||||
|
|
||||||
|
cutoff := time.Now().Add(-maxAge)
|
||||||
|
for _, entry := range entries {
|
||||||
|
if !entry.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
info, err := entry.Info()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if info.ModTime().Before(cutoff) {
|
||||||
|
jobPath := filepath.Join(jobsDir, entry.Name())
|
||||||
|
if err := os.RemoveAll(jobPath); err != nil {
|
||||||
|
log.Warnf("failed to remove stale job cache %s: %v", jobPath, err)
|
||||||
|
} else {
|
||||||
|
log.Infof("evicted stale job cache: %s", jobPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
func NewRunner(cfg *config.Config, reg *config.Registration, cli client.Client) *Runner {
|
func NewRunner(cfg *config.Config, reg *config.Registration, cli client.Client) *Runner {
|
||||||
ls := labels.Labels{}
|
ls := labels.Labels{}
|
||||||
for _, v := range reg.Labels {
|
for _, v := range reg.Labels {
|
||||||
@@ -53,23 +96,28 @@ func NewRunner(cfg *config.Config, reg *config.Registration, cli client.Client)
|
|||||||
envs[k] = v
|
envs[k] = v
|
||||||
}
|
}
|
||||||
if cfg.Cache.Enabled == nil || *cfg.Cache.Enabled {
|
if cfg.Cache.Enabled == nil || *cfg.Cache.Enabled {
|
||||||
cacheHandler, err := artifactcache.StartHandler(
|
if cfg.Cache.ExternalServer != "" {
|
||||||
cfg.Cache.Dir,
|
envs["ACTIONS_CACHE_URL"] = cfg.Cache.ExternalServer
|
||||||
cfg.Cache.Host,
|
|
||||||
cfg.Cache.Port,
|
|
||||||
log.StandardLogger().WithField("module", "cache_request"),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("cannot init cache server, it will be disabled: %v", err)
|
|
||||||
// go on
|
|
||||||
} else {
|
} else {
|
||||||
envs["ACTIONS_CACHE_URL"] = cacheHandler.ExternalURL() + "/"
|
cacheHandler, err := artifactcache.StartHandler(
|
||||||
|
cfg.Cache.Dir,
|
||||||
|
cfg.Cache.Host,
|
||||||
|
cfg.Cache.Port,
|
||||||
|
log.StandardLogger().WithField("module", "cache_request"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("cannot init cache server, it will be disabled: %v", err)
|
||||||
|
// go on
|
||||||
|
} else {
|
||||||
|
envs["ACTIONS_CACHE_URL"] = cacheHandler.ExternalURL() + "/"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set artifact gitea api
|
// set artifact gitea api
|
||||||
artifactGiteaAPI := strings.TrimSuffix(cli.Address(), "/") + "/api/actions_pipeline/"
|
artifactGiteaAPI := strings.TrimSuffix(cli.Address(), "/") + "/api/actions_pipeline/"
|
||||||
envs["ACTIONS_RUNTIME_URL"] = artifactGiteaAPI
|
envs["ACTIONS_RUNTIME_URL"] = artifactGiteaAPI
|
||||||
|
envs["ACTIONS_RESULTS_URL"] = strings.TrimSuffix(cli.Address(), "/")
|
||||||
|
|
||||||
// Set specific environments to distinguish between Gitea and GitHub
|
// Set specific environments to distinguish between Gitea and GitHub
|
||||||
envs["GITEA_ACTIONS"] = "true"
|
envs["GITEA_ACTIONS"] = "true"
|
||||||
@@ -87,10 +135,10 @@ func NewRunner(cfg *config.Config, reg *config.Registration, cli client.Client)
|
|||||||
func (r *Runner) Run(ctx context.Context, task *runnerv1.Task) error {
|
func (r *Runner) Run(ctx context.Context, task *runnerv1.Task) error {
|
||||||
if _, ok := r.runningTasks.Load(task.Id); ok {
|
if _, ok := r.runningTasks.Load(task.Id); ok {
|
||||||
return fmt.Errorf("task %d is already running", task.Id)
|
return fmt.Errorf("task %d is already running", task.Id)
|
||||||
} else {
|
|
||||||
r.runningTasks.Store(task.Id, struct{}{})
|
|
||||||
defer r.runningTasks.Delete(task.Id)
|
|
||||||
}
|
}
|
||||||
|
r.runningTasks.Store(task.Id, struct{}{})
|
||||||
|
defer r.runningTasks.Delete(task.Id)
|
||||||
|
defer r.cleanupJobCache(task.Id)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(ctx, r.cfg.Runner.Timeout)
|
ctx, cancel := context.WithTimeout(ctx, r.cfg.Runner.Timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@@ -109,6 +157,17 @@ func (r *Runner) Run(ctx context.Context, task *runnerv1.Task) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getDefaultActionsURL
|
||||||
|
// when DEFAULT_ACTIONS_URL == "https://github.com" and GithubMirror is not blank,
|
||||||
|
// it should be set to GithubMirror first.
|
||||||
|
func (r *Runner) getDefaultActionsURL(ctx context.Context, task *runnerv1.Task) string {
|
||||||
|
giteaDefaultActionsURL := task.Context.Fields["gitea_default_actions_url"].GetStringValue()
|
||||||
|
if giteaDefaultActionsURL == "https://github.com" && r.cfg.Runner.GithubMirror != "" {
|
||||||
|
return r.cfg.Runner.GithubMirror
|
||||||
|
}
|
||||||
|
return giteaDefaultActionsURL
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report.Reporter) (err error) {
|
func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report.Reporter) (err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@@ -133,7 +192,7 @@ func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report.
|
|||||||
taskContext := task.Context.Fields
|
taskContext := task.Context.Fields
|
||||||
|
|
||||||
log.Infof("task %v repo is %v %v %v", task.Id, taskContext["repository"].GetStringValue(),
|
log.Infof("task %v repo is %v %v %v", task.Id, taskContext["repository"].GetStringValue(),
|
||||||
taskContext["gitea_default_actions_url"].GetStringValue(),
|
r.getDefaultActionsURL(ctx, task),
|
||||||
r.client.Address())
|
r.client.Address())
|
||||||
|
|
||||||
preset := &model.GithubContext{
|
preset := &model.GithubContext{
|
||||||
@@ -159,8 +218,18 @@ func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report.
|
|||||||
preset.Token = t
|
preset.Token = t
|
||||||
}
|
}
|
||||||
|
|
||||||
// use task token to action api token
|
if actionsIdTokenRequestUrl := taskContext["actions_id_token_request_url"].GetStringValue(); actionsIdTokenRequestUrl != "" {
|
||||||
r.envs["ACTIONS_RUNTIME_TOKEN"] = preset.Token
|
r.envs["ACTIONS_ID_TOKEN_REQUEST_URL"] = actionsIdTokenRequestUrl
|
||||||
|
r.envs["ACTIONS_ID_TOKEN_REQUEST_TOKEN"] = taskContext["actions_id_token_request_token"].GetStringValue()
|
||||||
|
task.Secrets["ACTIONS_ID_TOKEN_REQUEST_TOKEN"] = r.envs["ACTIONS_ID_TOKEN_REQUEST_TOKEN"]
|
||||||
|
}
|
||||||
|
|
||||||
|
giteaRuntimeToken := taskContext["gitea_runtime_token"].GetStringValue()
|
||||||
|
if giteaRuntimeToken == "" {
|
||||||
|
// use task token to action api token for previous Gitea Server Versions
|
||||||
|
giteaRuntimeToken = preset.Token
|
||||||
|
}
|
||||||
|
r.envs["ACTIONS_RUNTIME_TOKEN"] = giteaRuntimeToken
|
||||||
|
|
||||||
eventJSON, err := json.Marshal(preset.Event)
|
eventJSON, err := json.Marshal(preset.Event)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -172,32 +241,47 @@ func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report.
|
|||||||
maxLifetime = time.Until(deadline)
|
maxLifetime = time.Until(deadline)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create job-specific environment with isolated cache directories
|
||||||
|
jobCacheDir := r.getJobCacheDir(task.Id)
|
||||||
|
jobEnvs := make(map[string]string, len(r.envs)+2)
|
||||||
|
for k, v := range r.envs {
|
||||||
|
jobEnvs[k] = v
|
||||||
|
}
|
||||||
|
// Isolate golangci-lint cache to prevent parallel job conflicts
|
||||||
|
jobEnvs["GOLANGCI_LINT_CACHE"] = filepath.Join(jobCacheDir, "golangci-lint")
|
||||||
|
// Set XDG_CACHE_HOME to isolate other tools that respect it
|
||||||
|
jobEnvs["XDG_CACHE_HOME"] = jobCacheDir
|
||||||
|
|
||||||
runnerConfig := &runner.Config{
|
runnerConfig := &runner.Config{
|
||||||
// On Linux, Workdir will be like "/<parent_directory>/<owner>/<repo>"
|
// On Linux, Workdir will be like "/<parent_directory>/<owner>/<repo>"
|
||||||
// On Windows, Workdir will be like "\<parent_directory>\<owner>\<repo>"
|
// On Windows, Workdir will be like "\<parent_directory>\<owner>\<repo>"
|
||||||
Workdir: filepath.FromSlash(fmt.Sprintf("/%s/%s", r.cfg.Container.WorkdirParent, preset.Repository)),
|
Workdir: filepath.FromSlash(fmt.Sprintf("/%s/%s", strings.TrimLeft(r.cfg.Container.WorkdirParent, "/"), preset.Repository)),
|
||||||
BindWorkdir: false,
|
BindWorkdir: false,
|
||||||
|
ActionCacheDir: filepath.FromSlash(jobCacheDir),
|
||||||
|
|
||||||
ReuseContainers: false,
|
ReuseContainers: false,
|
||||||
ForcePull: false,
|
ForcePull: r.cfg.Container.ForcePull,
|
||||||
ForceRebuild: false,
|
ForceRebuild: r.cfg.Container.ForceRebuild,
|
||||||
LogOutput: true,
|
LogOutput: true,
|
||||||
JSONLogger: false,
|
JSONLogger: false,
|
||||||
Env: r.envs,
|
Env: jobEnvs,
|
||||||
Secrets: task.Secrets,
|
Secrets: task.Secrets,
|
||||||
GitHubInstance: strings.TrimSuffix(r.client.Address(), "/"),
|
GitHubInstance: strings.TrimSuffix(r.client.Address(), "/"),
|
||||||
AutoRemove: true,
|
AutoRemove: true,
|
||||||
NoSkipCheckout: true,
|
NoSkipCheckout: true,
|
||||||
PresetGitHubContext: preset,
|
PresetGitHubContext: preset,
|
||||||
EventJSON: string(eventJSON),
|
EventJSON: string(eventJSON),
|
||||||
ContainerNamePrefix: fmt.Sprintf("GITEA-ACTIONS-TASK-%d", task.Id),
|
ContainerNamePrefix: fmt.Sprintf("GITEA-ACTIONS-TASK-%d", task.Id),
|
||||||
ContainerMaxLifetime: maxLifetime,
|
ContainerMaxLifetime: maxLifetime,
|
||||||
ContainerNetworkMode: container.NetworkMode(r.cfg.Container.Network),
|
ContainerNetworkMode: container.NetworkMode(r.cfg.Container.Network),
|
||||||
ContainerOptions: r.cfg.Container.Options,
|
ContainerOptions: r.cfg.Container.Options,
|
||||||
Privileged: r.cfg.Container.Privileged,
|
ContainerDaemonSocket: r.cfg.Container.DockerHost,
|
||||||
DefaultActionsURLs: parseDefaultActionsURLs(taskContext["gitea_default_actions_url"].GetStringValue()),
|
Privileged: r.cfg.Container.Privileged,
|
||||||
PlatformPicker: r.labels.PickPlatform,
|
DefaultActionInstance: r.getDefaultActionsURL(ctx, task),
|
||||||
Vars: task.Vars,
|
PlatformPicker: r.labels.PickPlatform,
|
||||||
|
Vars: task.Vars,
|
||||||
|
ValidVolumes: r.cfg.Container.ValidVolumes,
|
||||||
|
InsecureSkipTLS: r.cfg.Runner.Insecure,
|
||||||
}
|
}
|
||||||
|
|
||||||
rr, err := runner.New(runnerConfig)
|
rr, err := runner.New(runnerConfig)
|
||||||
@@ -211,24 +295,19 @@ func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report.
|
|||||||
// add logger recorders
|
// add logger recorders
|
||||||
ctx = common.WithLoggerHook(ctx, reporter)
|
ctx = common.WithLoggerHook(ctx, reporter)
|
||||||
|
|
||||||
|
if !log.IsLevelEnabled(log.DebugLevel) {
|
||||||
|
ctx = runner.WithJobLoggerFactory(ctx, NullLogger{})
|
||||||
|
}
|
||||||
|
|
||||||
execErr := executor(ctx)
|
execErr := executor(ctx)
|
||||||
reporter.SetOutputs(job.Outputs)
|
reporter.SetOutputs(job.Outputs)
|
||||||
return execErr
|
return execErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseDefaultActionsURLs(s string) []string {
|
func (r *Runner) Declare(ctx context.Context, labels []string, capabilitiesJson string) (*connect.Response[runnerv1.DeclareResponse], error) {
|
||||||
urls := strings.Split(s, ",")
|
|
||||||
trimmed := make([]string, 0, len(urls))
|
|
||||||
for _, u := range urls {
|
|
||||||
t := strings.TrimRight(strings.TrimSpace(u), "/")
|
|
||||||
trimmed = append(trimmed, t)
|
|
||||||
}
|
|
||||||
return trimmed
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Runner) Declare(ctx context.Context, labels []string) (*connect.Response[runnerv1.DeclareResponse], error) {
|
|
||||||
return r.client.Declare(ctx, connect.NewRequest(&runnerv1.DeclareRequest{
|
return r.client.Declare(ctx, connect.NewRequest(&runnerv1.DeclareRequest{
|
||||||
Version: ver.Version(),
|
Version: ver.Version(),
|
||||||
Labels: labels,
|
Labels: labels,
|
||||||
|
CapabilitiesJson: capabilitiesJson,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/actions-proto-go/ping/v1/pingv1connect"
|
"code.gitea.io/actions-proto-go/ping/v1/pingv1connect"
|
||||||
"code.gitea.io/actions-proto-go/runner/v1/runnerv1connect"
|
"code.gitea.io/actions-proto-go/runner/v1/runnerv1connect"
|
||||||
"github.com/bufbuild/connect-go"
|
"connectrpc.com/connect"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getHttpClient(endpoint string, insecure bool) *http.Client {
|
func getHTTPClient(endpoint string, insecure bool) *http.Client {
|
||||||
if strings.HasPrefix(endpoint, "https://") && insecure {
|
if strings.HasPrefix(endpoint, "https://") && insecure {
|
||||||
return &http.Client{
|
return &http.Client{
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
@@ -49,12 +49,12 @@ func New(endpoint string, insecure bool, uuid, token, version string, opts ...co
|
|||||||
|
|
||||||
return &HTTPClient{
|
return &HTTPClient{
|
||||||
PingServiceClient: pingv1connect.NewPingServiceClient(
|
PingServiceClient: pingv1connect.NewPingServiceClient(
|
||||||
getHttpClient(endpoint, insecure),
|
getHTTPClient(endpoint, insecure),
|
||||||
baseURL,
|
baseURL,
|
||||||
opts...,
|
opts...,
|
||||||
),
|
),
|
||||||
RunnerServiceClient: runnerv1connect.NewRunnerServiceClient(
|
RunnerServiceClient: runnerv1connect.NewRunnerServiceClient(
|
||||||
getHttpClient(endpoint, insecure),
|
getHTTPClient(endpoint, insecure),
|
||||||
baseURL,
|
baseURL,
|
||||||
opts...,
|
opts...,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
// Code generated by mockery v2.26.1. DO NOT EDIT.
|
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||||
|
|
||||||
package mocks
|
package mocks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
context "context"
|
context "context"
|
||||||
|
|
||||||
connect "github.com/bufbuild/connect-go"
|
connect "connectrpc.com/connect"
|
||||||
|
|
||||||
mock "github.com/stretchr/testify/mock"
|
mock "github.com/stretchr/testify/mock"
|
||||||
|
|
||||||
@@ -23,6 +23,10 @@ type Client struct {
|
|||||||
func (_m *Client) Address() string {
|
func (_m *Client) Address() string {
|
||||||
ret := _m.Called()
|
ret := _m.Called()
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for Address")
|
||||||
|
}
|
||||||
|
|
||||||
var r0 string
|
var r0 string
|
||||||
if rf, ok := ret.Get(0).(func() string); ok {
|
if rf, ok := ret.Get(0).(func() string); ok {
|
||||||
r0 = rf()
|
r0 = rf()
|
||||||
@@ -37,6 +41,10 @@ func (_m *Client) Address() string {
|
|||||||
func (_m *Client) Declare(_a0 context.Context, _a1 *connect.Request[runnerv1.DeclareRequest]) (*connect.Response[runnerv1.DeclareResponse], error) {
|
func (_m *Client) Declare(_a0 context.Context, _a1 *connect.Request[runnerv1.DeclareRequest]) (*connect.Response[runnerv1.DeclareResponse], error) {
|
||||||
ret := _m.Called(_a0, _a1)
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for Declare")
|
||||||
|
}
|
||||||
|
|
||||||
var r0 *connect.Response[runnerv1.DeclareResponse]
|
var r0 *connect.Response[runnerv1.DeclareResponse]
|
||||||
var r1 error
|
var r1 error
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[runnerv1.DeclareRequest]) (*connect.Response[runnerv1.DeclareResponse], error)); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[runnerv1.DeclareRequest]) (*connect.Response[runnerv1.DeclareResponse], error)); ok {
|
||||||
@@ -63,6 +71,10 @@ func (_m *Client) Declare(_a0 context.Context, _a1 *connect.Request[runnerv1.Dec
|
|||||||
func (_m *Client) FetchTask(_a0 context.Context, _a1 *connect.Request[runnerv1.FetchTaskRequest]) (*connect.Response[runnerv1.FetchTaskResponse], error) {
|
func (_m *Client) FetchTask(_a0 context.Context, _a1 *connect.Request[runnerv1.FetchTaskRequest]) (*connect.Response[runnerv1.FetchTaskResponse], error) {
|
||||||
ret := _m.Called(_a0, _a1)
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for FetchTask")
|
||||||
|
}
|
||||||
|
|
||||||
var r0 *connect.Response[runnerv1.FetchTaskResponse]
|
var r0 *connect.Response[runnerv1.FetchTaskResponse]
|
||||||
var r1 error
|
var r1 error
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[runnerv1.FetchTaskRequest]) (*connect.Response[runnerv1.FetchTaskResponse], error)); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[runnerv1.FetchTaskRequest]) (*connect.Response[runnerv1.FetchTaskResponse], error)); ok {
|
||||||
@@ -89,6 +101,10 @@ func (_m *Client) FetchTask(_a0 context.Context, _a1 *connect.Request[runnerv1.F
|
|||||||
func (_m *Client) Insecure() bool {
|
func (_m *Client) Insecure() bool {
|
||||||
ret := _m.Called()
|
ret := _m.Called()
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for Insecure")
|
||||||
|
}
|
||||||
|
|
||||||
var r0 bool
|
var r0 bool
|
||||||
if rf, ok := ret.Get(0).(func() bool); ok {
|
if rf, ok := ret.Get(0).(func() bool); ok {
|
||||||
r0 = rf()
|
r0 = rf()
|
||||||
@@ -103,6 +119,10 @@ func (_m *Client) Insecure() bool {
|
|||||||
func (_m *Client) Ping(_a0 context.Context, _a1 *connect.Request[pingv1.PingRequest]) (*connect.Response[pingv1.PingResponse], error) {
|
func (_m *Client) Ping(_a0 context.Context, _a1 *connect.Request[pingv1.PingRequest]) (*connect.Response[pingv1.PingResponse], error) {
|
||||||
ret := _m.Called(_a0, _a1)
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for Ping")
|
||||||
|
}
|
||||||
|
|
||||||
var r0 *connect.Response[pingv1.PingResponse]
|
var r0 *connect.Response[pingv1.PingResponse]
|
||||||
var r1 error
|
var r1 error
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[pingv1.PingRequest]) (*connect.Response[pingv1.PingResponse], error)); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[pingv1.PingRequest]) (*connect.Response[pingv1.PingResponse], error)); ok {
|
||||||
@@ -129,6 +149,10 @@ func (_m *Client) Ping(_a0 context.Context, _a1 *connect.Request[pingv1.PingRequ
|
|||||||
func (_m *Client) Register(_a0 context.Context, _a1 *connect.Request[runnerv1.RegisterRequest]) (*connect.Response[runnerv1.RegisterResponse], error) {
|
func (_m *Client) Register(_a0 context.Context, _a1 *connect.Request[runnerv1.RegisterRequest]) (*connect.Response[runnerv1.RegisterResponse], error) {
|
||||||
ret := _m.Called(_a0, _a1)
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for Register")
|
||||||
|
}
|
||||||
|
|
||||||
var r0 *connect.Response[runnerv1.RegisterResponse]
|
var r0 *connect.Response[runnerv1.RegisterResponse]
|
||||||
var r1 error
|
var r1 error
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[runnerv1.RegisterRequest]) (*connect.Response[runnerv1.RegisterResponse], error)); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[runnerv1.RegisterRequest]) (*connect.Response[runnerv1.RegisterResponse], error)); ok {
|
||||||
@@ -155,6 +179,10 @@ func (_m *Client) Register(_a0 context.Context, _a1 *connect.Request[runnerv1.Re
|
|||||||
func (_m *Client) UpdateLog(_a0 context.Context, _a1 *connect.Request[runnerv1.UpdateLogRequest]) (*connect.Response[runnerv1.UpdateLogResponse], error) {
|
func (_m *Client) UpdateLog(_a0 context.Context, _a1 *connect.Request[runnerv1.UpdateLogRequest]) (*connect.Response[runnerv1.UpdateLogResponse], error) {
|
||||||
ret := _m.Called(_a0, _a1)
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for UpdateLog")
|
||||||
|
}
|
||||||
|
|
||||||
var r0 *connect.Response[runnerv1.UpdateLogResponse]
|
var r0 *connect.Response[runnerv1.UpdateLogResponse]
|
||||||
var r1 error
|
var r1 error
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[runnerv1.UpdateLogRequest]) (*connect.Response[runnerv1.UpdateLogResponse], error)); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[runnerv1.UpdateLogRequest]) (*connect.Response[runnerv1.UpdateLogResponse], error)); ok {
|
||||||
@@ -181,6 +209,10 @@ func (_m *Client) UpdateLog(_a0 context.Context, _a1 *connect.Request[runnerv1.U
|
|||||||
func (_m *Client) UpdateTask(_a0 context.Context, _a1 *connect.Request[runnerv1.UpdateTaskRequest]) (*connect.Response[runnerv1.UpdateTaskResponse], error) {
|
func (_m *Client) UpdateTask(_a0 context.Context, _a1 *connect.Request[runnerv1.UpdateTaskRequest]) (*connect.Response[runnerv1.UpdateTaskResponse], error) {
|
||||||
ret := _m.Called(_a0, _a1)
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for UpdateTask")
|
||||||
|
}
|
||||||
|
|
||||||
var r0 *connect.Response[runnerv1.UpdateTaskResponse]
|
var r0 *connect.Response[runnerv1.UpdateTaskResponse]
|
||||||
var r1 error
|
var r1 error
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[runnerv1.UpdateTaskRequest]) (*connect.Response[runnerv1.UpdateTaskResponse], error)); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, *connect.Request[runnerv1.UpdateTaskRequest]) (*connect.Response[runnerv1.UpdateTaskResponse], error)); ok {
|
||||||
@@ -203,13 +235,13 @@ func (_m *Client) UpdateTask(_a0 context.Context, _a1 *connect.Request[runnerv1.
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
type mockConstructorTestingTNewClient interface {
|
// NewClient creates a new instance of Client. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||||
|
// The first argument is typically a *testing.T value.
|
||||||
|
func NewClient(t interface {
|
||||||
mock.TestingT
|
mock.TestingT
|
||||||
Cleanup(func())
|
Cleanup(func())
|
||||||
}
|
},
|
||||||
|
) *Client {
|
||||||
// NewClient creates a new instance of Client. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
|
||||||
func NewClient(t mockConstructorTestingTNewClient) *Client {
|
|
||||||
mock := &Client{}
|
mock := &Client{}
|
||||||
mock.Mock.Test(t)
|
mock.Mock.Test(t)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
# Example configuration file, it's safe to copy this as the default config file without any modification.
|
# 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 `./act_runner generate-config > config.yaml` to generate a config file.
|
||||||
|
|
||||||
log:
|
log:
|
||||||
# The level of logging, can be trace, debug, info, warn, error, fatal
|
# The level of logging, can be trace, debug, info, warn, error, fatal
|
||||||
level: info
|
level: info
|
||||||
@@ -18,19 +21,31 @@ runner:
|
|||||||
env_file: .env
|
env_file: .env
|
||||||
# The timeout for a job to be finished.
|
# The timeout for a job to be finished.
|
||||||
# Please note that the Gitea instance also has a timeout (3h by default) for the job.
|
# 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.
|
# So the job could be stopped by the Gitea instance if its timeout is shorter than this.
|
||||||
timeout: 3h
|
timeout: 3h
|
||||||
|
# The timeout for the runner to wait for running jobs to finish when shutting down.
|
||||||
|
# Any running jobs that haven't finished after this timeout will be cancelled.
|
||||||
|
shutdown_timeout: 0s
|
||||||
# Whether skip verifying the TLS certificate of the Gitea instance.
|
# Whether skip verifying the TLS certificate of the Gitea instance.
|
||||||
insecure: false
|
insecure: false
|
||||||
# The timeout for fetching the job from the Gitea instance.
|
# The timeout for fetching the job from the Gitea instance.
|
||||||
fetch_timeout: 5s
|
fetch_timeout: 5s
|
||||||
# The interval for fetching the job from the Gitea instance.
|
# The interval for fetching the job from the Gitea instance.
|
||||||
fetch_interval: 2s
|
fetch_interval: 2s
|
||||||
|
# The github_mirror of a runner is used to specify the mirror address of the github that pulls the action repository.
|
||||||
|
# It works when something like `uses: actions/checkout@v4` is used and DEFAULT_ACTIONS_URL is set to github,
|
||||||
|
# and github_mirror is not empty. In this case,
|
||||||
|
# it replaces https://github.com with the value here, which is useful for some special network environments.
|
||||||
|
github_mirror: ''
|
||||||
# The labels of a runner are used to determine which jobs the runner can run, and how to run them.
|
# 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"]
|
# Like: "macos-arm64:host" or "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest"
|
||||||
|
# Find more images provided by Gitea at https://gitea.com/gitea/runner-images .
|
||||||
# If it's empty when registering, it will ask for inputting labels.
|
# If it's empty when registering, it will ask for inputting labels.
|
||||||
# If it's empty when execute `deamon`, will use labels in `.runner` file.
|
# If it's empty when execute `daemon`, will use labels in `.runner` file.
|
||||||
labels: []
|
labels:
|
||||||
|
- "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest"
|
||||||
|
- "ubuntu-24.04:docker://docker.gitea.com/runner-images:ubuntu-24.04"
|
||||||
|
- "ubuntu-22.04:docker://docker.gitea.com/runner-images:ubuntu-22.04"
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
# Enable cache server to use actions/cache.
|
# Enable cache server to use actions/cache.
|
||||||
@@ -45,6 +60,10 @@ cache:
|
|||||||
# The port of the cache server.
|
# The port of the cache server.
|
||||||
# 0 means to use a random available port.
|
# 0 means to use a random available port.
|
||||||
port: 0
|
port: 0
|
||||||
|
# The external cache server URL. Valid only when enable is true.
|
||||||
|
# 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:
|
container:
|
||||||
# Specifies the network to which the container will connect.
|
# Specifies the network to which the container will connect.
|
||||||
@@ -53,8 +72,39 @@ container:
|
|||||||
network: ""
|
network: ""
|
||||||
# Whether to use privileged mode or not when launching task containers (privileged mode is required for Docker-in-Docker).
|
# Whether to use privileged mode or not when launching task containers (privileged mode is required for Docker-in-Docker).
|
||||||
privileged: false
|
privileged: false
|
||||||
# And other options to be used when the container is started (eg, --add-host=my.gitea.url:host-gateway).
|
# Any other options to be used when the container is started (e.g., --add-host=my.gitea.url:host-gateway).
|
||||||
options:
|
options:
|
||||||
# The parent directory of a job's working directory.
|
# The parent directory of a job's working directory.
|
||||||
|
# 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.
|
# If it's empty, /workspace will be used.
|
||||||
workdir_parent:
|
workdir_parent:
|
||||||
|
# Volumes (including bind mounts) can be mounted to containers. Glob syntax is supported, see https://github.com/gobwas/glob
|
||||||
|
# You can specify multiple volumes. If the sequence is empty, no volumes can be mounted.
|
||||||
|
# For example, if you only allow containers to mount the `data` volume and all the json files in `/src`, you should change the config to:
|
||||||
|
# valid_volumes:
|
||||||
|
# - data
|
||||||
|
# - /src/*.json
|
||||||
|
# If you want to allow any volume, please use the following configuration:
|
||||||
|
# valid_volumes:
|
||||||
|
# - '**'
|
||||||
|
valid_volumes: []
|
||||||
|
# Overrides the docker client host with the specified one.
|
||||||
|
# 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 act_runner
|
||||||
|
require_docker: false
|
||||||
|
# Timeout to wait for the docker daemon to be reachable, if docker is required by require_docker or act_runner
|
||||||
|
docker_timeout: 0s
|
||||||
|
|
||||||
|
host:
|
||||||
|
# The parent directory of a job's working directory.
|
||||||
|
# If it's empty, $HOME/.cache/act/ will be used.
|
||||||
|
workdir_parent:
|
||||||
|
|||||||
@@ -21,32 +21,46 @@ type Log struct {
|
|||||||
|
|
||||||
// Runner represents the configuration for the runner.
|
// Runner represents the configuration for the runner.
|
||||||
type Runner struct {
|
type Runner struct {
|
||||||
File string `yaml:"file"` // File specifies the file path for the runner.
|
File string `yaml:"file"` // File specifies the file path for the runner.
|
||||||
Capacity int `yaml:"capacity"` // Capacity specifies the capacity of the runner.
|
Capacity int `yaml:"capacity"` // Capacity specifies the capacity of the runner.
|
||||||
Envs map[string]string `yaml:"envs"` // Envs stores environment variables for the runner.
|
Envs map[string]string `yaml:"envs"` // Envs stores environment variables for the runner.
|
||||||
EnvFile string `yaml:"env_file"` // EnvFile specifies the path to the file containing environment variables for the runner.
|
EnvFile string `yaml:"env_file"` // EnvFile specifies the path to the file containing environment variables for the runner.
|
||||||
Timeout time.Duration `yaml:"timeout"` // Timeout specifies the duration for runner timeout.
|
Timeout time.Duration `yaml:"timeout"` // Timeout specifies the duration for runner timeout.
|
||||||
Insecure bool `yaml:"insecure"` // Insecure indicates whether the runner operates in an insecure mode.
|
ShutdownTimeout time.Duration `yaml:"shutdown_timeout"` // ShutdownTimeout specifies the duration to wait for running jobs to complete during a shutdown of the runner.
|
||||||
FetchTimeout time.Duration `yaml:"fetch_timeout"` // FetchTimeout specifies the timeout duration for fetching resources.
|
Insecure bool `yaml:"insecure"` // Insecure indicates whether the runner operates in an insecure mode.
|
||||||
FetchInterval time.Duration `yaml:"fetch_interval"` // FetchInterval specifies the interval duration for fetching resources.
|
FetchTimeout time.Duration `yaml:"fetch_timeout"` // FetchTimeout specifies the timeout duration for fetching resources.
|
||||||
Labels []string `yaml:"labels"` // Labels specifies the labels of the runner. Labels are declared on each startup
|
FetchInterval time.Duration `yaml:"fetch_interval"` // FetchInterval specifies the interval duration for fetching resources.
|
||||||
|
Labels []string `yaml:"labels"` // Labels specify the labels of the runner. Labels are declared on each startup
|
||||||
|
GithubMirror string `yaml:"github_mirror"` // GithubMirror defines what mirrors should be used when using github
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache represents the configuration for caching.
|
// Cache represents the configuration for caching.
|
||||||
type Cache struct {
|
type Cache struct {
|
||||||
Enabled *bool `yaml:"enabled"` // Enabled indicates whether caching is enabled. It is a pointer to distinguish between false and not set. If not set, it will be true.
|
Enabled *bool `yaml:"enabled"` // Enabled indicates whether caching is enabled. It is a pointer to distinguish between false and not set. If not set, it will be true.
|
||||||
Dir string `yaml:"dir"` // Dir specifies the directory path for caching.
|
Dir string `yaml:"dir"` // Dir specifies the directory path for caching.
|
||||||
Host string `yaml:"host"` // Host specifies the caching host.
|
Host string `yaml:"host"` // Host specifies the caching host.
|
||||||
Port uint16 `yaml:"port"` // Port specifies the caching port.
|
Port uint16 `yaml:"port"` // Port specifies the caching port.
|
||||||
|
ExternalServer string `yaml:"external_server"` // ExternalServer specifies the URL of external cache server
|
||||||
}
|
}
|
||||||
|
|
||||||
// Container represents the configuration for the container.
|
// Container represents the configuration for the container.
|
||||||
type Container struct {
|
type Container struct {
|
||||||
Network string `yaml:"network"` // Network specifies the network for the container.
|
Network string `yaml:"network"` // Network specifies the network for the container.
|
||||||
NetworkMode string `yaml:"network_mode"` // Deprecated: use Network instead. Could be removed after Gitea 1.20
|
NetworkMode string `yaml:"network_mode"` // Deprecated: use Network instead. Could be removed after Gitea 1.20
|
||||||
Privileged bool `yaml:"privileged"` // Privileged indicates whether the container runs in privileged mode.
|
Privileged bool `yaml:"privileged"` // Privileged indicates whether the container runs in privileged mode.
|
||||||
Options string `yaml:"options"` // Options specifies additional options for the container.
|
Options string `yaml:"options"` // Options specifies additional options for the container.
|
||||||
WorkdirParent string `yaml:"workdir_parent"` // WorkdirParent specifies the parent directory for the container's working directory.
|
WorkdirParent string `yaml:"workdir_parent"` // WorkdirParent specifies the parent directory for the container's working directory.
|
||||||
|
ValidVolumes []string `yaml:"valid_volumes"` // ValidVolumes specifies the volumes (including bind mounts) can be mounted to containers.
|
||||||
|
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 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Host represents the configuration for the host.
|
||||||
|
type Host struct {
|
||||||
|
WorkdirParent string `yaml:"workdir_parent"` // WorkdirParent specifies the parent directory for the host's working directory.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config represents the overall configuration.
|
// Config represents the overall configuration.
|
||||||
@@ -55,6 +69,7 @@ type Config struct {
|
|||||||
Runner Runner `yaml:"runner"` // Runner represents the configuration for the runner.
|
Runner Runner `yaml:"runner"` // Runner represents the configuration for the runner.
|
||||||
Cache Cache `yaml:"cache"` // Cache represents the configuration for caching.
|
Cache Cache `yaml:"cache"` // Cache represents the configuration for caching.
|
||||||
Container Container `yaml:"container"` // Container represents the configuration for the container.
|
Container Container `yaml:"container"` // Container represents the configuration for the container.
|
||||||
|
Host Host `yaml:"host"` // Host represents the configuration for the host.
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadDefault returns the default configuration.
|
// LoadDefault returns the default configuration.
|
||||||
@@ -78,6 +93,9 @@ func LoadDefault(file string) (*Config, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("read env file %q: %w", cfg.Runner.EnvFile, err)
|
return nil, fmt.Errorf("read env file %q: %w", cfg.Runner.EnvFile, err)
|
||||||
}
|
}
|
||||||
|
if cfg.Runner.Envs == nil {
|
||||||
|
cfg.Runner.Envs = map[string]string{}
|
||||||
|
}
|
||||||
for k, v := range envs {
|
for k, v := range envs {
|
||||||
cfg.Runner.Envs[k] = v
|
cfg.Runner.Envs[k] = v
|
||||||
}
|
}
|
||||||
@@ -109,6 +127,10 @@ func LoadDefault(file string) (*Config, error) {
|
|||||||
if cfg.Container.WorkdirParent == "" {
|
if cfg.Container.WorkdirParent == "" {
|
||||||
cfg.Container.WorkdirParent = "workspace"
|
cfg.Container.WorkdirParent = "workspace"
|
||||||
}
|
}
|
||||||
|
if cfg.Host.WorkdirParent == "" {
|
||||||
|
home, _ := os.UserHomeDir()
|
||||||
|
cfg.Host.WorkdirParent = filepath.Join(home, ".cache", "act")
|
||||||
|
}
|
||||||
if cfg.Runner.FetchTimeout <= 0 {
|
if cfg.Runner.FetchTimeout <= 0 {
|
||||||
cfg.Runner.FetchTimeout = 5 * time.Second
|
cfg.Runner.FetchTimeout = 5 * time.Second
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,12 +14,13 @@ const registrationWarning = "This file is automatically generated by act-runner.
|
|||||||
type Registration struct {
|
type Registration struct {
|
||||||
Warning string `json:"WARNING"` // Warning message to display, it's always the registrationWarning constant
|
Warning string `json:"WARNING"` // Warning message to display, it's always the registrationWarning constant
|
||||||
|
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
UUID string `json:"uuid"`
|
UUID string `json:"uuid"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
Address string `json:"address"`
|
Address string `json:"address"`
|
||||||
Labels []string `json:"labels"`
|
Labels []string `json:"labels"`
|
||||||
|
Ephemeral bool `json:"ephemeral"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadRegistration(file string) (*Registration, error) {
|
func LoadRegistration(file string) (*Registration, error) {
|
||||||
|
|||||||
209
internal/pkg/envcheck/bandwidth.go
Normal file
209
internal/pkg/envcheck/bandwidth.go
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package envcheck
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BandwidthInfo holds network bandwidth test results
|
||||||
|
type BandwidthInfo struct {
|
||||||
|
DownloadMbps float64 `json:"download_mbps"`
|
||||||
|
UploadMbps float64 `json:"upload_mbps,omitempty"`
|
||||||
|
Latency float64 `json:"latency_ms,omitempty"`
|
||||||
|
TestedAt time.Time `json:"tested_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BandwidthManager handles periodic bandwidth testing
|
||||||
|
type BandwidthManager struct {
|
||||||
|
serverURL string
|
||||||
|
lastResult *BandwidthInfo
|
||||||
|
mu sync.RWMutex
|
||||||
|
testInterval time.Duration
|
||||||
|
stopChan chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBandwidthManager creates a new bandwidth manager
|
||||||
|
func NewBandwidthManager(serverURL string, testInterval time.Duration) *BandwidthManager {
|
||||||
|
return &BandwidthManager{
|
||||||
|
serverURL: serverURL,
|
||||||
|
testInterval: testInterval,
|
||||||
|
stopChan: make(chan struct{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start begins periodic bandwidth testing
|
||||||
|
func (bm *BandwidthManager) Start(ctx context.Context) {
|
||||||
|
// Run initial test
|
||||||
|
bm.RunTest(ctx)
|
||||||
|
|
||||||
|
// Start periodic testing
|
||||||
|
go func() {
|
||||||
|
ticker := time.NewTicker(bm.testInterval)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
bm.RunTest(ctx)
|
||||||
|
case <-bm.stopChan:
|
||||||
|
return
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop stops the periodic testing
|
||||||
|
func (bm *BandwidthManager) Stop() {
|
||||||
|
close(bm.stopChan)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunTest runs a bandwidth test and stores the result
|
||||||
|
func (bm *BandwidthManager) RunTest(ctx context.Context) *BandwidthInfo {
|
||||||
|
result := TestBandwidth(ctx, bm.serverURL)
|
||||||
|
|
||||||
|
bm.mu.Lock()
|
||||||
|
bm.lastResult = result
|
||||||
|
bm.mu.Unlock()
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLastResult returns the most recent bandwidth test result
|
||||||
|
func (bm *BandwidthManager) GetLastResult() *BandwidthInfo {
|
||||||
|
bm.mu.RLock()
|
||||||
|
defer bm.mu.RUnlock()
|
||||||
|
return bm.lastResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestBandwidth tests network bandwidth to the Gitea server
|
||||||
|
func TestBandwidth(ctx context.Context, serverURL string) *BandwidthInfo {
|
||||||
|
if serverURL == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
info := &BandwidthInfo{
|
||||||
|
TestedAt: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test latency first
|
||||||
|
info.Latency = testLatency(ctx, serverURL)
|
||||||
|
|
||||||
|
// Test download speed
|
||||||
|
info.DownloadMbps = testDownloadSpeed(ctx, serverURL)
|
||||||
|
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLatency(ctx context.Context, serverURL string) float64 {
|
||||||
|
client := &http.Client{
|
||||||
|
Timeout: 10 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
reqCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(reqCtx, "HEAD", serverURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
|
||||||
|
latency := time.Since(start).Seconds() * 1000 // Convert to ms
|
||||||
|
return float64(int(latency*100)) / 100 // Round to 2 decimals
|
||||||
|
}
|
||||||
|
|
||||||
|
func testDownloadSpeed(ctx context.Context, serverURL string) float64 {
|
||||||
|
// Try multiple endpoints to accumulate ~1MB of data
|
||||||
|
endpoints := []string{
|
||||||
|
"/assets/css/index.css",
|
||||||
|
"/assets/js/index.js",
|
||||||
|
"/assets/img/logo.svg",
|
||||||
|
"/assets/img/logo.png",
|
||||||
|
"/",
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &http.Client{
|
||||||
|
Timeout: 30 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalBytes int64
|
||||||
|
var totalDuration time.Duration
|
||||||
|
targetBytes := int64(1024 * 1024) // 1MB target
|
||||||
|
maxAttempts := 10 // Limit iterations
|
||||||
|
|
||||||
|
for attempt := 0; attempt < maxAttempts && totalBytes < targetBytes; attempt++ {
|
||||||
|
for _, endpoint := range endpoints {
|
||||||
|
if totalBytes >= targetBytes {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
url := serverURL + endpoint
|
||||||
|
|
||||||
|
reqCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
||||||
|
req, err := http.NewRequestWithContext(reqCtx, "GET", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
cancel()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
cancel()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
n, _ := io.Copy(io.Discard, resp.Body)
|
||||||
|
resp.Body.Close()
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
duration := time.Since(start)
|
||||||
|
|
||||||
|
if n > 0 {
|
||||||
|
totalBytes += n
|
||||||
|
totalDuration += duration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if totalBytes == 0 || totalDuration == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate speed in Mbps
|
||||||
|
seconds := totalDuration.Seconds()
|
||||||
|
if seconds == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
bytesPerSecond := float64(totalBytes) / seconds
|
||||||
|
mbps := (bytesPerSecond * 8) / (1024 * 1024)
|
||||||
|
|
||||||
|
return float64(int(mbps*100)) / 100
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatBandwidth formats bandwidth for display
|
||||||
|
func FormatBandwidth(mbps float64) string {
|
||||||
|
if mbps == 0 {
|
||||||
|
return "Unknown"
|
||||||
|
}
|
||||||
|
if mbps >= 1000 {
|
||||||
|
return fmt.Sprintf("%.1f Gbps", mbps/1000)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%.1f Mbps", mbps)
|
||||||
|
}
|
||||||
889
internal/pkg/envcheck/capabilities.go
Normal file
889
internal/pkg/envcheck/capabilities.go
Normal file
@@ -0,0 +1,889 @@
|
|||||||
|
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package envcheck
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/docker/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DiskInfo holds disk space information
|
||||||
|
type DiskInfo struct {
|
||||||
|
Path string `json:"path,omitempty"` // Path being checked (working directory)
|
||||||
|
Total uint64 `json:"total_bytes"`
|
||||||
|
Free uint64 `json:"free_bytes"`
|
||||||
|
Used uint64 `json:"used_bytes"`
|
||||||
|
UsedPercent float64 `json:"used_percent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DistroInfo holds Linux distribution information
|
||||||
|
type DistroInfo struct {
|
||||||
|
ID string `json:"id,omitempty"` // e.g., "ubuntu", "debian", "fedora"
|
||||||
|
VersionID string `json:"version_id,omitempty"` // e.g., "24.04", "12"
|
||||||
|
PrettyName string `json:"pretty_name,omitempty"` // e.g., "Ubuntu 24.04 LTS"
|
||||||
|
}
|
||||||
|
|
||||||
|
// XcodeInfo holds Xcode and iOS development information
|
||||||
|
type XcodeInfo struct {
|
||||||
|
Version string `json:"version,omitempty"`
|
||||||
|
Build string `json:"build,omitempty"`
|
||||||
|
SDKs []string `json:"sdks,omitempty"` // e.g., ["iOS 17.0", "macOS 14.0"]
|
||||||
|
Simulators []string `json:"simulators,omitempty"` // Available iOS simulators
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunnerCapabilities represents the capabilities of a runner for AI consumption
|
||||||
|
type RunnerCapabilities struct {
|
||||||
|
OS string `json:"os"`
|
||||||
|
Arch string `json:"arch"`
|
||||||
|
Distro *DistroInfo `json:"distro,omitempty"`
|
||||||
|
Xcode *XcodeInfo `json:"xcode,omitempty"`
|
||||||
|
Docker bool `json:"docker"`
|
||||||
|
DockerCompose bool `json:"docker_compose"`
|
||||||
|
ContainerRuntime string `json:"container_runtime,omitempty"`
|
||||||
|
Shell []string `json:"shell,omitempty"`
|
||||||
|
Tools map[string][]string `json:"tools,omitempty"`
|
||||||
|
BuildTools []string `json:"build_tools,omitempty"` // Available build/installer tools
|
||||||
|
PackageManagers []string `json:"package_managers,omitempty"`
|
||||||
|
Features *CapabilityFeatures `json:"features,omitempty"`
|
||||||
|
Limitations []string `json:"limitations,omitempty"`
|
||||||
|
Disk *DiskInfo `json:"disk,omitempty"`
|
||||||
|
Bandwidth *BandwidthInfo `json:"bandwidth,omitempty"`
|
||||||
|
SuggestedLabels []string `json:"suggested_labels,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CapabilityFeatures represents feature support flags
|
||||||
|
type CapabilityFeatures struct {
|
||||||
|
ArtifactsV4 bool `json:"artifacts_v4"`
|
||||||
|
Cache bool `json:"cache"`
|
||||||
|
Services bool `json:"services"`
|
||||||
|
CompositeActions bool `json:"composite_actions"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DetectCapabilities detects the runner's capabilities
|
||||||
|
// workingDir is the directory where builds will run (for disk space detection)
|
||||||
|
func DetectCapabilities(ctx context.Context, dockerHost string, workingDir string) *RunnerCapabilities {
|
||||||
|
cap := &RunnerCapabilities{
|
||||||
|
OS: runtime.GOOS,
|
||||||
|
Arch: runtime.GOARCH,
|
||||||
|
Tools: make(map[string][]string),
|
||||||
|
BuildTools: []string{},
|
||||||
|
PackageManagers: []string{},
|
||||||
|
Shell: detectShells(),
|
||||||
|
Features: &CapabilityFeatures{
|
||||||
|
ArtifactsV4: false, // Gitea doesn't support v4 artifacts
|
||||||
|
Cache: true,
|
||||||
|
Services: true,
|
||||||
|
CompositeActions: true,
|
||||||
|
},
|
||||||
|
Limitations: []string{
|
||||||
|
"actions/upload-artifact@v4 not supported (use v3 or direct API upload)",
|
||||||
|
"actions/download-artifact@v4 not supported (use v3)",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect Linux distribution
|
||||||
|
if runtime.GOOS == "linux" {
|
||||||
|
cap.Distro = detectLinuxDistro()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect macOS Xcode/iOS
|
||||||
|
if runtime.GOOS == "darwin" {
|
||||||
|
cap.Xcode = detectXcode(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect Docker
|
||||||
|
cap.Docker, cap.ContainerRuntime = detectDocker(ctx, dockerHost)
|
||||||
|
if cap.Docker {
|
||||||
|
cap.DockerCompose = detectDockerCompose(ctx)
|
||||||
|
cap.Features.Services = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect common tools
|
||||||
|
detectTools(ctx, cap)
|
||||||
|
|
||||||
|
// Detect build tools
|
||||||
|
detectBuildTools(ctx, cap)
|
||||||
|
|
||||||
|
// Detect package managers
|
||||||
|
detectPackageManagers(ctx, cap)
|
||||||
|
|
||||||
|
// Detect disk space on the working directory's filesystem
|
||||||
|
cap.Disk = detectDiskSpace(workingDir)
|
||||||
|
|
||||||
|
// Generate suggested labels based on detected capabilities
|
||||||
|
cap.SuggestedLabels = generateSuggestedLabels(cap)
|
||||||
|
|
||||||
|
return cap
|
||||||
|
}
|
||||||
|
|
||||||
|
// detectXcode detects Xcode and iOS development capabilities on macOS
|
||||||
|
func detectXcode(ctx context.Context) *XcodeInfo {
|
||||||
|
timeoutCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// Check for xcodebuild
|
||||||
|
cmd := exec.CommandContext(timeoutCtx, "xcodebuild", "-version")
|
||||||
|
output, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
xcode := &XcodeInfo{}
|
||||||
|
lines := strings.Split(string(output), "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
if strings.HasPrefix(line, "Xcode ") {
|
||||||
|
xcode.Version = strings.TrimPrefix(line, "Xcode ")
|
||||||
|
} else if strings.HasPrefix(line, "Build version ") {
|
||||||
|
xcode.Build = strings.TrimPrefix(line, "Build version ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get available SDKs
|
||||||
|
cmd = exec.CommandContext(timeoutCtx, "xcodebuild", "-showsdks")
|
||||||
|
output, err = cmd.Output()
|
||||||
|
if err == nil {
|
||||||
|
lines = strings.Split(string(output), "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
// Look for SDK lines like "-sdk iphoneos17.0" or "iOS 17.0"
|
||||||
|
if strings.Contains(line, "SDK") || strings.HasPrefix(line, "-sdk") {
|
||||||
|
continue // Skip header lines
|
||||||
|
}
|
||||||
|
if strings.Contains(line, "iOS") || strings.Contains(line, "macOS") ||
|
||||||
|
strings.Contains(line, "watchOS") || strings.Contains(line, "tvOS") ||
|
||||||
|
strings.Contains(line, "visionOS") || strings.Contains(line, "xrOS") {
|
||||||
|
// Extract SDK name
|
||||||
|
if idx := strings.Index(line, "-sdk"); idx != -1 {
|
||||||
|
sdkPart := strings.TrimSpace(line[:idx])
|
||||||
|
if sdkPart != "" {
|
||||||
|
xcode.SDKs = append(xcode.SDKs, sdkPart)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get available simulators
|
||||||
|
cmd = exec.CommandContext(timeoutCtx, "xcrun", "simctl", "list", "devices", "available", "-j")
|
||||||
|
output, err = cmd.Output()
|
||||||
|
if err == nil {
|
||||||
|
var simData struct {
|
||||||
|
Devices map[string][]struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
State string `json:"state"`
|
||||||
|
} `json:"devices"`
|
||||||
|
}
|
||||||
|
if json.Unmarshal(output, &simData) == nil {
|
||||||
|
seen := make(map[string]bool)
|
||||||
|
for runtime, devices := range simData.Devices {
|
||||||
|
if strings.Contains(runtime, "iOS") {
|
||||||
|
for _, dev := range devices {
|
||||||
|
key := dev.Name
|
||||||
|
if !seen[key] {
|
||||||
|
seen[key] = true
|
||||||
|
xcode.Simulators = append(xcode.Simulators, dev.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if xcode.Version == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return xcode
|
||||||
|
}
|
||||||
|
|
||||||
|
// detectLinuxDistro reads /etc/os-release to get distribution info
|
||||||
|
func detectLinuxDistro() *DistroInfo {
|
||||||
|
file, err := os.Open("/etc/os-release")
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
distro := &DistroInfo{}
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
if strings.HasPrefix(line, "ID=") {
|
||||||
|
distro.ID = strings.Trim(strings.TrimPrefix(line, "ID="), "\"")
|
||||||
|
} else if strings.HasPrefix(line, "VERSION_ID=") {
|
||||||
|
distro.VersionID = strings.Trim(strings.TrimPrefix(line, "VERSION_ID="), "\"")
|
||||||
|
} else if strings.HasPrefix(line, "PRETTY_NAME=") {
|
||||||
|
distro.PrettyName = strings.Trim(strings.TrimPrefix(line, "PRETTY_NAME="), "\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if distro.ID == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return distro
|
||||||
|
}
|
||||||
|
|
||||||
|
// generateSuggestedLabels creates industry-standard labels based on capabilities
|
||||||
|
func generateSuggestedLabels(cap *RunnerCapabilities) []string {
|
||||||
|
labels := []string{}
|
||||||
|
seen := make(map[string]bool)
|
||||||
|
|
||||||
|
addLabel := func(label string) {
|
||||||
|
if label != "" && !seen[label] {
|
||||||
|
seen[label] = true
|
||||||
|
labels = append(labels, label)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OS labels
|
||||||
|
switch cap.OS {
|
||||||
|
case "linux":
|
||||||
|
addLabel("linux")
|
||||||
|
addLabel("linux-latest")
|
||||||
|
case "windows":
|
||||||
|
addLabel("windows")
|
||||||
|
addLabel("windows-latest")
|
||||||
|
case "darwin":
|
||||||
|
addLabel("macos")
|
||||||
|
addLabel("macos-latest")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Distro labels (Linux only)
|
||||||
|
if cap.Distro != nil && cap.Distro.ID != "" {
|
||||||
|
distro := strings.ToLower(cap.Distro.ID)
|
||||||
|
addLabel(distro)
|
||||||
|
addLabel(distro + "-latest")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Xcode/iOS labels (macOS only)
|
||||||
|
if cap.Xcode != nil {
|
||||||
|
addLabel("xcode")
|
||||||
|
// Check for SDKs
|
||||||
|
for _, sdk := range cap.Xcode.SDKs {
|
||||||
|
sdkLower := strings.ToLower(sdk)
|
||||||
|
if strings.Contains(sdkLower, "ios") {
|
||||||
|
addLabel("ios")
|
||||||
|
}
|
||||||
|
if strings.Contains(sdkLower, "visionos") || strings.Contains(sdkLower, "xros") {
|
||||||
|
addLabel("visionos")
|
||||||
|
}
|
||||||
|
if strings.Contains(sdkLower, "watchos") {
|
||||||
|
addLabel("watchos")
|
||||||
|
}
|
||||||
|
if strings.Contains(sdkLower, "tvos") {
|
||||||
|
addLabel("tvos")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If simulators available, add simulator label
|
||||||
|
if len(cap.Xcode.Simulators) > 0 {
|
||||||
|
addLabel("ios-simulator")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tool-based labels
|
||||||
|
if _, ok := cap.Tools["dotnet"]; ok {
|
||||||
|
addLabel("dotnet")
|
||||||
|
}
|
||||||
|
if _, ok := cap.Tools["java"]; ok {
|
||||||
|
addLabel("java")
|
||||||
|
}
|
||||||
|
if _, ok := cap.Tools["node"]; ok {
|
||||||
|
addLabel("node")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build tool labels
|
||||||
|
for _, tool := range cap.BuildTools {
|
||||||
|
switch tool {
|
||||||
|
case "msbuild":
|
||||||
|
addLabel("msbuild")
|
||||||
|
case "visual-studio":
|
||||||
|
addLabel("vs2022") // or detect actual version
|
||||||
|
case "inno-setup":
|
||||||
|
addLabel("inno-setup")
|
||||||
|
case "nsis":
|
||||||
|
addLabel("nsis")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return labels
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToJSON converts capabilities to JSON string for transmission
|
||||||
|
func (c *RunnerCapabilities) ToJSON() string {
|
||||||
|
data, err := json.Marshal(c)
|
||||||
|
if err != nil {
|
||||||
|
return "{}"
|
||||||
|
}
|
||||||
|
return string(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectShells() []string {
|
||||||
|
shells := []string{}
|
||||||
|
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "windows":
|
||||||
|
if _, err := exec.LookPath("pwsh"); err == nil {
|
||||||
|
shells = append(shells, "pwsh")
|
||||||
|
}
|
||||||
|
if _, err := exec.LookPath("powershell"); err == nil {
|
||||||
|
shells = append(shells, "powershell")
|
||||||
|
}
|
||||||
|
shells = append(shells, "cmd")
|
||||||
|
case "darwin":
|
||||||
|
if _, err := exec.LookPath("zsh"); err == nil {
|
||||||
|
shells = append(shells, "zsh")
|
||||||
|
}
|
||||||
|
if _, err := exec.LookPath("bash"); err == nil {
|
||||||
|
shells = append(shells, "bash")
|
||||||
|
}
|
||||||
|
shells = append(shells, "sh")
|
||||||
|
default: // linux and others
|
||||||
|
if _, err := exec.LookPath("bash"); err == nil {
|
||||||
|
shells = append(shells, "bash")
|
||||||
|
}
|
||||||
|
shells = append(shells, "sh")
|
||||||
|
}
|
||||||
|
|
||||||
|
return shells
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectDocker(ctx context.Context, dockerHost string) (bool, string) {
|
||||||
|
opts := []client.Opt{client.FromEnv}
|
||||||
|
if dockerHost != "" {
|
||||||
|
opts = append(opts, client.WithHost(dockerHost))
|
||||||
|
}
|
||||||
|
|
||||||
|
cli, err := client.NewClientWithOpts(opts...)
|
||||||
|
if err != nil {
|
||||||
|
return false, ""
|
||||||
|
}
|
||||||
|
defer cli.Close()
|
||||||
|
|
||||||
|
timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
_, err = cli.Ping(timeoutCtx)
|
||||||
|
if err != nil {
|
||||||
|
return false, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it's podman or docker
|
||||||
|
info, err := cli.Info(timeoutCtx)
|
||||||
|
if err == nil {
|
||||||
|
if strings.Contains(strings.ToLower(info.Name), "podman") {
|
||||||
|
return true, "podman"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, "docker"
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectDockerCompose(ctx context.Context) bool {
|
||||||
|
// Check for docker compose v2 (docker compose)
|
||||||
|
cmd := exec.CommandContext(ctx, "docker", "compose", "version")
|
||||||
|
if err := cmd.Run(); err == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for docker-compose v1
|
||||||
|
if _, err := exec.LookPath("docker-compose"); err == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectTools(ctx context.Context, cap *RunnerCapabilities) {
|
||||||
|
toolDetectors := map[string]func(context.Context) []string{
|
||||||
|
"node": detectNodeVersions,
|
||||||
|
"go": detectGoVersions,
|
||||||
|
"python": detectPythonVersions,
|
||||||
|
"java": detectJavaVersions,
|
||||||
|
"dotnet": detectDotnetVersions,
|
||||||
|
"rust": detectRustVersions,
|
||||||
|
"ruby": detectRubyVersions,
|
||||||
|
"php": detectPHPVersions,
|
||||||
|
"swift": detectSwiftVersions,
|
||||||
|
"kotlin": detectKotlinVersions,
|
||||||
|
"flutter": detectFlutterVersions,
|
||||||
|
"dart": detectDartVersions,
|
||||||
|
"powershell": detectPowerShellVersions,
|
||||||
|
}
|
||||||
|
|
||||||
|
for tool, detector := range toolDetectors {
|
||||||
|
if versions := detector(ctx); len(versions) > 0 {
|
||||||
|
cap.Tools[tool] = versions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect additional tools that just need presence check
|
||||||
|
simpleTools := map[string]string{
|
||||||
|
"git": "git",
|
||||||
|
"cmake": "cmake",
|
||||||
|
"make": "make",
|
||||||
|
"ninja": "ninja",
|
||||||
|
"gradle": "gradle",
|
||||||
|
"maven": "mvn",
|
||||||
|
"npm": "npm",
|
||||||
|
"yarn": "yarn",
|
||||||
|
"pnpm": "pnpm",
|
||||||
|
"cargo": "cargo",
|
||||||
|
"pip": "pip3",
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, cmd := range simpleTools {
|
||||||
|
if v := detectSimpleToolVersion(ctx, cmd); v != "" {
|
||||||
|
cap.Tools[name] = []string{v}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectBuildTools(ctx context.Context, cap *RunnerCapabilities) {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "windows":
|
||||||
|
detectWindowsBuildTools(ctx, cap)
|
||||||
|
case "darwin":
|
||||||
|
detectMacOSBuildTools(ctx, cap)
|
||||||
|
case "linux":
|
||||||
|
detectLinuxBuildTools(ctx, cap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectWindowsBuildTools(ctx context.Context, cap *RunnerCapabilities) {
|
||||||
|
// Check for Visual Studio via vswhere
|
||||||
|
vswherePaths := []string{
|
||||||
|
`C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe`,
|
||||||
|
`C:\Program Files\Microsoft Visual Studio\Installer\vswhere.exe`,
|
||||||
|
}
|
||||||
|
for _, vswhere := range vswherePaths {
|
||||||
|
if _, err := os.Stat(vswhere); err == nil {
|
||||||
|
cmd := exec.CommandContext(ctx, vswhere, "-latest", "-property", "displayName")
|
||||||
|
if output, err := cmd.Output(); err == nil && len(output) > 0 {
|
||||||
|
cap.BuildTools = append(cap.BuildTools, "visual-studio")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for MSBuild
|
||||||
|
msbuildPaths := []string{
|
||||||
|
`C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\MSBuild.exe`,
|
||||||
|
`C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\MSBuild.exe`,
|
||||||
|
`C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\MSBuild.exe`,
|
||||||
|
`C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\MSBuild.exe`,
|
||||||
|
`C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\MSBuild\Current\Bin\MSBuild.exe`,
|
||||||
|
`C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe`,
|
||||||
|
}
|
||||||
|
for _, msbuild := range msbuildPaths {
|
||||||
|
if _, err := os.Stat(msbuild); err == nil {
|
||||||
|
cap.BuildTools = append(cap.BuildTools, "msbuild")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for Inno Setup
|
||||||
|
innoSetupPaths := []string{
|
||||||
|
`C:\Program Files (x86)\Inno Setup 6\ISCC.exe`,
|
||||||
|
`C:\Program Files\Inno Setup 6\ISCC.exe`,
|
||||||
|
`C:\Program Files (x86)\Inno Setup 5\ISCC.exe`,
|
||||||
|
`C:\Program Files\Inno Setup 5\ISCC.exe`,
|
||||||
|
}
|
||||||
|
for _, iscc := range innoSetupPaths {
|
||||||
|
if _, err := os.Stat(iscc); err == nil {
|
||||||
|
cap.BuildTools = append(cap.BuildTools, "inno-setup")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Also check PATH
|
||||||
|
if _, err := exec.LookPath("iscc"); err == nil {
|
||||||
|
if !contains(cap.BuildTools, "inno-setup") {
|
||||||
|
cap.BuildTools = append(cap.BuildTools, "inno-setup")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for NSIS
|
||||||
|
nsisPaths := []string{
|
||||||
|
`C:\Program Files (x86)\NSIS\makensis.exe`,
|
||||||
|
`C:\Program Files\NSIS\makensis.exe`,
|
||||||
|
}
|
||||||
|
for _, nsis := range nsisPaths {
|
||||||
|
if _, err := os.Stat(nsis); err == nil {
|
||||||
|
cap.BuildTools = append(cap.BuildTools, "nsis")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, err := exec.LookPath("makensis"); err == nil {
|
||||||
|
if !contains(cap.BuildTools, "nsis") {
|
||||||
|
cap.BuildTools = append(cap.BuildTools, "nsis")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for WiX Toolset
|
||||||
|
wixPaths := []string{
|
||||||
|
`C:\Program Files (x86)\WiX Toolset v3.11\bin\candle.exe`,
|
||||||
|
`C:\Program Files (x86)\WiX Toolset v3.14\bin\candle.exe`,
|
||||||
|
}
|
||||||
|
for _, wix := range wixPaths {
|
||||||
|
if _, err := os.Stat(wix); err == nil {
|
||||||
|
cap.BuildTools = append(cap.BuildTools, "wix")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for signtool (Windows SDK)
|
||||||
|
signtoolPaths, _ := filepath.Glob(`C:\Program Files (x86)\Windows Kits\10\bin\*\x64\signtool.exe`)
|
||||||
|
if len(signtoolPaths) > 0 {
|
||||||
|
cap.BuildTools = append(cap.BuildTools, "signtool")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectMacOSBuildTools(ctx context.Context, cap *RunnerCapabilities) {
|
||||||
|
// Check for xcpretty
|
||||||
|
if _, err := exec.LookPath("xcpretty"); err == nil {
|
||||||
|
cap.BuildTools = append(cap.BuildTools, "xcpretty")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for fastlane
|
||||||
|
if _, err := exec.LookPath("fastlane"); err == nil {
|
||||||
|
cap.BuildTools = append(cap.BuildTools, "fastlane")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for CocoaPods
|
||||||
|
if _, err := exec.LookPath("pod"); err == nil {
|
||||||
|
cap.BuildTools = append(cap.BuildTools, "cocoapods")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for Carthage
|
||||||
|
if _, err := exec.LookPath("carthage"); err == nil {
|
||||||
|
cap.BuildTools = append(cap.BuildTools, "carthage")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for SwiftLint
|
||||||
|
if _, err := exec.LookPath("swiftlint"); err == nil {
|
||||||
|
cap.BuildTools = append(cap.BuildTools, "swiftlint")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for create-dmg or similar
|
||||||
|
if _, err := exec.LookPath("create-dmg"); err == nil {
|
||||||
|
cap.BuildTools = append(cap.BuildTools, "create-dmg")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for Packages (packagesbuild)
|
||||||
|
if _, err := exec.LookPath("packagesbuild"); err == nil {
|
||||||
|
cap.BuildTools = append(cap.BuildTools, "packages")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for pkgbuild (built-in)
|
||||||
|
if _, err := exec.LookPath("pkgbuild"); err == nil {
|
||||||
|
cap.BuildTools = append(cap.BuildTools, "pkgbuild")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for codesign (built-in)
|
||||||
|
if _, err := exec.LookPath("codesign"); err == nil {
|
||||||
|
cap.BuildTools = append(cap.BuildTools, "codesign")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for notarytool (built-in with Xcode)
|
||||||
|
if _, err := exec.LookPath("notarytool"); err == nil {
|
||||||
|
cap.BuildTools = append(cap.BuildTools, "notarytool")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectLinuxBuildTools(ctx context.Context, cap *RunnerCapabilities) {
|
||||||
|
// Check for common Linux build tools
|
||||||
|
tools := []string{
|
||||||
|
"gcc", "g++", "clang", "clang++",
|
||||||
|
"autoconf", "automake", "libtool",
|
||||||
|
"pkg-config", "meson",
|
||||||
|
"dpkg-deb", "rpmbuild", "fpm",
|
||||||
|
"appimage-builder", "linuxdeploy",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tool := range tools {
|
||||||
|
if _, err := exec.LookPath(tool); err == nil {
|
||||||
|
cap.BuildTools = append(cap.BuildTools, tool)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectPackageManagers(ctx context.Context, cap *RunnerCapabilities) {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "windows":
|
||||||
|
if _, err := exec.LookPath("choco"); err == nil {
|
||||||
|
cap.PackageManagers = append(cap.PackageManagers, "chocolatey")
|
||||||
|
}
|
||||||
|
if _, err := exec.LookPath("scoop"); err == nil {
|
||||||
|
cap.PackageManagers = append(cap.PackageManagers, "scoop")
|
||||||
|
}
|
||||||
|
if _, err := exec.LookPath("winget"); err == nil {
|
||||||
|
cap.PackageManagers = append(cap.PackageManagers, "winget")
|
||||||
|
}
|
||||||
|
case "darwin":
|
||||||
|
if _, err := exec.LookPath("brew"); err == nil {
|
||||||
|
cap.PackageManagers = append(cap.PackageManagers, "homebrew")
|
||||||
|
}
|
||||||
|
if _, err := exec.LookPath("port"); err == nil {
|
||||||
|
cap.PackageManagers = append(cap.PackageManagers, "macports")
|
||||||
|
}
|
||||||
|
case "linux":
|
||||||
|
if _, err := exec.LookPath("apt"); err == nil {
|
||||||
|
cap.PackageManagers = append(cap.PackageManagers, "apt")
|
||||||
|
}
|
||||||
|
if _, err := exec.LookPath("yum"); err == nil {
|
||||||
|
cap.PackageManagers = append(cap.PackageManagers, "yum")
|
||||||
|
}
|
||||||
|
if _, err := exec.LookPath("dnf"); err == nil {
|
||||||
|
cap.PackageManagers = append(cap.PackageManagers, "dnf")
|
||||||
|
}
|
||||||
|
if _, err := exec.LookPath("pacman"); err == nil {
|
||||||
|
cap.PackageManagers = append(cap.PackageManagers, "pacman")
|
||||||
|
}
|
||||||
|
if _, err := exec.LookPath("zypper"); err == nil {
|
||||||
|
cap.PackageManagers = append(cap.PackageManagers, "zypper")
|
||||||
|
}
|
||||||
|
if _, err := exec.LookPath("apk"); err == nil {
|
||||||
|
cap.PackageManagers = append(cap.PackageManagers, "apk")
|
||||||
|
}
|
||||||
|
if _, err := exec.LookPath("snap"); err == nil {
|
||||||
|
cap.PackageManagers = append(cap.PackageManagers, "snap")
|
||||||
|
}
|
||||||
|
if _, err := exec.LookPath("flatpak"); err == nil {
|
||||||
|
cap.PackageManagers = append(cap.PackageManagers, "flatpak")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectNodeVersions(ctx context.Context) []string {
|
||||||
|
return detectToolVersion(ctx, "node", "--version", "v")
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectGoVersions(ctx context.Context) []string {
|
||||||
|
return detectToolVersion(ctx, "go", "version", "go")
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectPythonVersions(ctx context.Context) []string {
|
||||||
|
versions := []string{}
|
||||||
|
|
||||||
|
// Try python3 first
|
||||||
|
if v := detectToolVersion(ctx, "python3", "--version", "Python "); len(v) > 0 {
|
||||||
|
versions = append(versions, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also try python
|
||||||
|
if v := detectToolVersion(ctx, "python", "--version", "Python "); len(v) > 0 {
|
||||||
|
for _, ver := range v {
|
||||||
|
if !contains(versions, ver) {
|
||||||
|
versions = append(versions, ver)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return versions
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectJavaVersions(ctx context.Context) []string {
|
||||||
|
cmd := exec.CommandContext(ctx, "java", "-version")
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
lines := strings.Split(string(output), "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
if strings.Contains(line, "version") {
|
||||||
|
start := strings.Index(line, "\"")
|
||||||
|
end := strings.LastIndex(line, "\"")
|
||||||
|
if start != -1 && end > start {
|
||||||
|
version := line[start+1 : end]
|
||||||
|
parts := strings.Split(version, ".")
|
||||||
|
if len(parts) > 0 {
|
||||||
|
if parts[0] == "1" && len(parts) > 1 {
|
||||||
|
return []string{parts[1]}
|
||||||
|
}
|
||||||
|
return []string{parts[0]}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectDotnetVersions(ctx context.Context) []string {
|
||||||
|
cmd := exec.CommandContext(ctx, "dotnet", "--list-sdks")
|
||||||
|
output, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
versions := []string{}
|
||||||
|
lines := strings.Split(string(output), "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
parts := strings.Split(line, " ")
|
||||||
|
if len(parts) > 0 {
|
||||||
|
version := parts[0]
|
||||||
|
major := strings.Split(version, ".")[0]
|
||||||
|
if !contains(versions, major) {
|
||||||
|
versions = append(versions, major)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return versions
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectRustVersions(ctx context.Context) []string {
|
||||||
|
return detectToolVersion(ctx, "rustc", "--version", "rustc ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectRubyVersions(ctx context.Context) []string {
|
||||||
|
return detectToolVersion(ctx, "ruby", "--version", "ruby ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectPHPVersions(ctx context.Context) []string {
|
||||||
|
return detectToolVersion(ctx, "php", "--version", "PHP ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectSwiftVersions(ctx context.Context) []string {
|
||||||
|
return detectToolVersion(ctx, "swift", "--version", "Swift version ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectKotlinVersions(ctx context.Context) []string {
|
||||||
|
return detectToolVersion(ctx, "kotlin", "-version", "Kotlin version ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectFlutterVersions(ctx context.Context) []string {
|
||||||
|
return detectToolVersion(ctx, "flutter", "--version", "Flutter ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectDartVersions(ctx context.Context) []string {
|
||||||
|
return detectToolVersion(ctx, "dart", "--version", "Dart SDK version: ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectPowerShellVersions(ctx context.Context) []string {
|
||||||
|
versions := []string{}
|
||||||
|
|
||||||
|
// Check for pwsh (PowerShell Core / PowerShell 7+)
|
||||||
|
if v := detectPwshVersion(ctx, "pwsh"); v != "" {
|
||||||
|
versions = append(versions, "pwsh:"+v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for powershell (Windows PowerShell 5.x)
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
if v := detectPwshVersion(ctx, "powershell"); v != "" {
|
||||||
|
versions = append(versions, "powershell:"+v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return versions
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectPwshVersion(ctx context.Context, cmd string) string {
|
||||||
|
timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// Use -Command to get version
|
||||||
|
var c *exec.Cmd
|
||||||
|
if cmd == "pwsh" {
|
||||||
|
c = exec.CommandContext(timeoutCtx, cmd, "-Command", "$PSVersionTable.PSVersion.ToString()")
|
||||||
|
} else {
|
||||||
|
c = exec.CommandContext(timeoutCtx, cmd, "-Command", "$PSVersionTable.PSVersion.ToString()")
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := c.Output()
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
version := strings.TrimSpace(string(output))
|
||||||
|
// Return major.minor
|
||||||
|
parts := strings.Split(version, ".")
|
||||||
|
if len(parts) >= 2 {
|
||||||
|
return parts[0] + "." + parts[1]
|
||||||
|
}
|
||||||
|
return version
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectSimpleToolVersion(ctx context.Context, cmd string) string {
|
||||||
|
if _, err := exec.LookPath(cmd); err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
c := exec.CommandContext(timeoutCtx, cmd, "--version")
|
||||||
|
output, err := c.Output()
|
||||||
|
if err != nil {
|
||||||
|
// Try without --version for tools that don't support it
|
||||||
|
return "installed"
|
||||||
|
}
|
||||||
|
|
||||||
|
line := strings.TrimSpace(strings.Split(string(output), "\n")[0])
|
||||||
|
// Extract version number if possible
|
||||||
|
parts := strings.Fields(line)
|
||||||
|
for _, part := range parts {
|
||||||
|
// Look for something that looks like a version
|
||||||
|
if len(part) > 0 && (part[0] >= '0' && part[0] <= '9' || part[0] == 'v') {
|
||||||
|
return strings.TrimPrefix(part, "v")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "installed"
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectToolVersion(ctx context.Context, cmd string, args string, prefix string) []string {
|
||||||
|
timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
c := exec.CommandContext(timeoutCtx, cmd, args)
|
||||||
|
output, err := c.Output()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
line := strings.TrimSpace(string(output))
|
||||||
|
if prefix != "" {
|
||||||
|
if idx := strings.Index(line, prefix); idx != -1 {
|
||||||
|
line = line[idx+len(prefix):]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.Fields(line)
|
||||||
|
if len(parts) > 0 {
|
||||||
|
version := parts[0]
|
||||||
|
version = strings.TrimPrefix(version, "v")
|
||||||
|
vparts := strings.Split(version, ".")
|
||||||
|
if len(vparts) >= 2 {
|
||||||
|
return []string{vparts[0] + "." + vparts[1]}
|
||||||
|
}
|
||||||
|
return []string{vparts[0]}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func contains(slice []string, item string) bool {
|
||||||
|
for _, s := range slice {
|
||||||
|
if s == item {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
43
internal/pkg/envcheck/disk_unix.go
Normal file
43
internal/pkg/envcheck/disk_unix.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
//go:build unix
|
||||||
|
|
||||||
|
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package envcheck
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// detectDiskSpace detects disk space on the specified path's filesystem (Unix version)
|
||||||
|
// If path is empty, defaults to "/"
|
||||||
|
func detectDiskSpace(path string) *DiskInfo {
|
||||||
|
if path == "" {
|
||||||
|
path = "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
var stat unix.Statfs_t
|
||||||
|
|
||||||
|
err := unix.Statfs(path, &stat)
|
||||||
|
if err != nil {
|
||||||
|
// Fallback to root if the path doesn't exist
|
||||||
|
err = unix.Statfs("/", &stat)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
path = "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
total := stat.Blocks * uint64(stat.Bsize)
|
||||||
|
free := stat.Bavail * uint64(stat.Bsize)
|
||||||
|
used := total - free
|
||||||
|
usedPercent := float64(used) / float64(total) * 100
|
||||||
|
|
||||||
|
return &DiskInfo{
|
||||||
|
Path: path,
|
||||||
|
Total: total,
|
||||||
|
Free: free,
|
||||||
|
Used: used,
|
||||||
|
UsedPercent: usedPercent,
|
||||||
|
}
|
||||||
|
}
|
||||||
57
internal/pkg/envcheck/disk_windows.go
Normal file
57
internal/pkg/envcheck/disk_windows.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package envcheck
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
// detectDiskSpace detects disk space on the specified path's drive (Windows version)
|
||||||
|
// If path is empty, defaults to "C:\"
|
||||||
|
func detectDiskSpace(path string) *DiskInfo {
|
||||||
|
if path == "" {
|
||||||
|
path = "C:\\"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve to absolute path
|
||||||
|
absPath, err := filepath.Abs(path)
|
||||||
|
if err != nil {
|
||||||
|
absPath = "C:\\"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract drive letter (e.g., "D:\" from "D:\builds\runner")
|
||||||
|
drivePath := filepath.VolumeName(absPath) + "\\"
|
||||||
|
if drivePath == "\\" {
|
||||||
|
drivePath = "C:\\"
|
||||||
|
}
|
||||||
|
|
||||||
|
var freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes uint64
|
||||||
|
|
||||||
|
pathPtr := windows.StringToUTF16Ptr(drivePath)
|
||||||
|
err = windows.GetDiskFreeSpaceEx(pathPtr, &freeBytesAvailable, &totalNumberOfBytes, &totalNumberOfFreeBytes)
|
||||||
|
if err != nil {
|
||||||
|
// Fallback to C: drive
|
||||||
|
pathPtr = windows.StringToUTF16Ptr("C:\\")
|
||||||
|
err = windows.GetDiskFreeSpaceEx(pathPtr, &freeBytesAvailable, &totalNumberOfBytes, &totalNumberOfFreeBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
drivePath = "C:\\"
|
||||||
|
}
|
||||||
|
|
||||||
|
used := totalNumberOfBytes - totalNumberOfFreeBytes
|
||||||
|
usedPercent := float64(used) / float64(totalNumberOfBytes) * 100
|
||||||
|
|
||||||
|
return &DiskInfo{
|
||||||
|
Path: drivePath,
|
||||||
|
Total: totalNumberOfBytes,
|
||||||
|
Free: totalNumberOfFreeBytes,
|
||||||
|
Used: used,
|
||||||
|
UsedPercent: usedPercent,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,9 +10,16 @@ import (
|
|||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CheckIfDockerRunning(ctx context.Context) error {
|
func CheckIfDockerRunning(ctx context.Context, configDockerHost string) error {
|
||||||
// TODO: if runner support configures to use docker, we need config.Config to pass in
|
opts := []client.Opt{
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
client.FromEnv,
|
||||||
|
}
|
||||||
|
|
||||||
|
if configDockerHost != "" {
|
||||||
|
opts = append(opts, client.WithHost(configDockerHost))
|
||||||
|
}
|
||||||
|
|
||||||
|
cli, err := client.NewClientWithOpts(opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -20,7 +27,7 @@ func CheckIfDockerRunning(ctx context.Context) error {
|
|||||||
|
|
||||||
_, err = cli.Ping(ctx)
|
_, err = cli.Ping(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot ping the docker daemon, does it running? %w", err)
|
return fmt.Errorf("cannot ping the docker daemon, is it running? %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -55,7 +55,6 @@ func (l Labels) PickPlatform(runsOn []string) string {
|
|||||||
switch label.Schema {
|
switch label.Schema {
|
||||||
case SchemeDocker:
|
case SchemeDocker:
|
||||||
// "//" will be ignored
|
// "//" will be ignored
|
||||||
// TODO maybe we should use 'ubuntu-18.04:docker:node:16-buster' instead
|
|
||||||
platforms[label.Name] = strings.TrimPrefix(label.Arg, "//")
|
platforms[label.Name] = strings.TrimPrefix(label.Arg, "//")
|
||||||
case SchemeHost:
|
case SchemeHost:
|
||||||
platforms[label.Name] = "-self-hosted"
|
platforms[label.Name] = "-self-hosted"
|
||||||
@@ -80,7 +79,7 @@ func (l Labels) PickPlatform(runsOn []string) string {
|
|||||||
// So the runner receives a task with a label that the runner doesn't have,
|
// So the runner receives a task with a label that the runner doesn't have,
|
||||||
// it happens when the user have edited the label of the runner in the web UI.
|
// it happens when the user have edited the label of the runner in the web UI.
|
||||||
// TODO: it may be not correct, what if the runner is used as host mode only?
|
// TODO: it may be not correct, what if the runner is used as host mode only?
|
||||||
return "node:16-bullseye"
|
return "docker.gitea.com/runner-images:ubuntu-latest"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l Labels) Names() []string {
|
func (l Labels) Names() []string {
|
||||||
|
|||||||
@@ -55,9 +55,8 @@ func TestParse(t *testing.T) {
|
|||||||
if tt.wantErr {
|
if tt.wantErr {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
}
|
||||||
|
require.NoError(t, err)
|
||||||
assert.DeepEqual(t, got, tt.want)
|
assert.DeepEqual(t, got, tt.want)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
|
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
|
||||||
retry "github.com/avast/retry-go/v4"
|
"connectrpc.com/connect"
|
||||||
"github.com/bufbuild/connect-go"
|
"github.com/avast/retry-go/v4"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
@@ -47,6 +47,9 @@ func NewReporter(ctx context.Context, cancel context.CancelFunc, client client.C
|
|||||||
if v := task.Context.Fields["token"].GetStringValue(); v != "" {
|
if v := task.Context.Fields["token"].GetStringValue(); v != "" {
|
||||||
oldnew = append(oldnew, v, "***")
|
oldnew = append(oldnew, v, "***")
|
||||||
}
|
}
|
||||||
|
if v := task.Context.Fields["gitea_runtime_token"].GetStringValue(); v != "" {
|
||||||
|
oldnew = append(oldnew, v, "***")
|
||||||
|
}
|
||||||
for _, v := range task.Secrets {
|
for _, v := range task.Secrets {
|
||||||
oldnew = append(oldnew, v, "***")
|
oldnew = append(oldnew, v, "***")
|
||||||
}
|
}
|
||||||
@@ -111,6 +114,9 @@ func (r *Reporter) Fire(entry *log.Entry) error {
|
|||||||
for _, s := range r.state.Steps {
|
for _, s := range r.state.Steps {
|
||||||
if s.Result == runnerv1.Result_RESULT_UNSPECIFIED {
|
if s.Result == runnerv1.Result_RESULT_UNSPECIFIED {
|
||||||
s.Result = runnerv1.Result_RESULT_CANCELLED
|
s.Result = runnerv1.Result_RESULT_CANCELLED
|
||||||
|
if jobResult == runnerv1.Result_RESULT_SKIPPED {
|
||||||
|
s.Result = runnerv1.Result_RESULT_SKIPPED
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,6 +143,12 @@ func (r *Reporter) Fire(entry *log.Entry) error {
|
|||||||
if step.StartedAt == nil {
|
if step.StartedAt == nil {
|
||||||
step.StartedAt = timestamppb.New(timestamp)
|
step.StartedAt = timestamppb.New(timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Force reporting log errors as raw output to prevent silent failures
|
||||||
|
if entry.Level == log.ErrorLevel {
|
||||||
|
entry.Data["raw_output"] = true
|
||||||
|
}
|
||||||
|
|
||||||
if v, ok := entry.Data["raw_output"]; ok {
|
if v, ok := entry.Data["raw_output"]; ok {
|
||||||
if rawOutput, ok := v.(bool); ok && rawOutput {
|
if rawOutput, ok := v.(bool); ok && rawOutput {
|
||||||
if row := r.parseLogRow(entry); row != nil {
|
if row := r.parseLogRow(entry); row != nil {
|
||||||
@@ -418,7 +430,7 @@ func (r *Reporter) parseLogRow(entry *log.Entry) *runnerv1.LogRow {
|
|||||||
|
|
||||||
return &runnerv1.LogRow{
|
return &runnerv1.LogRow{
|
||||||
Time: timestamppb.New(entry.Time),
|
Time: timestamppb.New(entry.Time),
|
||||||
Content: content,
|
Content: strings.ToValidUTF8(content, "?"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
|
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
|
||||||
connect_go "github.com/bufbuild/connect-go"
|
connect_go "connectrpc.com/connect"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
|
|||||||
6
renovate.json5
Normal file
6
renovate.json5
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
|
"extends": [
|
||||||
|
"local>gitea/renovate-config"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# wait for docker daemon
|
|
||||||
while ! nc -z localhost 2376 </dev/null; do
|
|
||||||
echo 'waiting for docker daemon...'
|
|
||||||
sleep 5
|
|
||||||
done
|
|
||||||
|
|
||||||
. /opt/act/run.sh
|
|
||||||
@@ -6,6 +6,8 @@ fi
|
|||||||
|
|
||||||
cd /data
|
cd /data
|
||||||
|
|
||||||
|
RUNNER_STATE_FILE=${RUNNER_STATE_FILE:-'.runner'}
|
||||||
|
|
||||||
CONFIG_ARG=""
|
CONFIG_ARG=""
|
||||||
if [[ ! -z "${CONFIG_FILE}" ]]; then
|
if [[ ! -z "${CONFIG_FILE}" ]]; then
|
||||||
CONFIG_ARG="--config ${CONFIG_FILE}"
|
CONFIG_ARG="--config ${CONFIG_FILE}"
|
||||||
@@ -14,10 +16,23 @@ EXTRA_ARGS=""
|
|||||||
if [[ ! -z "${GITEA_RUNNER_LABELS}" ]]; then
|
if [[ ! -z "${GITEA_RUNNER_LABELS}" ]]; then
|
||||||
EXTRA_ARGS="${EXTRA_ARGS} --labels ${GITEA_RUNNER_LABELS}"
|
EXTRA_ARGS="${EXTRA_ARGS} --labels ${GITEA_RUNNER_LABELS}"
|
||||||
fi
|
fi
|
||||||
|
if [[ ! -z "${GITEA_RUNNER_EPHEMERAL}" ]]; then
|
||||||
|
EXTRA_ARGS="${EXTRA_ARGS} --ephemeral"
|
||||||
|
fi
|
||||||
|
RUN_ARGS=""
|
||||||
|
if [[ ! -z "${GITEA_RUNNER_ONCE}" ]]; then
|
||||||
|
RUN_ARGS="${RUN_ARGS} --once"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# In case no token is set, it's possible to read the token from a file, i.e. a Docker Secret
|
||||||
|
if [[ -z "${GITEA_RUNNER_REGISTRATION_TOKEN}" ]] && [[ -f "${GITEA_RUNNER_REGISTRATION_TOKEN_FILE}" ]]; then
|
||||||
|
GITEA_RUNNER_REGISTRATION_TOKEN=$(cat "${GITEA_RUNNER_REGISTRATION_TOKEN_FILE}")
|
||||||
|
fi
|
||||||
|
|
||||||
# Use the same ENV variable names as https://github.com/vegardit/docker-gitea-act-runner
|
# Use the same ENV variable names as https://github.com/vegardit/docker-gitea-act-runner
|
||||||
|
test -f "$RUNNER_STATE_FILE" || echo "$RUNNER_STATE_FILE is missing or not a regular file"
|
||||||
|
|
||||||
if [[ ! -s .runner ]]; then
|
if [[ ! -s "$RUNNER_STATE_FILE" ]]; then
|
||||||
try=$((try + 1))
|
try=$((try + 1))
|
||||||
success=0
|
success=0
|
||||||
|
|
||||||
@@ -44,5 +59,6 @@ if [[ ! -s .runner ]]; then
|
|||||||
fi
|
fi
|
||||||
# Prevent reading the token from the act_runner process
|
# Prevent reading the token from the act_runner process
|
||||||
unset GITEA_RUNNER_REGISTRATION_TOKEN
|
unset GITEA_RUNNER_REGISTRATION_TOKEN
|
||||||
|
unset GITEA_RUNNER_REGISTRATION_TOKEN_FILE
|
||||||
|
|
||||||
act_runner daemon ${CONFIG_ARG}
|
exec act_runner daemon ${CONFIG_ARG} ${RUN_ARGS}
|
||||||
|
|||||||
3
scripts/s6/act_runner/finish
Executable file
3
scripts/s6/act_runner/finish
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
exec s6-svscanctl -t /etc/s6
|
||||||
5
scripts/s6/act_runner/run
Executable file
5
scripts/s6/act_runner/run
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
s6-svwait -U /etc/s6/docker
|
||||||
|
|
||||||
|
exec run.sh
|
||||||
6
scripts/s6/docker/data/check
Executable file
6
scripts/s6/docker/data/check
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
if ! docker info &> /dev/null; then
|
||||||
|
echo "Waiting for Docker daemon to start..."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
4
scripts/s6/docker/finish
Executable file
4
scripts/s6/docker/finish
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
exec s6-svscanctl -t /etc/s6
|
||||||
|
|
||||||
1
scripts/s6/docker/notification-fd
Normal file
1
scripts/s6/docker/notification-fd
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3
|
||||||
3
scripts/s6/docker/run
Executable file
3
scripts/s6/docker/run
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
exec s6-notifyoncheck dockerd-entrypoint.sh
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
[supervisord]
|
|
||||||
nodaemon=true
|
|
||||||
logfile=/dev/null
|
|
||||||
logfile_maxbytes=0
|
|
||||||
|
|
||||||
[program:dockerd]
|
|
||||||
command=/usr/local/bin/dockerd-entrypoint.sh
|
|
||||||
|
|
||||||
[program:act_runner]
|
|
||||||
stdout_logfile=/dev/fd/1
|
|
||||||
stdout_logfile_maxbytes=0
|
|
||||||
redirect_stderr=true
|
|
||||||
command=/opt/act/rootless.sh
|
|
||||||
Reference in New Issue
Block a user