Merge branch 'main' into arrange-pipeline-list

This commit is contained in:
6543 2024-11-05 23:52:55 +01:00 committed by GitHub
commit 2e76c671fa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
337 changed files with 12747 additions and 10461 deletions

View file

@ -15,6 +15,7 @@
"apimachinery",
"Archlinux",
"autoincr",
"automerge",
"autoscaler",
"backporting",
"backports",
@ -71,6 +72,8 @@
"gomod",
"gonic",
"GOPATH",
"Gource",
"handlebargh",
"HEALTHCHECK",
"healthz",
"Hetzner",
@ -159,8 +162,10 @@
"seccomp",
"secprofile",
"securecookie",
"selfhosted",
"sess",
"shellescape",
"sigstore",
"Sonatype",
"SSHURL",
"sslmode",
@ -184,6 +189,7 @@
"Traefik",
"tseslint",
"ttlcache",
"TUNEIT",
"Tunnelmole",
"typecheck",
"Typeflag",
@ -195,6 +201,7 @@
"varz",
"Vieter",
"virtualisation",
"visualisation",
"vite",
"vueuse",
"waivable",
@ -230,7 +237,7 @@
"Makefile",
"flake.nix",
"go.mod",
"pipeline/rpc/proto/woodpecker.pb.go",
"**/*.pb.go",
"server/store/datastore/migration/**/*",
"web/components.d.ts",
"web/src/assets/locales/**/*",
@ -238,13 +245,13 @@
"**/testdata/**",
"docs/versioned_docs/",
"package.json",
"91-migrations.md",
// generated
"go.sum",
"flake.lock",
"pnpm-lock.yaml",
"**/node_modules/**/*",
"cmd/server/docs/docs.go",
"renovate.json",
// TODO: remove the following
"docs/**/*.js",
"docs/**/*.ts"

11
.github/pull_request_template.md vendored Normal file
View file

@ -0,0 +1,11 @@
<!--
Please check the following tips:
1. Avoid using force-push and commands that require it (such as `commit --amend` and `rebase origin/main`). This makes it more difficult for the maintainers to review your work. Add new commits on top of the current branch, and merge the new state of `main` into your branch with plain `merge`.
2. Provide a meaningful title for this pull request. It will be used as the commit message when this pull request is merged. Add as many commits as you like with any messages you like, they will be squashed into one commit.
3. If this pull request fixes an issue, refer to the issue with messages like `Closes #1234`, or `Fixes #1234` in the pull description.
4. Please check that you are targeting the `main` branch. Pull requests on release branches are only allowed for backports.
5. Make sure you have read contribution guidelines: https://woodpecker-ci.org/docs/development/getting-started
6. It is recommended to enable "Allow edits by maintainers", so maintainers can help you more easily.
-->

13
.github/renovate.json vendored
View file

@ -1,12 +1,14 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["github>woodpecker-ci/renovate-config"],
"automergeType": "pr",
"enabledManagers": ["woodpecker"],
"customManagers": [
{
"customType": "regex",
"fileMatch": ["shared/constant/constant.go"],
"matchStrings": [
"//\\s*renovate:\\s*datasource=(?<datasource>.*?) depName=(?<depName>.*?)( versioning=(?<versioning>.*?))?\\s+DefaultCloneImage = \"docker.io/woodpeckerci/plugin-git:(?<currentValue>.*)\""
"//\\s*renovate:\\s*datasource=(?<datasource>.*?) depName=(?<depName>.*?)( versioning=(?<versioning>.*?))?\\s+DefaultClonePlugin = \"docker.io/woodpeckerci/plugin-git:(?<currentValue>.*)\""
],
"versioningTemplate": "{{#if versioning}}{{{versioning}}}{{else}}semver{{/if}}"
}
@ -29,8 +31,8 @@
},
{
"groupName": "golang-lang",
"matchPackagePatterns": ["^golang$", "xgo"],
"matchUpdateTypes": ["minor", "patch"]
"matchUpdateTypes": ["minor", "patch"],
"matchPackageNames": ["/^golang$/", "/xgo/"]
},
{
"groupName": "golang-packages",
@ -60,9 +62,10 @@
"matchFileNames": ["docs/**/package.json"]
},
{
"description": "Extract version from xgo container tags",
"matchDatasources": ["docker"],
"matchPackagePatterns": ["xgo"],
"versioning": "regex:^go-(?<major>\\d+)?(\\.(?<minor>\\d+))?(\\.(?<patch>\\d+))$"
"versioning": "regex:^go-(?<major>\\d+)\\.(?<minor>\\d+)\\.x$",
"matchPackageNames": ["/techknowlogick/xgo/"]
}
]
}

1
.lycheeignore Normal file
View file

@ -0,0 +1 @@
https://stackoverflow.com/*

View file

@ -5,16 +5,16 @@ repos:
- id: check-hooks-apply
- id: check-useless-excludes
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
rev: v5.0.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/golangci/golangci-lint
rev: v1.59.1
rev: v1.61.0
hooks:
- id: golangci-lint
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.41.0
rev: v0.42.0
hooks:
- id: markdownlint
exclude: '^(docs/versioned_docs/.*|CHANGELOG.md)$'
@ -24,7 +24,7 @@ repos:
- id: checkmake
exclude: '^docker/Dockerfile.make$' # actually a Dockerfile and not a makefile
- repo: https://github.com/hadolint/hadolint
rev: v2.13.0-beta
rev: v2.13.1-beta
hooks:
- id: hadolint
- repo: https://github.com/pre-commit/mirrors-prettier

View file

@ -2,12 +2,14 @@ when:
- event: tag
- event: pull_request
branch: ${CI_REPO_DEFAULT_BRANCH}
path: Makefile
path:
- Makefile
- .woodpecker/binaries.yaml
variables:
- &golang_image 'docker.io/golang:1.22'
- &node_image 'docker.io/node:22-alpine'
- &xgo_image 'docker.io/techknowlogick/xgo:go-1.22.x'
- &golang_image 'docker.io/golang:1.23'
- &node_image 'docker.io/node:23-alpine'
- &xgo_image 'docker.io/techknowlogick/xgo:go-1.23.1'
# cspell:words bindata netgo
@ -97,7 +99,7 @@ steps:
release:
depends_on:
- checksums
image: woodpeckerci/plugin-release:0.1.0
image: woodpeckerci/plugin-release:0.2.1
settings:
api_key:
from_secret: github_token

View file

@ -1,8 +1,8 @@
variables:
- &golang_image 'docker.io/golang:1.22'
- &node_image 'docker.io/node:22-alpine'
- &xgo_image 'docker.io/techknowlogick/xgo:go-1.22.x'
- &buildx_plugin 'docker.io/woodpeckerci/plugin-docker-buildx:4.1.0'
- &golang_image 'docker.io/golang:1.23'
- &node_image 'docker.io/node:23-alpine'
- &xgo_image 'docker.io/techknowlogick/xgo:go-1.23.1'
- &buildx_plugin 'docker.io/woodpeckerci/plugin-docker-buildx:5.0.0'
- &platforms_release 'linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/386,linux/amd64,linux/ppc64le,linux/riscv64,linux/s390x,freebsd/arm64,freebsd/amd64,openbsd/arm64,openbsd/amd64'
- &platforms_server 'linux/arm/v7,linux/arm64/v8,linux/amd64,linux/ppc64le,linux/riscv64'
- &platforms_preview 'linux/amd64'

View file

@ -1,7 +1,7 @@
variables:
- &golang_image 'docker.io/golang:1.22'
- &node_image 'docker.io/node:21-alpine'
- &alpine_image 'docker.io/alpine:3.19'
- &golang_image 'docker.io/golang:1.23'
- &node_image 'docker.io/node:23-alpine'
- &alpine_image 'docker.io/alpine:3.20'
- path: &when_path
- 'docs/**'
- '.woodpecker/docs.yaml'
@ -60,7 +60,7 @@ steps:
- event: manual
deploy-preview:
image: docker.io/woodpeckerci/plugin-surge-preview:1.3.0
image: docker.io/woodpeckerci/plugin-surge-preview:1.3.2
settings:
path: 'docs/build/'
surge_token:

View file

@ -1,9 +1,8 @@
steps:
release-helper:
image: woodpeckerci/plugin-ready-release-go:1.2.0
pull: true
- name: release-helper
image: woodpeckerci/plugin-ready-release-go:2.0.0
settings:
release_branch: ${CI_REPO_DEFAULT_BRANCH}
release_branch: ${CI_COMMIT_BRANCH}
forge_type: github
git_email: woodpecker-bot@obermui.de
github_token:
@ -11,6 +10,8 @@ steps:
when:
- event: push
branch: ${CI_REPO_DEFAULT_BRANCH}
branch:
- ${CI_REPO_DEFAULT_BRANCH}
- release/*
- event: manual
evaluate: 'TASK == "release-helper"'

View file

@ -6,19 +6,21 @@ when:
- renovate/*
variables:
- &trivy_plugin docker.io/woodpeckerci/plugin-trivy:1.1.0
- &trivy_plugin docker.io/woodpeckerci/plugin-trivy:1.2.0
steps:
backend:
depends_on: []
image: *trivy_plugin
settings:
server: server
skip-dirs: web/,docs/
docs:
depends_on: []
image: *trivy_plugin
settings:
server: server
skip-dirs: node_modules/,plugins/woodpecker-plugins/node_modules/
dir: docs/
@ -26,5 +28,18 @@ steps:
depends_on: []
image: *trivy_plugin
settings:
server: server
skip-dirs: node_modules/
dir: web/
services:
server:
image: *trivy_plugin
# settings:
# service: true
# db-repository: docker.io/aquasec/trivy-db:2
environment:
PLUGIN_SERVICE: 'true'
PLUGIN_DB_REPOSITORY: 'docker.io/aquasec/trivy-db:2'
ports:
- 10000

View file

@ -13,7 +13,7 @@ steps:
branch: renovate/*
- name: spellcheck
image: docker.io/node:22-alpine
image: docker.io/node:23-alpine
depends_on: []
commands:
- corepack enable
@ -23,15 +23,15 @@ steps:
- tree --gitignore -I 012_columns_rename_procs_to_steps.go -I versioned_docs -I '*opensource.svg'| pnpx cspell lint --no-progress stdin
- name: prettier
image: docker.io/woodpeckerci/plugin-prettier:0.1.0
image: docker.io/woodpeckerci/plugin-prettier:0.2.0
depends_on: []
settings:
version: 3.2.5
version: 3.3.3
- name: links
image: docker.io/lycheeverse/lychee:0.15.1
depends_on: []
commands:
- lychee pipeline/frontend/yaml/linter/schema/schema.json
- lychee --exclude localhost docs/docs/
- lychee --exclude localhost docs/src/pages/
- lychee --user-agent "curl/8.4.0" --exclude localhost docs/docs/
- lychee --user-agent "curl/8.4.0" --exclude localhost docs/src/pages/

View file

@ -1,5 +1,5 @@
variables:
- &golang_image 'docker.io/golang:1.22'
- &golang_image 'docker.io/golang:1.23'
- &when
- path: &when_path # related config files
- '.woodpecker/test.yaml'
@ -40,6 +40,7 @@ steps:
- go run go.woodpecker-ci.org/woodpecker/v2/cmd/cli lint
environment:
WOODPECKER_DISABLE_UPDATE_CHECK: true
WOODPECKER_PLUGINS_PRIVILEGED: 'docker.io/woodpeckerci/plugin-docker-buildx:5.0.0'
when:
- event: pull_request
path:
@ -128,7 +129,7 @@ steps:
- test
- sqlite
pull: true
image: docker.io/woodpeckerci/plugin-codecov:2.1.2
image: docker.io/woodpeckerci/plugin-codecov:2.1.5
settings:
files:
- agent-coverage.out
@ -144,7 +145,7 @@ steps:
services:
postgres:
image: docker.io/postgres:16
image: docker.io/postgres:17
ports: ['5432']
environment:
POSTGRES_USER: postgres
@ -152,7 +153,7 @@ services:
when: *when
mysql:
image: docker.io/mysql:8.2.0
image: docker.io/mysql:9.1.0
ports: ['3306']
environment:
MYSQL_DATABASE: test

View file

@ -6,7 +6,7 @@ when:
- renovate/*
variables:
- &node_image 'docker.io/node:22-alpine'
- &node_image 'docker.io/node:23-alpine'
- &when
path:
# related config files
@ -58,6 +58,7 @@ steps:
test:
depends_on:
- install-dependencies
- format-check # wait for it else test artifacts are falsely detected as wrong
image: *node_image
directory: web/
commands:

View file

@ -1,5 +1,71 @@
# Changelog
## [2.7.2](https://github.com/woodpecker-ci/woodpecker/releases/tag/v2.7.2) - 2024-11-03
### Important
To secure your instance, set `WOODPECKER_PLUGINS_PRIVILEGED` to only allow specific versions of the `woodpeckerci/plugin-docker-buildx` plugin, use version 5.0.0 or above. This prevents older, potentially unstable versions from being privileged.
For example, to allow only version 5.0.0, use:
```bash
WOODPECKER_PLUGINS_PRIVILEGED=woodpeckerci/plugin-docker-buildx:5.0.0
```
To allow multiple versions, you can separate them with commas:
```bash
WOODPECKER_PLUGINS_PRIVILEGED=woodpeckerci/plugin-docker-buildx:5.0.0,woodpeckerci/plugin-docker-buildx:5.1.0
```
This setup ensures only specified, stable plugin versions are given privileged access.
Read more about it in [#4213](https://github.com/woodpecker-ci/woodpecker/pull/4213)
### ❤️ Thanks to all contributors! ❤️
@6543, @anbraten, @j04n-f, @pat-s, @qwerty287
### 🔒 Security
- Chore(deps): update dependency vite to v5.4.6 [security] ([#4163](https://github.com/woodpecker-ci/woodpecker/pull/4163)) [[#4187](https://github.com/woodpecker-ci/woodpecker/pull/4187)]
### 🐛 Bug Fixes
- Don't parse forge config files multiple times if no error occured ([#4272](https://github.com/woodpecker-ci/woodpecker/pull/4272)) [[#4273](https://github.com/woodpecker-ci/woodpecker/pull/4273)]
- Fix repo/owner parsing for gitlab ([#4255](https://github.com/woodpecker-ci/woodpecker/pull/4255)) [[#4261](https://github.com/woodpecker-ci/woodpecker/pull/4261)]
- Run queue.process() in background [[#4115](https://github.com/woodpecker-ci/woodpecker/pull/4115)]
- Only update agent.LastWork if not done recently ([#4031](https://github.com/woodpecker-ci/woodpecker/pull/4031)) [[#4100](https://github.com/woodpecker-ci/woodpecker/pull/4100)]
### Misc
- Backport JS dependency updates [[#4189](https://github.com/woodpecker-ci/woodpecker/pull/4189)]
## [2.7.1](https://github.com/woodpecker-ci/woodpecker/releases/tag/v2.7.1) - 2024-09-07
### ❤️ Thanks to all contributors! ❤️
@6543, @anbraten, @j04n-f, @qwerty287
### 🔒 Security
- Lint privileged plugin match and allow to be set empty [[#4084](https://github.com/woodpecker-ci/woodpecker/pull/4084)]
- Allow admins to specify privileged plugins by name **and tag** [[#4076](https://github.com/woodpecker-ci/woodpecker/pull/4076)]
- Warn if using secrets/env with plugin [[#4039](https://github.com/woodpecker-ci/woodpecker/pull/4039)]
### 🐛 Bug Fixes
- Set refspec for gitlab MR [[#4021](https://github.com/woodpecker-ci/woodpecker/pull/4021)]
- Change Bitbucket PR hook to point the source branch, commit & ref [[#3965](https://github.com/woodpecker-ci/woodpecker/pull/3965)]
- Add updated, merged and declined events to bb webhook activation [[#3963](https://github.com/woodpecker-ci/woodpecker/pull/3963)]
- Fix login via navbar [[#3962](https://github.com/woodpecker-ci/woodpecker/pull/3962)]
- Fix panic if forge is unreachable [[#3944](https://github.com/woodpecker-ci/woodpecker/pull/3944)]
- Fix org settings page [[#4093](https://github.com/woodpecker-ci/woodpecker/pull/4093)]
### Misc
- Bump github.com/docker/docker from v24.0.9 to v24.0.9+30 [[#4077](https://github.com/woodpecker-ci/woodpecker/pull/4077)]
## [2.7.0](https://github.com/woodpecker-ci/woodpecker/releases/tag/v2.7.0) - 2024-07-18
### ❤️ Thanks to all contributors! ❤️

View file

@ -39,7 +39,8 @@ CGO_ENABLED ?= 1 # only used to compile server
HAS_GO = $(shell hash go > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
ifeq ($(HAS_GO),GO)
XGO_VERSION ?= go-1.20.x
# renovate: datasource=docker depName=docker.io/techknowlogick/xgo
XGO_VERSION ?= go-1.22.x
CGO_CFLAGS ?= $(shell go env CGO_CFLAGS)
endif
CGO_CFLAGS ?=

View file

@ -43,55 +43,48 @@
</p>
<br/>
Woodpecker is a simple yet powerful CI/CD engine with great extensibility.
Woodpecker is a simple, yet powerful CI/CD engine with great extensibility.
![woodpecker](docs/docs/woodpecker.png)
![woodpecker](docs/woodpecker.png)
## 🫶 Support
## Installation & Resources
Please consider donating and become a backer. 🙏 [[Become a backer](https://opencollective.com/woodpecker-ci#category-CONTRIBUTE)]
Woodpecker can be installed in various ways (see the [Installation Instructions](https://woodpecker-ci.org/docs/administration/getting-started)) and runs with SQLite as database by default.
It requires around 100 MB of RAM (Server) and 30 MB (Agent) at runtime in idle mode.
## Support
You can support the project by becoming a backer on [Open Collective](https://opencollective.com/woodpecker-ci#category-CONTRIBUTE) or via [GitHub Sponsors](https://github.com/sponsors/woodpecker-ci).
<a href="https://opencollective.com/woodpecker-ci" target="_blank"><img src="https://opencollective.com/woodpecker-ci/backers.svg?width=890" alt="Open Collective backers"></a>
## 📖 Documentation
## Documentation
<https://woodpecker-ci.org/>
Our documentation can be found at <https://woodpecker-ci.org/docs/intro>.
## ✨ Contribute
## Translation
See [Contributing Guide](https://github.com/woodpecker-ci/.github/blob/main/CONTRIBUTING.md)
We have a self-hosted [Weblate](https://weblate.org/en/) instance at [translate.woodpecker-ci.org](https://translate.woodpecker-ci.org).
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://woodpecker-ci.org/docs/next/development/getting-started#gitpod)
An overview of the current translation state is available at <https://translate.woodpecker-ci.org/projects/woodpecker-ci/#languages>.
## 📣 Translate
## Public Woodpecker Instances
We use an own [Weblate](https://weblate.org/en/) instance at [translate.woodpecker-ci.org](https://translate.woodpecker-ci.org).
Woodpecker is used as the main CI/CD engine at [Codeberg](https://codeberg.org), an alternative Git hosting platform with a focus on privacy and free software development.
<a href="https://translate.woodpecker-ci.org/engage/woodpecker-ci/">
<img src="https://translate.woodpecker-ci.org/widgets/woodpecker-ci/-/ui/multi-blue.svg" alt="Translation status" />
</a>
## Plugins
## 👋 Who uses Woodpecker?
Woodpecker can be extended via plugins.
The [plugin overview website](https://woodpecker-ci.org/plugins) helps browsing available plugins.
It combines both plugins by the Woodpecker core team and community-maintained ones.
Woodpecker is used by [itself](https://ci.woodpecker-ci.org/woodpecker/woodpecker-ci/), multiple well-known companies, organizations like [Codeberg](https://codeberg.org), hobbyists and many others.
## Star History
Leave a [comment](https://github.com/woodpecker-ci/woodpecker/discussions/2149) if you're using it as well.
Also consider using the topic `WoodpeckerCI` in your repository, so others can learn from your config and use the hashtag `#WoodpeckerCI` when talking about the project on social media!
Here are some places where people mention Woodpecker:
- [GitHub](https://github.com/topics/WoodpeckerCI)
- [Codeberg](https://codeberg.org/explore/repos?q=woodpeckerci&topic=1)
- [Twitter](https://twitter.com/search?q=%23WoodpeckerCI&src=typed_query)
- [Fediverse](https://mastodon.social/tags/WoodpeckerCI)
## ✨ Stars over time
[![Stargazers over time](https://starchart.cc/woodpecker-ci/woodpecker.svg)](https://starchart.cc/woodpecker-ci/woodpecker)
[![Star History Chart](https://api.star-history.com/svg?repos=woodpecker-ci/woodpecker&type=Date)](https://star-history.com/#woodpecker-ci/woodpecker&Date)
## License
Woodpecker is Apache 2.0 licensed with the source files in this repository having a header indicating which license they are under and what copyrights apply.
Woodpecker is Apache 2.0 licensed.
The source files have a header indicating which license they are under and what copyrights apply.
Files under the `docs/` folder are licensed under Creative Commons Attribution-ShareAlike 4.0 International Public License.
Everything in `docs/` is licensed under the Creative Commons Attribution-ShareAlike 4.0 International Public License.

View file

@ -26,19 +26,12 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
)
const (
// Store not more than 1mb in a log-line as 4mb is the limit of a grpc message
// and log-lines needs to be parsed by the browsers later on.
maxLogLineLength = 1024 * 1024 // 1mb
)
func (r *Runner) createLogger(_logger zerolog.Logger, uploads *sync.WaitGroup, workflow *rpc.Workflow) pipeline.Logger {
return func(step *backend.Step, rc io.ReadCloser) error {
defer rc.Close()
logger := _logger.With().
Str("image", step.Image).
Str("workflow_id", workflow.ID).
Logger()
uploads.Add(1)
@ -51,7 +44,7 @@ func (r *Runner) createLogger(_logger zerolog.Logger, uploads *sync.WaitGroup, w
logger.Debug().Msg("log stream opened")
logStream := log.NewLineWriter(r.client, step.UUID, secrets...)
if err := log.CopyLineByLine(logStream, rc, maxLogLineLength); err != nil {
if err := log.CopyLineByLine(logStream, rc, pipeline.MaxLogLineLength); err != nil {
logger.Error().Err(err).Msg("copy limited logStream part")
}

View file

@ -25,29 +25,44 @@ import (
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
grpcproto "google.golang.org/protobuf/proto"
backend "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc/proto"
)
// Set grpc version on compile time to compare against server version response.
const ClientGrpcVersion int32 = proto.Version
const (
// Set grpc version on compile time to compare against server version response.
ClientGrpcVersion int32 = proto.Version
// Maximum size of an outgoing log message.
// Picked to prevent it from going over GRPC size limit (4 MiB) with a large safety margin.
maxLogBatchSize int = 1 * 1024 * 1024
// Maximum amount of time between sending consecutive batched log messages.
// Controls the delay between the CI job generating a log record, and web users receiving it.
maxLogFlushPeriod time.Duration = time.Second
)
type client struct {
client proto.WoodpeckerClient
conn *grpc.ClientConn
logs chan *proto.LogEntry
}
// NewGrpcClient returns a new grpc Client.
func NewGrpcClient(conn *grpc.ClientConn) rpc.Peer {
func NewGrpcClient(ctx context.Context, conn *grpc.ClientConn) rpc.Peer {
client := new(client)
client.client = proto.NewWoodpeckerClient(conn)
client.conn = conn
client.logs = make(chan *proto.LogEntry, 10) // max memory use: 10 lines * 1 MiB
go client.processLogs(ctx)
return client
}
func (c *client) Close() error {
close(c.logs)
return c.conn.Close()
}
@ -72,13 +87,13 @@ func (c *client) Version(ctx context.Context) (*rpc.Version, error) {
}
// Next returns the next workflow in the queue.
func (c *client) Next(ctx context.Context, f rpc.Filter) (*rpc.Workflow, error) {
func (c *client) Next(ctx context.Context, filter rpc.Filter) (*rpc.Workflow, error) {
var res *proto.NextResponse
var err error
retry := c.newBackOff()
req := new(proto.NextRequest)
req.Filter = new(proto.Filter)
req.Filter.Labels = f.Labels
req.Filter.Labels = filter.Labels
for {
res, err = c.client.Next(ctx, req)
if err == nil {
@ -135,10 +150,10 @@ func (c *client) Next(ctx context.Context, f rpc.Filter) (*rpc.Workflow, error)
}
// Wait blocks until the workflow is complete.
func (c *client) Wait(ctx context.Context, id string) (err error) {
func (c *client) Wait(ctx context.Context, workflowID string) (err error) {
retry := c.newBackOff()
req := new(proto.WaitRequest)
req.Id = id
req.Id = workflowID
for {
_, err = c.client.Wait(ctx, req)
if err == nil {
@ -273,10 +288,10 @@ func (c *client) Done(ctx context.Context, workflowID string, state rpc.Workflow
}
// Extend extends the workflow deadline.
func (c *client) Extend(ctx context.Context, id string) (err error) {
func (c *client) Extend(ctx context.Context, workflowID string) (err error) {
retry := c.newBackOff()
req := new(proto.ExtendRequest)
req.Id = id
req.Id = workflowID
for {
_, err = c.client.Extend(ctx, req)
if err == nil {
@ -317,10 +332,10 @@ func (c *client) Extend(ctx context.Context, id string) (err error) {
}
// Update updates the workflow state.
func (c *client) Update(ctx context.Context, id string, state rpc.StepState) (err error) {
func (c *client) Update(ctx context.Context, workflowID string, state rpc.StepState) (err error) {
retry := c.newBackOff()
req := new(proto.UpdateRequest)
req.Id = id
req.Id = workflowID
req.State = new(proto.StepState)
req.State.StepUuid = state.StepUUID
req.State.Started = state.Started
@ -367,18 +382,69 @@ func (c *client) Update(ctx context.Context, id string, state rpc.StepState) (er
return nil
}
// Log writes the workflow log entry.
func (c *client) Log(ctx context.Context, logEntry *rpc.LogEntry) (err error) {
retry := c.newBackOff()
req := new(proto.LogRequest)
req.LogEntry = new(proto.LogEntry)
req.LogEntry.StepUuid = logEntry.StepUUID
req.LogEntry.Data = logEntry.Data
req.LogEntry.Line = int32(logEntry.Line)
req.LogEntry.Time = logEntry.Time
req.LogEntry.Type = int32(logEntry.Type)
// EnqueueLog queues the log entry to be written in a batch later.
func (c *client) EnqueueLog(logEntry *rpc.LogEntry) {
c.logs <- &proto.LogEntry{
StepUuid: logEntry.StepUUID,
Data: logEntry.Data,
Line: int32(logEntry.Line),
Time: logEntry.Time,
Type: int32(logEntry.Type),
}
}
func (c *client) processLogs(ctx context.Context) {
var entries []*proto.LogEntry
var bytes int
send := func() {
if len(entries) == 0 {
return
}
log.Debug().
Int("entries", len(entries)).
Int("bytes", bytes).
Msg("log drain: sending queued logs")
if err := c.sendLogs(ctx, entries); err != nil {
log.Error().Err(err).Msg("log drain: could not send logs to server")
}
// even if send failed, we don't have infinite memory; retry has already been used
entries = entries[:0]
bytes = 0
}
// ctx.Done() is covered by the log channel being closed
for {
_, err = c.client.Log(ctx, req)
select {
case entry, ok := <-c.logs:
if !ok {
log.Info().Msg("log drain: channel closed")
send()
return
}
entries = append(entries, entry)
bytes += grpcproto.Size(entry) // cspell:words grpcproto
if bytes >= maxLogBatchSize {
send()
}
case <-time.After(maxLogFlushPeriod):
send()
}
}
}
func (c *client) sendLogs(ctx context.Context, entries []*proto.LogEntry) error {
req := &proto.LogRequest{LogEntries: entries}
retry := c.newBackOff()
for {
_, err := c.client.Log(ctx, req)
if err == nil {
break
}
@ -414,12 +480,15 @@ func (c *client) Log(ctx context.Context, logEntry *rpc.LogEntry) (err error) {
return nil
}
func (c *client) RegisterAgent(ctx context.Context, platform, backend, version string, capacity int) (int64, error) {
func (c *client) RegisterAgent(ctx context.Context, info rpc.AgentInfo) (int64, error) {
req := new(proto.RegisterAgentRequest)
req.Platform = platform
req.Backend = backend
req.Version = version
req.Capacity = int32(capacity)
req.Info = &proto.AgentInfo{
Platform: info.Platform,
Backend: info.Backend,
Version: info.Version,
Capacity: int32(info.Capacity),
CustomLabels: info.CustomLabels,
}
res, err := c.client.RegisterAgent(ctx, req)
return res.GetAgentId(), err

View file

@ -28,6 +28,7 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/pipeline"
backend "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
"go.woodpecker-ci.org/woodpecker/v2/shared/constant"
"go.woodpecker-ci.org/woodpecker/v2/shared/utils"
)
@ -105,7 +106,6 @@ func (r *Runner) Run(runnerCtx, shutdownCtx context.Context) error { //nolint:co
if err := r.client.Wait(workflowCtx, workflow.ID); err != nil {
canceled = true
logger.Warn().Err(err).Msg("cancel signal received")
cancel()
} else {
logger.Debug().Msg("done listening for cancel signal")
@ -117,11 +117,10 @@ func (r *Runner) Run(runnerCtx, shutdownCtx context.Context) error { //nolint:co
select {
case <-workflowCtx.Done():
logger.Debug().Msg("pipeline done")
return
case <-time.After(time.Minute):
logger.Debug().Msg("pipeline lease renewed")
case <-time.After(constant.TaskTimeout / 3):
logger.Debug().Msg("pipeline lease renewed")
if err := r.client.Extend(workflowCtx, workflow.ID); err != nil {
log.Error().Err(err).Msg("extending pipeline deadline failed")
}
@ -144,7 +143,7 @@ func (r *Runner) Run(runnerCtx, shutdownCtx context.Context) error { //nolint:co
pipeline.WithContext(workflowCtx),
pipeline.WithTaskUUID(fmt.Sprint(workflow.ID)),
pipeline.WithLogger(r.createLogger(logger, &uploads, workflow)),
pipeline.WithTracer(r.createTracer(ctxMeta, logger, workflow)),
pipeline.WithTracer(r.createTracer(ctxMeta, &uploads, logger, workflow)),
pipeline.WithBackend(*r.backend),
pipeline.WithDescription(map[string]string{
"workflow_id": workflow.ID,
@ -170,9 +169,9 @@ func (r *Runner) Run(runnerCtx, shutdownCtx context.Context) error { //nolint:co
Bool("canceled", canceled).
Msg("workflow finished")
logger.Debug().Msg("uploading logs ...")
logger.Debug().Msg("uploading logs and traces / states ...")
uploads.Wait()
logger.Debug().Msg("uploaded logs")
logger.Debug().Msg("uploaded logs and traces / states")
logger.Debug().
Str("error", state.Error).

View file

@ -18,6 +18,7 @@ import (
"context"
"runtime"
"strconv"
"sync"
"time"
"github.com/rs/zerolog"
@ -26,11 +27,13 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
)
func (r *Runner) createTracer(ctxMeta context.Context, logger zerolog.Logger, workflow *rpc.Workflow) pipeline.TraceFunc {
func (r *Runner) createTracer(ctxMeta context.Context, uploads *sync.WaitGroup, logger zerolog.Logger, workflow *rpc.Workflow) pipeline.TraceFunc {
return func(state *pipeline.State) error {
uploads.Add(1)
stepLogger := logger.With().
Str("image", state.Pipeline.Step.Image).
Str("workflowID", workflow.ID).
Str("workflow_id", workflow.ID).
Err(state.Process.Error).
Int("exit_code", state.Process.ExitCode).
Bool("exited", state.Process.Exited).
@ -57,6 +60,7 @@ func (r *Runner) createTracer(ctxMeta context.Context, logger zerolog.Logger, wo
}
stepLogger.Debug().Msg("update step status complete")
uploads.Done()
}()
if state.Process.Exited {
return nil
@ -68,21 +72,12 @@ func (r *Runner) createTracer(ctxMeta context.Context, logger zerolog.Logger, wo
// TODO: find better way to update this state and move it to pipeline to have the same env in cli-exec
state.Pipeline.Step.Environment["CI_MACHINE"] = r.hostname
state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "success"
state.Pipeline.Step.Environment["CI_PIPELINE_STARTED"] = strconv.FormatInt(state.Pipeline.Started, 10)
state.Pipeline.Step.Environment["CI_PIPELINE_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
state.Pipeline.Step.Environment["CI_STEP_STATUS"] = "success"
state.Pipeline.Step.Environment["CI_STEP_STARTED"] = strconv.FormatInt(state.Pipeline.Started, 10)
state.Pipeline.Step.Environment["CI_STEP_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
state.Pipeline.Step.Environment["CI_SYSTEM_PLATFORM"] = runtime.GOOS + "/" + runtime.GOARCH
if state.Pipeline.Error != nil {
state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "failure"
state.Pipeline.Step.Environment["CI_STEP_STATUS"] = "failure"
}
return nil
}
}

View file

@ -25,6 +25,7 @@ import (
"strings"
"github.com/drone/envsubst"
"github.com/oklog/ulid/v2"
"github.com/rs/zerolog/log"
"github.com/urfave/cli/v3"
@ -36,11 +37,13 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/kubernetes"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/local"
backend_types "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/metadata"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/compiler"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/linter"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/matrix"
pipelineLog "go.woodpecker-ci.org/woodpecker/v2/pipeline/log"
"go.woodpecker-ci.org/woodpecker/v2/shared/constant"
"go.woodpecker-ci.org/woodpecker/v2/shared/utils"
)
@ -74,6 +77,7 @@ func execDir(ctx context.Context, c *cli.Command, dir string) error {
if runtime.GOOS == "windows" {
repoPath = convertPathForWindows(repoPath)
}
// TODO: respect depends_on and do parallel runs with output to multiple _windows_ e.g. tmux like
return filepath.Walk(dir, func(path string, info os.FileInfo, e error) error {
if e != nil {
return e
@ -82,7 +86,7 @@ func execDir(ctx context.Context, c *cli.Command, dir string) error {
// check if it is a regular file (not dir)
if info.Mode().IsRegular() && (strings.HasSuffix(info.Name(), ".yaml") || strings.HasSuffix(info.Name(), ".yml")) {
fmt.Println("#", info.Name())
_ = runExec(ctx, c, path, repoPath) // TODO: should we drop errors or store them and report back?
_ = runExec(ctx, c, path, repoPath, false) // TODO: should we drop errors or store them and report back?
fmt.Println("")
return nil
}
@ -101,10 +105,10 @@ func execFile(ctx context.Context, c *cli.Command, file string) error {
if runtime.GOOS == "windows" {
repoPath = convertPathForWindows(repoPath)
}
return runExec(ctx, c, file, repoPath)
return runExec(ctx, c, file, repoPath, true)
}
func runExec(ctx context.Context, c *cli.Command, file, repoPath string) error {
func runExec(ctx context.Context, c *cli.Command, file, repoPath string, singleExec bool) error {
dat, err := os.ReadFile(file)
if err != nil {
return err
@ -119,7 +123,7 @@ func runExec(ctx context.Context, c *cli.Command, file, repoPath string) error {
axes = append(axes, matrix.Axis{})
}
for _, axis := range axes {
err := execWithAxis(ctx, c, file, repoPath, axis)
err := execWithAxis(ctx, c, file, repoPath, axis, singleExec)
if err != nil {
return err
}
@ -127,8 +131,20 @@ func runExec(ctx context.Context, c *cli.Command, file, repoPath string) error {
return nil
}
func execWithAxis(ctx context.Context, c *cli.Command, file, repoPath string, axis matrix.Axis) error {
metadata := metadataFromContext(ctx, c, axis)
func execWithAxis(ctx context.Context, c *cli.Command, file, repoPath string, axis matrix.Axis, singleExec bool) error {
metadataWorkflow := &metadata.Workflow{}
if !singleExec {
// TODO: proper try to use the engine to generate the same metadata for workflows
// https://github.com/woodpecker-ci/woodpecker/pull/3967
metadataWorkflow.Name = strings.TrimSuffix(strings.TrimSuffix(file, ".yaml"), ".yml")
}
metadata, err := metadataFromContext(ctx, c, axis, metadataWorkflow)
if err != nil {
return fmt.Errorf("could not create metadata: %w", err)
} else if metadata == nil {
return fmt.Errorf("metadata is nil")
}
environ := metadata.Environ()
var secrets []compiler.Secret
for key, val := range metadata.Workflow.Matrix {
@ -166,6 +182,9 @@ func execWithAxis(ctx context.Context, c *cli.Command, file, repoPath string, ax
return err
}
// emulate server behavior https://github.com/woodpecker-ci/woodpecker/blob/eebaa10d104cbc3fa7ce4c0e344b0b7978405135/server/pipeline/stepbuilder/stepBuilder.go#L289-L295
prefix := "wp_" + ulid.Make().String()
// configure volumes for local execution
volumes := c.StringSlice("volumes")
if c.Bool("local") {
@ -180,12 +199,22 @@ func execWithAxis(ctx context.Context, c *cli.Command, file, repoPath string, ax
workspacePath = c.String("workspace-path")
}
volumes = append(volumes, c.String("prefix")+"_default:"+workspaceBase)
volumes = append(volumes, prefix+"_default:"+workspaceBase)
volumes = append(volumes, repoPath+":"+path.Join(workspaceBase, workspacePath))
}
privilegedPlugins := c.StringSlice("plugins-privileged")
// lint the yaml file
err = linter.New(linter.WithTrusted(true)).Lint([]*linter.WorkflowConfig{{
err = linter.New(
linter.WithTrusted(linter.TrustedConfiguration{
Security: c.Bool("repo-trusted-security"),
Network: c.Bool("repo-trusted-network"),
Volumes: c.Bool("repo-trusted-volumes"),
}),
linter.PrivilegedPlugins(privilegedPlugins),
linter.WithTrustedClonePlugins(constant.TrustedClonePlugins),
).Lint([]*linter.WorkflowConfig{{
File: path.Base(file),
RawConfig: confStr,
Workflow: conf,
@ -201,7 +230,7 @@ func execWithAxis(ctx context.Context, c *cli.Command, file, repoPath string, ax
// compiles the yaml file
compiled, err := compiler.New(
compiler.WithEscalated(
c.StringSlice("privileged")...,
privilegedPlugins...,
),
compiler.WithVolumes(volumes...),
compiler.WithWorkspace(
@ -211,9 +240,7 @@ func execWithAxis(ctx context.Context, c *cli.Command, file, repoPath string, ax
compiler.WithNetworks(
c.StringSlice("network")...,
),
compiler.WithPrefix(
c.String("prefix"),
),
compiler.WithPrefix(prefix),
compiler.WithProxy(compiler.ProxyOptions{
NoProxy: c.String("backend-no-proxy"),
HTTPProxy: c.String("backend-http-proxy"),
@ -227,7 +254,7 @@ func execWithAxis(ctx context.Context, c *cli.Command, file, repoPath string, ax
c.String("netrc-password"),
c.String("netrc-machine"),
),
compiler.WithMetadata(metadata),
compiler.WithMetadata(*metadata),
compiler.WithSecret(secrets...),
compiler.WithEnviron(pipelineEnv),
).Compile(conf)
@ -281,8 +308,7 @@ func convertPathForWindows(path string) string {
return filepath.ToSlash(path)
}
const maxLogLineLength = 1024 * 1024 // 1mb
var defaultLogger = pipeline.Logger(func(step *backend_types.Step, rc io.ReadCloser) error {
logWriter := NewLineWriter(step.Name, step.UUID)
return pipelineLog.CopyLineByLine(logWriter, rc, maxLogLineLength)
return pipelineLog.CopyLineByLine(logWriter, rc, pipeline.MaxLogLineLength)
})

View file

@ -18,8 +18,6 @@ import (
"time"
"github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/shared/constant"
)
var flags = []cli.Flag{
@ -34,6 +32,11 @@ var flags = []cli.Flag{
Name: "repo-path",
Usage: "path to local repository",
},
&cli.StringFlag{
Sources: cli.EnvVars("WOODPECKER_METADATA_FILE"),
Name: "metadata-file",
Usage: "path to pipeline metadata file (normally downloaded from UI). Parameters can be adjusted by applying additional cli flags",
},
&cli.DurationFlag{
Sources: cli.EnvVars("WOODPECKER_TIMEOUT"),
Name: "timeout",
@ -50,17 +53,10 @@ var flags = []cli.Flag{
Name: "network",
Usage: "external networks",
},
&cli.StringFlag{
Sources: cli.EnvVars("WOODPECKER_PREFIX"),
Name: "prefix",
Value: "woodpecker",
Usage: "prefix used for containers, volumes, networks, ... created by woodpecker",
Hidden: true,
},
&cli.StringSliceFlag{
Name: "privileged",
Usage: "privileged plugins",
Value: constant.PrivilegedPlugins,
Sources: cli.EnvVars("WOODPECKER_PLUGINS_PRIVILEGED"),
Name: "plugins-privileged",
Usage: "Allow plugins to run in privileged mode, if environment variable is defined but empty there will be none",
},
&cli.StringFlag{
Sources: cli.EnvVars("WOODPECKER_BACKEND"),
@ -127,201 +123,287 @@ var flags = []cli.Flag{
&cli.StringFlag{
Sources: cli.EnvVars("CI_SYSTEM_PLATFORM"),
Name: "system-platform",
Usage: "Set the metadata environment variable \"CI_SYSTEM_PLATFORM\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_SYSTEM_HOST"),
Name: "system-host",
Usage: "Set the metadata environment variable \"CI_SYSTEM_HOST\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_SYSTEM_NAME"),
Name: "system-name",
Usage: "Set the metadata environment variable \"CI_SYSTEM_NAME\".",
Value: "woodpecker",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_SYSTEM_URL"),
Name: "system-url",
Usage: "Set the metadata environment variable \"CI_SYSTEM_URL\".",
Value: "https://github.com/woodpecker-ci/woodpecker",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_REPO"),
Name: "repo",
Usage: "full repo name",
Usage: "Set the full name to derive metadata environment variables \"CI_REPO\", \"CI_REPO_NAME\" and \"CI_REPO_OWNER\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_REPO_REMOTE_ID"),
Name: "repo-remote-id",
Usage: "Set the metadata environment variable \"CI_REPO_REMOTE_ID\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_REPO_URL"),
Name: "repo-url",
Usage: "Set the metadata environment variable \"CI_REPO_URL\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_REPO_SCM"),
Name: "repo-scm",
Usage: "Set the metadata environment variable \"CI_REPO_SCM\".",
Value: "git",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_REPO_DEFAULT_BRANCH"),
Name: "repo-default-branch",
Usage: "Set the metadata environment variable \"CI_REPO_DEFAULT_BRANCH\".",
Value: "main",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_REPO_CLONE_URL"),
Name: "repo-clone-url",
Usage: "Set the metadata environment variable \"CI_REPO_CLONE_URL\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_REPO_CLONE_SSH_URL"),
Name: "repo-clone-ssh-url",
Usage: "Set the metadata environment variable \"CI_REPO_CLONE_SSH_URL\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_REPO_PRIVATE"),
Name: "repo-private",
Usage: "Set the metadata environment variable \"CI_REPO_PRIVATE\".",
},
&cli.BoolFlag{
Sources: cli.EnvVars("CI_REPO_TRUSTED"),
Name: "repo-trusted",
Sources: cli.EnvVars("CI_REPO_TRUSTED_NETWORK"),
Name: "repo-trusted-network",
Usage: "Set the metadata environment variable \"CI_REPO_TRUSTED_NETWORK\".",
},
&cli.BoolFlag{
Sources: cli.EnvVars("CI_REPO_TRUSTED_VOLUMES"),
Name: "repo-trusted-volumes",
Usage: "Set the metadata environment variable \"CI_REPO_TRUSTED_VOLUMES\".",
},
&cli.BoolFlag{
Sources: cli.EnvVars("CI_REPO_TRUSTED_SECURITY"),
Name: "repo-trusted-security",
Usage: "Set the metadata environment variable \"CI_REPO_TRUSTED_SECURITY\".",
},
&cli.IntFlag{
Sources: cli.EnvVars("CI_PIPELINE_NUMBER"),
Name: "pipeline-number",
Usage: "Set the metadata environment variable \"CI_PIPELINE_NUMBER\".",
},
&cli.IntFlag{
Sources: cli.EnvVars("CI_PIPELINE_PARENT"),
Name: "pipeline-parent",
Usage: "Set the metadata environment variable \"CI_PIPELINE_PARENT\".",
},
&cli.IntFlag{
Sources: cli.EnvVars("CI_PIPELINE_CREATED"),
Name: "pipeline-created",
Usage: "Set the metadata environment variable \"CI_PIPELINE_CREATED\".",
},
&cli.IntFlag{
Sources: cli.EnvVars("CI_PIPELINE_STARTED"),
Name: "pipeline-started",
},
&cli.IntFlag{
Sources: cli.EnvVars("CI_PIPELINE_FINISHED"),
Name: "pipeline-finished",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_PIPELINE_STATUS"),
Name: "pipeline-status",
Usage: "Set the metadata environment variable \"CI_PIPELINE_STARTED\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_PIPELINE_EVENT"),
Name: "pipeline-event",
Usage: "Set the metadata environment variable \"CI_PIPELINE_EVENT\".",
Value: "manual",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_PIPELINE_URL"),
Sources: cli.EnvVars("CI_PIPELINE_FORGE_URL"),
Name: "pipeline-url",
Usage: "Set the metadata environment variable \"CI_PIPELINE_FORGE_URL\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_PIPELINE_DEPLOY_TARGET", "CI_PIPELINE_TARGET"), // TODO: remove CI_PIPELINE_TARGET in 3.x
Sources: cli.EnvVars("CI_PIPELINE_DEPLOY_TARGET"),
Name: "pipeline-deploy-to",
Usage: "Set the metadata environment variable \"CI_PIPELINE_DEPLOY_TARGET\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_PIPELINE_DEPLOY_TASK", "CI_PIPELINE_TASK"), // TODO: remove CI_PIPELINE_TASK in 3.x
Sources: cli.EnvVars("CI_PIPELINE_DEPLOY_TASK"),
Name: "pipeline-deploy-task",
Usage: "Set the metadata environment variable \"CI_PIPELINE_DEPLOY_TASK\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_PIPELINE_FILES"),
Usage: "Set the metadata environment variable \"CI_PIPELINE_FILES\", either json formatted list of strings, or comma separated string list.",
Name: "pipeline-changed-files",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_COMMIT_SHA"),
Name: "commit-sha",
Usage: "Set the metadata environment variable \"CI_COMMIT_SHA\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_COMMIT_REF"),
Name: "commit-ref",
Usage: "Set the metadata environment variable \"CI_COMMIT_REF\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_COMMIT_REFSPEC"),
Name: "commit-refspec",
Usage: "Set the metadata environment variable \"CI_COMMIT_REFSPEC\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_COMMIT_BRANCH"),
Name: "commit-branch",
Usage: "Set the metadata environment variable \"CI_COMMIT_BRANCH\".",
Value: "main",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_COMMIT_MESSAGE"),
Name: "commit-message",
Usage: "Set the metadata environment variable \"CI_COMMIT_MESSAGE\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_COMMIT_AUTHOR_NAME"),
Sources: cli.EnvVars("CI_COMMIT_AUTHOR"),
Name: "commit-author-name",
Usage: "Set the metadata environment variable \"CI_COMMIT_AUTHOR\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_COMMIT_AUTHOR_AVATAR"),
Name: "commit-author-avatar",
Usage: "Set the metadata environment variable \"CI_COMMIT_AUTHOR_AVATAR\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_COMMIT_AUTHOR_EMAIL"),
Name: "commit-author-email",
Usage: "Set the metadata environment variable \"CI_COMMIT_AUTHOR_EMAIL\".",
},
&cli.StringSliceFlag{
Sources: cli.EnvVars("CI_COMMIT_PULL_REQUEST_LABELS"),
Name: "commit-pull-labels",
Usage: "Set the metadata environment variable \"CI_COMMIT_PULL_REQUEST_LABELS\".",
},
&cli.BoolFlag{
Sources: cli.EnvVars("CI_COMMIT_PRERELEASE"),
Name: "commit-release-is-pre",
Usage: "Set the metadata environment variable \"CI_COMMIT_PRERELEASE\".",
},
&cli.IntFlag{
Sources: cli.EnvVars("CI_PREV_PIPELINE_NUMBER"),
Name: "prev-pipeline-number",
Usage: "Set the metadata environment variable \"CI_PREV_PIPELINE_NUMBER\".",
},
&cli.IntFlag{
Sources: cli.EnvVars("CI_PREV_PIPELINE_CREATED"),
Name: "prev-pipeline-created",
Usage: "Set the metadata environment variable \"CI_PREV_PIPELINE_CREATED\".",
},
&cli.IntFlag{
Sources: cli.EnvVars("CI_PREV_PIPELINE_STARTED"),
Name: "prev-pipeline-started",
Usage: "Set the metadata environment variable \"CI_PREV_PIPELINE_STARTED\".",
},
&cli.IntFlag{
Sources: cli.EnvVars("CI_PREV_PIPELINE_FINISHED"),
Name: "prev-pipeline-finished",
Usage: "Set the metadata environment variable \"CI_PREV_PIPELINE_FINISHED\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_PREV_PIPELINE_STATUS"),
Name: "prev-pipeline-status",
Usage: "Set the metadata environment variable \"CI_PREV_PIPELINE_STATUS\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_PREV_PIPELINE_EVENT"),
Name: "prev-pipeline-event",
Usage: "Set the metadata environment variable \"CI_PREV_PIPELINE_EVENT\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_PREV_PIPELINE_URL"),
Sources: cli.EnvVars("CI_PREV_PIPELINE_FORGE_URL"),
Name: "prev-pipeline-url",
Usage: "Set the metadata environment variable \"CI_PREV_PIPELINE_FORGE_URL\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_PREV_PIPELINE_DEPLOY_TARGET"),
Name: "prev-pipeline-deploy-to",
Usage: "Set the metadata environment variable \"CI_PREV_PIPELINE_DEPLOY_TARGET\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_PREV_PIPELINE_DEPLOY_TASK"),
Name: "prev-pipeline-deploy-task",
Usage: "Set the metadata environment variable \"CI_PREV_PIPELINE_DEPLOY_TASK\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_PREV_COMMIT_SHA"),
Name: "prev-commit-sha",
Usage: "Set the metadata environment variable \"CI_PREV_COMMIT_SHA\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_PREV_COMMIT_REF"),
Name: "prev-commit-ref",
Usage: "Set the metadata environment variable \"CI_PREV_COMMIT_REF\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_PREV_COMMIT_REFSPEC"),
Name: "prev-commit-refspec",
Usage: "Set the metadata environment variable \"CI_PREV_COMMIT_REFSPEC\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_PREV_COMMIT_BRANCH"),
Name: "prev-commit-branch",
Usage: "Set the metadata environment variable \"CI_PREV_COMMIT_BRANCH\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_PREV_COMMIT_MESSAGE"),
Name: "prev-commit-message",
Usage: "Set the metadata environment variable \"CI_PREV_COMMIT_MESSAGE\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_PREV_COMMIT_AUTHOR_NAME"),
Sources: cli.EnvVars("CI_PREV_COMMIT_AUTHOR"),
Name: "prev-commit-author-name",
Usage: "Set the metadata environment variable \"CI_PREV_COMMIT_AUTHOR\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_PREV_COMMIT_AUTHOR_AVATAR"),
Name: "prev-commit-author-avatar",
Usage: "Set the metadata environment variable \"CI_PREV_COMMIT_AUTHOR_AVATAR\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_PREV_COMMIT_AUTHOR_EMAIL"),
Name: "prev-commit-author-email",
Usage: "Set the metadata environment variable \"CI_PREV_COMMIT_AUTHOR_EMAIL\".",
},
&cli.IntFlag{
&cli.StringFlag{
Sources: cli.EnvVars("CI_WORKFLOW_NAME"),
Name: "workflow-name",
Usage: "Set the metadata environment variable \"CI_WORKFLOW_NAME\".",
},
&cli.IntFlag{
Sources: cli.EnvVars("CI_WORKFLOW_NUMBER"),
Name: "workflow-number",
},
&cli.IntFlag{
Sources: cli.EnvVars("CI_STEP_NAME"),
Name: "step-name",
Usage: "Set the metadata environment variable \"CI_WORKFLOW_NUMBER\".",
},
&cli.StringSliceFlag{
Sources: cli.EnvVars("CI_ENV"),
Name: "env",
Usage: "Set the metadata environment variable \"CI_ENV\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_FORGE_TYPE"),
Name: "forge-type",
Usage: "Set the metadata environment variable \"CI_FORGE_TYPE\".",
},
&cli.StringFlag{
Sources: cli.EnvVars("CI_FORGE_URL"),
Name: "forge-url",
Usage: "Set the metadata environment variable \"CI_FORGE_URL\".",
},
}

View file

@ -16,6 +16,9 @@ package exec
import (
"context"
"encoding/json"
"fmt"
"os"
"runtime"
"strings"
@ -27,94 +30,133 @@ import (
)
// return the metadata from the cli context.
func metadataFromContext(_ context.Context, c *cli.Command, axis matrix.Axis) metadata.Metadata {
func metadataFromContext(_ context.Context, c *cli.Command, axis matrix.Axis, w *metadata.Workflow) (*metadata.Metadata, error) {
m := &metadata.Metadata{}
if c.IsSet("metadata-file") {
metadataFile, err := os.Open(c.String("metadata-file"))
if err != nil {
return nil, err
}
defer metadataFile.Close()
if err := json.NewDecoder(metadataFile).Decode(m); err != nil {
return nil, err
}
}
platform := c.String("system-platform")
if platform == "" {
platform = runtime.GOOS + "/" + runtime.GOARCH
}
fullRepoName := c.String("repo-name")
repoOwner := ""
repoName := ""
if idx := strings.LastIndex(fullRepoName, "/"); idx != -1 {
repoOwner = fullRepoName[:idx]
repoName = fullRepoName[idx+1:]
metadataFileAndOverrideOrDefault(c, "repo-name", func(fullRepoName string) {
if idx := strings.LastIndex(fullRepoName, "/"); idx != -1 {
m.Repo.Owner = fullRepoName[:idx]
m.Repo.Name = fullRepoName[idx+1:]
}
}, c.String)
var err error
metadataFileAndOverrideOrDefault(c, "pipeline-changed-files", func(changedFilesRaw string) {
var changedFiles []string
if len(changedFilesRaw) != 0 && changedFilesRaw[0] == '[' {
if jsonErr := json.Unmarshal([]byte(changedFilesRaw), &changedFiles); jsonErr != nil {
err = fmt.Errorf("pipeline-changed-files detected json but could not parse it: %w", jsonErr)
}
} else {
for _, file := range strings.Split(changedFilesRaw, ",") {
changedFiles = append(changedFiles, strings.TrimSpace(file))
}
}
m.Curr.Commit.ChangedFiles = changedFiles
}, c.String)
if err != nil {
return nil, err
}
return metadata.Metadata{
Repo: metadata.Repo{
Name: repoName,
Owner: repoOwner,
RemoteID: c.String("repo-remote-id"),
ForgeURL: c.String("repo-url"),
CloneURL: c.String("repo-clone-url"),
CloneSSHURL: c.String("repo-clone-ssh-url"),
Private: c.Bool("repo-private"),
Trusted: c.Bool("repo-trusted"),
},
Curr: metadata.Pipeline{
Number: c.Int("pipeline-number"),
Parent: c.Int("pipeline-parent"),
Created: c.Int("pipeline-created"),
Started: c.Int("pipeline-started"),
Finished: c.Int("pipeline-finished"),
Status: c.String("pipeline-status"),
Event: c.String("pipeline-event"),
ForgeURL: c.String("pipeline-url"),
DeployTo: c.String("pipeline-deploy-to"),
DeployTask: c.String("pipeline-deploy-task"),
Commit: metadata.Commit{
Sha: c.String("commit-sha"),
Ref: c.String("commit-ref"),
Refspec: c.String("commit-refspec"),
Branch: c.String("commit-branch"),
Message: c.String("commit-message"),
Author: metadata.Author{
Name: c.String("commit-author-name"),
Email: c.String("commit-author-email"),
Avatar: c.String("commit-author-avatar"),
},
},
},
Prev: metadata.Pipeline{
Number: c.Int("prev-pipeline-number"),
Created: c.Int("prev-pipeline-created"),
Started: c.Int("prev-pipeline-started"),
Finished: c.Int("prev-pipeline-finished"),
Status: c.String("prev-pipeline-status"),
Event: c.String("prev-pipeline-event"),
ForgeURL: c.String("prev-pipeline-url"),
Commit: metadata.Commit{
Sha: c.String("prev-commit-sha"),
Ref: c.String("prev-commit-ref"),
Refspec: c.String("prev-commit-refspec"),
Branch: c.String("prev-commit-branch"),
Message: c.String("prev-commit-message"),
Author: metadata.Author{
Name: c.String("prev-commit-author-name"),
Email: c.String("prev-commit-author-email"),
Avatar: c.String("prev-commit-author-avatar"),
},
},
},
Workflow: metadata.Workflow{
Name: c.String("workflow-name"),
Number: int(c.Int("workflow-number")),
Matrix: axis,
},
Step: metadata.Step{
Name: c.String("step-name"),
Number: int(c.Int("step-number")),
},
Sys: metadata.System{
Name: c.String("system-name"),
URL: c.String("system-url"),
Platform: platform,
Version: version.Version,
},
Forge: metadata.Forge{
Type: c.String("forge-type"),
URL: c.String("forge-url"),
},
// Repo
metadataFileAndOverrideOrDefault(c, "repo-remote-id", func(s string) { m.Repo.RemoteID = s }, c.String)
metadataFileAndOverrideOrDefault(c, "repo-url", func(s string) { m.Repo.ForgeURL = s }, c.String)
metadataFileAndOverrideOrDefault(c, "repo-scm", func(s string) { m.Repo.SCM = s }, c.String)
metadataFileAndOverrideOrDefault(c, "repo-default-branch", func(s string) { m.Repo.Branch = s }, c.String)
metadataFileAndOverrideOrDefault(c, "repo-clone-url", func(s string) { m.Repo.CloneURL = s }, c.String)
metadataFileAndOverrideOrDefault(c, "repo-clone-ssh-url", func(s string) { m.Repo.CloneSSHURL = s }, c.String)
metadataFileAndOverrideOrDefault(c, "repo-private", func(b bool) { m.Repo.Private = b }, c.Bool)
metadataFileAndOverrideOrDefault(c, "repo-trusted-network", func(b bool) { m.Repo.Trusted.Network = b }, c.Bool)
metadataFileAndOverrideOrDefault(c, "repo-trusted-security", func(b bool) { m.Repo.Trusted.Security = b }, c.Bool)
metadataFileAndOverrideOrDefault(c, "repo-trusted-volumes", func(b bool) { m.Repo.Trusted.Volumes = b }, c.Bool)
// Current Pipeline
metadataFileAndOverrideOrDefault(c, "pipeline-number", func(i int64) { m.Curr.Number = i }, c.Int)
metadataFileAndOverrideOrDefault(c, "pipeline-parent", func(i int64) { m.Curr.Parent = i }, c.Int)
metadataFileAndOverrideOrDefault(c, "pipeline-created", func(i int64) { m.Curr.Created = i }, c.Int)
metadataFileAndOverrideOrDefault(c, "pipeline-started", func(i int64) { m.Curr.Started = i }, c.Int)
metadataFileAndOverrideOrDefault(c, "pipeline-finished", func(i int64) { m.Curr.Finished = i }, c.Int)
metadataFileAndOverrideOrDefault(c, "pipeline-status", func(s string) { m.Curr.Status = s }, c.String)
metadataFileAndOverrideOrDefault(c, "pipeline-event", func(s string) { m.Curr.Event = s }, c.String)
metadataFileAndOverrideOrDefault(c, "pipeline-url", func(s string) { m.Curr.ForgeURL = s }, c.String)
metadataFileAndOverrideOrDefault(c, "pipeline-deploy-to", func(s string) { m.Curr.DeployTo = s }, c.String)
metadataFileAndOverrideOrDefault(c, "pipeline-deploy-task", func(s string) { m.Curr.DeployTask = s }, c.String)
// Current Pipeline Commit
metadataFileAndOverrideOrDefault(c, "commit-sha", func(s string) { m.Curr.Commit.Sha = s }, c.String)
metadataFileAndOverrideOrDefault(c, "commit-ref", func(s string) { m.Curr.Commit.Ref = s }, c.String)
metadataFileAndOverrideOrDefault(c, "commit-refspec", func(s string) { m.Curr.Commit.Refspec = s }, c.String)
metadataFileAndOverrideOrDefault(c, "commit-branch", func(s string) { m.Curr.Commit.Branch = s }, c.String)
metadataFileAndOverrideOrDefault(c, "commit-message", func(s string) { m.Curr.Commit.Message = s }, c.String)
metadataFileAndOverrideOrDefault(c, "commit-author-name", func(s string) { m.Curr.Commit.Author.Name = s }, c.String)
metadataFileAndOverrideOrDefault(c, "commit-author-email", func(s string) { m.Curr.Commit.Author.Email = s }, c.String)
metadataFileAndOverrideOrDefault(c, "commit-author-avatar", func(s string) { m.Curr.Commit.Author.Avatar = s }, c.String)
metadataFileAndOverrideOrDefault(c, "commit-pull-labels", func(sl []string) { m.Curr.Commit.PullRequestLabels = sl }, c.StringSlice)
metadataFileAndOverrideOrDefault(c, "commit-release-is-pre", func(b bool) { m.Curr.Commit.IsPrerelease = b }, c.Bool)
// Previous Pipeline
metadataFileAndOverrideOrDefault(c, "prev-pipeline-number", func(i int64) { m.Prev.Number = i }, c.Int)
metadataFileAndOverrideOrDefault(c, "prev-pipeline-created", func(i int64) { m.Prev.Created = i }, c.Int)
metadataFileAndOverrideOrDefault(c, "prev-pipeline-started", func(i int64) { m.Prev.Started = i }, c.Int)
metadataFileAndOverrideOrDefault(c, "prev-pipeline-finished", func(i int64) { m.Prev.Finished = i }, c.Int)
metadataFileAndOverrideOrDefault(c, "prev-pipeline-status", func(s string) { m.Prev.Status = s }, c.String)
metadataFileAndOverrideOrDefault(c, "prev-pipeline-event", func(s string) { m.Prev.Event = s }, c.String)
metadataFileAndOverrideOrDefault(c, "prev-pipeline-url", func(s string) { m.Prev.ForgeURL = s }, c.String)
// Previous Pipeline Commit
metadataFileAndOverrideOrDefault(c, "prev-commit-sha", func(s string) { m.Prev.Commit.Sha = s }, c.String)
metadataFileAndOverrideOrDefault(c, "prev-commit-ref", func(s string) { m.Prev.Commit.Ref = s }, c.String)
metadataFileAndOverrideOrDefault(c, "prev-commit-refspec", func(s string) { m.Prev.Commit.Refspec = s }, c.String)
metadataFileAndOverrideOrDefault(c, "prev-commit-branch", func(s string) { m.Prev.Commit.Branch = s }, c.String)
metadataFileAndOverrideOrDefault(c, "prev-commit-message", func(s string) { m.Prev.Commit.Message = s }, c.String)
metadataFileAndOverrideOrDefault(c, "prev-commit-author-name", func(s string) { m.Prev.Commit.Author.Name = s }, c.String)
metadataFileAndOverrideOrDefault(c, "prev-commit-author-email", func(s string) { m.Prev.Commit.Author.Email = s }, c.String)
metadataFileAndOverrideOrDefault(c, "prev-commit-author-avatar", func(s string) { m.Prev.Commit.Author.Avatar = s }, c.String)
// Workflow
metadataFileAndOverrideOrDefault(c, "workflow-name", func(s string) { m.Workflow.Name = s }, c.String)
metadataFileAndOverrideOrDefault(c, "workflow-number", func(i int64) { m.Workflow.Number = int(i) }, c.Int)
m.Workflow.Matrix = axis
// System
metadataFileAndOverrideOrDefault(c, "system-name", func(s string) { m.Sys.Name = s }, c.String)
metadataFileAndOverrideOrDefault(c, "system-url", func(s string) { m.Sys.URL = s }, c.String)
metadataFileAndOverrideOrDefault(c, "system-host", func(s string) { m.Sys.Host = s }, c.String)
m.Sys.Platform = platform
m.Sys.Version = version.Version
// Forge
metadataFileAndOverrideOrDefault(c, "forge-type", func(s string) { m.Forge.Type = s }, c.String)
metadataFileAndOverrideOrDefault(c, "forge-url", func(s string) { m.Forge.URL = s }, c.String)
if w != nil {
m.Workflow = *w
}
return m, nil
}
// metadataFileAndOverrideOrDefault will either use the flag default or if metadata file is set only overload if explicit set.
func metadataFileAndOverrideOrDefault[T any](c *cli.Command, flag string, setter func(T), getter func(string) T) {
if !c.IsSet("metadata-file") || c.IsSet(flag) {
setter(getter(flag))
}
}

142
cli/exec/metadata_test.go Normal file
View file

@ -0,0 +1,142 @@
// Copyright 2024 Woodpecker Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package exec
import (
"context"
"encoding/json"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/metadata"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/matrix"
)
func TestMetadataFromContext(t *testing.T) {
sampleMetadata := &metadata.Metadata{
Repo: metadata.Repo{Owner: "test-user", Name: "test-repo"},
Curr: metadata.Pipeline{Number: 5},
}
runCommand := func(flags []cli.Flag, fn func(c *cli.Command)) {
c := &cli.Command{
Flags: flags,
Action: func(_ context.Context, c *cli.Command) error {
fn(c)
return nil
},
}
assert.NoError(t, c.Run(context.Background(), []string{"woodpecker-cli"}))
}
t.Run("LoadFromFile", func(t *testing.T) {
tempFileName := createTempFile(t, sampleMetadata)
flags := []cli.Flag{
&cli.StringFlag{Name: "metadata-file"},
}
runCommand(flags, func(c *cli.Command) {
_ = c.Set("metadata-file", tempFileName)
m, err := metadataFromContext(context.Background(), c, nil, nil)
require.NoError(t, err)
assert.Equal(t, "test-repo", m.Repo.Name)
assert.Equal(t, int64(5), m.Curr.Number)
})
})
t.Run("OverrideFromFlags", func(t *testing.T) {
tempFileName := createTempFile(t, sampleMetadata)
flags := []cli.Flag{
&cli.StringFlag{Name: "metadata-file"},
&cli.StringFlag{Name: "repo-name"},
&cli.IntFlag{Name: "pipeline-number"},
}
runCommand(flags, func(c *cli.Command) {
_ = c.Set("metadata-file", tempFileName)
_ = c.Set("repo-name", "aUser/override-repo")
_ = c.Set("pipeline-number", "10")
m, err := metadataFromContext(context.Background(), c, nil, nil)
require.NoError(t, err)
assert.Equal(t, "override-repo", m.Repo.Name)
assert.Equal(t, int64(10), m.Curr.Number)
})
})
t.Run("InvalidFile", func(t *testing.T) {
tempFile, err := os.CreateTemp("", "invalid.json")
require.NoError(t, err)
t.Cleanup(func() { os.Remove(tempFile.Name()) })
_, err = tempFile.Write([]byte("invalid json"))
require.NoError(t, err)
flags := []cli.Flag{
&cli.StringFlag{Name: "metadata-file"},
}
runCommand(flags, func(c *cli.Command) {
_ = c.Set("metadata-file", tempFile.Name())
_, err = metadataFromContext(context.Background(), c, nil, nil)
assert.Error(t, err)
})
})
t.Run("DefaultValues", func(t *testing.T) {
flags := []cli.Flag{
&cli.StringFlag{Name: "repo-name", Value: "test/default-repo"},
&cli.IntFlag{Name: "pipeline-number", Value: 1},
}
runCommand(flags, func(c *cli.Command) {
m, err := metadataFromContext(context.Background(), c, nil, nil)
require.NoError(t, err)
if assert.NotNil(t, m) {
assert.Equal(t, "test", m.Repo.Owner)
assert.Equal(t, "default-repo", m.Repo.Name)
assert.Equal(t, int64(1), m.Curr.Number)
}
})
})
t.Run("MatrixAxis", func(t *testing.T) {
runCommand([]cli.Flag{}, func(c *cli.Command) {
axis := matrix.Axis{"go": "1.16", "os": "linux"}
m, err := metadataFromContext(context.Background(), c, axis, nil)
require.NoError(t, err)
assert.EqualValues(t, map[string]string{"go": "1.16", "os": "linux"}, m.Workflow.Matrix)
})
})
}
func createTempFile(t *testing.T, content any) string {
t.Helper()
tempFile, err := os.CreateTemp("", "metadata.json")
require.NoError(t, err)
t.Cleanup(func() { os.Remove(tempFile.Name()) })
err = json.NewEncoder(tempFile).Encode(content)
require.NoError(t, err)
return tempFile.Name()
}

View file

@ -27,6 +27,7 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/linter"
"go.woodpecker-ci.org/woodpecker/v2/shared/constant"
)
// Command exports the info command.
@ -35,6 +36,19 @@ var Command = &cli.Command{
Usage: "lint a pipeline configuration file",
ArgsUsage: "[path/to/.woodpecker.yaml]",
Action: lint,
Flags: []cli.Flag{
&cli.StringSliceFlag{
Sources: cli.EnvVars("WOODPECKER_PLUGINS_PRIVILEGED"),
Name: "plugins-privileged",
Usage: "Allow plugins to run in privileged mode, if environment variable is defined but empty there will be none",
},
&cli.StringSliceFlag{
Sources: cli.EnvVars("WOODPECKER_PLUGINS_TRUSTED_CLONE"),
Name: "plugins-trusted-clone",
Usage: "Plugins which are trusted to handle the netrc info in clone steps",
Value: constant.TrustedClonePlugins,
},
},
}
func lint(ctx context.Context, c *cli.Command) error {
@ -69,7 +83,7 @@ func lintDir(ctx context.Context, c *cli.Command, dir string) error {
return nil
}
func lintFile(_ context.Context, _ *cli.Command, file string) error {
func lintFile(_ context.Context, c *cli.Command, file string) error {
fi, err := os.Open(file)
if err != nil {
return err
@ -83,7 +97,7 @@ func lintFile(_ context.Context, _ *cli.Command, file string) error {
rawConfig := string(buf)
c, err := yaml.ParseString(rawConfig)
parsedConfig, err := yaml.ParseString(rawConfig)
if err != nil {
return err
}
@ -91,11 +105,19 @@ func lintFile(_ context.Context, _ *cli.Command, file string) error {
config := &linter.WorkflowConfig{
File: path.Base(file),
RawConfig: rawConfig,
Workflow: c,
Workflow: parsedConfig,
}
// TODO: lint multiple files at once to allow checks for sth like "depends_on" to work
err = linter.New(linter.WithTrusted(true)).Lint([]*linter.WorkflowConfig{config})
err = linter.New(
linter.WithTrusted(linter.TrustedConfiguration{
Network: true,
Volumes: true,
Security: true,
}),
linter.PrivilegedPlugins(c.StringSlice("plugins-privileged")),
linter.WithTrustedClonePlugins(c.StringSlice("plugins-trusted-clone")),
).Lint([]*linter.WorkflowConfig{config})
if err != nil {
str, err := FormatLintError(config.File, err)

View file

@ -16,6 +16,7 @@ package secret
import (
"context"
"fmt"
"html/template"
"os"
@ -51,6 +52,11 @@ func secretInfo(ctx context.Context, c *cli.Command) error {
secretName = c.String("name")
format = c.String("format") + "\n"
)
if secretName == "" {
return fmt.Errorf("secret name is missing")
}
client, err := internal.NewClient(ctx, c)
if err != nil {
return err

View file

@ -20,6 +20,7 @@ import (
"crypto/tls"
"errors"
"fmt"
"maps"
"net/http"
"os"
"strings"
@ -156,7 +157,7 @@ func run(ctx context.Context, c *cli.Command, backends []types.Backend) error {
}
defer conn.Close()
client := agent_rpc.NewGrpcClient(conn)
client := agent_rpc.NewGrpcClient(ctx, conn)
agentConfigPersisted := atomic.Bool{}
grpcCtx := metadata.NewOutgoingContext(grpcClientCtx, metadata.Pairs("hostname", hostname))
@ -198,7 +199,22 @@ func run(ctx context.Context, c *cli.Command, backends []types.Backend) error {
log.Debug().Msgf("loaded %s backend engine", backendEngine.Name())
maxWorkflows := int(c.Int("max-workflows"))
agentConfig.AgentID, err = client.RegisterAgent(grpcCtx, engInfo.Platform, backendEngine.Name(), version.String(), maxWorkflows) //nolint:contextcheck
customLabels := make(map[string]string)
if err := stringSliceAddToMap(c.StringSlice("labels"), customLabels); err != nil {
return err
}
if len(customLabels) != 0 {
log.Debug().Msgf("custom labels detected: %#v", customLabels)
}
agentConfig.AgentID, err = client.RegisterAgent(grpcCtx, rpc.AgentInfo{ //nolint:contextcheck
Version: version.String(),
Backend: backendEngine.Name(),
Platform: engInfo.Platform,
Capacity: maxWorkflows,
CustomLabels: customLabels,
})
if err != nil {
return err
}
@ -210,7 +226,7 @@ func run(ctx context.Context, c *cli.Command, backends []types.Backend) error {
<-agentCtx.Done()
// Remove stateless agents from server
if !agentConfigPersisted.Load() {
log.Debug().Msg("unregistering agent from server ...")
log.Debug().Msg("unregister agent from server ...")
// we want to run it explicit run when context got canceled so run it in background
err := client.UnregisterAgent(grpcClientCtx)
if err != nil {
@ -228,16 +244,17 @@ func run(ctx context.Context, c *cli.Command, backends []types.Backend) error {
}
}
// set default labels ...
labels := map[string]string{
"hostname": hostname,
"platform": engInfo.Platform,
"backend": backendEngine.Name(),
"repo": "*", // allow all repos by default
}
// ... and let it overwrite by custom ones
maps.Copy(labels, customLabels)
if err := stringSliceAddToMap(c.StringSlice("filter"), labels); err != nil {
return err
}
log.Debug().Any("labels", labels).Msgf("agent configured with labels")
filter := rpc.Filter{
Labels: labels,

View file

@ -60,8 +60,9 @@ var flags = []cli.Flag{
Value: "/etc/woodpecker/agent.conf",
},
&cli.StringSliceFlag{
Sources: cli.EnvVars("WOODPECKER_FILTER_LABELS"),
Name: "filter",
Sources: cli.EnvVars("WOODPECKER_AGENT_LABELS", "WOODPECKER_FILTER_LABELS"), // remove WOODPECKER_FILTER_LABELS in v4.x
Name: "labels",
Aliases: []string{"filter"}, // remove in v4.x
Usage: "List of labels to filter tasks on. An agent must be assigned every tag listed in a task to be selected.",
},
&cli.IntFlag{

View file

@ -29,7 +29,6 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/cli/org"
"go.woodpecker-ci.org/woodpecker/v2/cli/pipeline"
"go.woodpecker-ci.org/woodpecker/v2/cli/repo"
"go.woodpecker-ci.org/woodpecker/v2/cli/repo/registry"
"go.woodpecker-ci.org/woodpecker/v2/cli/secret"
"go.woodpecker-ci.org/woodpecker/v2/cli/setup"
"go.woodpecker-ci.org/woodpecker/v2/cli/update"
@ -57,8 +56,6 @@ func newApp() *cli.Command {
deploy.Command,
exec.Command,
info.Command,
// TODO: Remove in 3.x
registry.Command,
secret.Command,
user.Command,
lint.Command,

View file

@ -101,7 +101,7 @@ const docTemplate = `{
}
}
},
"/agents/{agent}": {
"/agents/{agent_id}": {
"get": {
"produces": [
"application/json"
@ -211,7 +211,7 @@ const docTemplate = `{
}
}
},
"/agents/{agent}/tasks": {
"/agents/{agent_id}/tasks": {
"get": {
"produces": [
"application/json"
@ -1063,6 +1063,193 @@ const docTemplate = `{
}
}
},
"/orgs/{org_id}/agents": {
"get": {
"produces": [
"application/json"
],
"tags": [
"Agents"
],
"summary": "List agents for an organization",
"parameters": [
{
"type": "string",
"default": "Bearer \u003cpersonal access token\u003e",
"description": "Insert your personal access token",
"name": "Authorization",
"in": "header",
"required": true
},
{
"type": "integer",
"description": "the organization's id",
"name": "org_id",
"in": "path",
"required": true
},
{
"type": "integer",
"default": 1,
"description": "for response pagination, page offset number",
"name": "page",
"in": "query"
},
{
"type": "integer",
"default": 50,
"description": "for response pagination, max items per page",
"name": "perPage",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Agent"
}
}
}
}
},
"post": {
"description": "Creates a new agent with a random token, scoped to the specified organization",
"produces": [
"application/json"
],
"tags": [
"Agents"
],
"summary": "Create a new organization-scoped agent",
"parameters": [
{
"type": "string",
"default": "Bearer \u003cpersonal access token\u003e",
"description": "Insert your personal access token",
"name": "Authorization",
"in": "header",
"required": true
},
{
"type": "integer",
"description": "the organization's id",
"name": "org_id",
"in": "path",
"required": true
},
{
"description": "the agent's data (only 'name' and 'no_schedule' are read)",
"name": "agent",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/Agent"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/Agent"
}
}
}
}
},
"/orgs/{org_id}/agents/{agent_id}": {
"delete": {
"produces": [
"text/plain"
],
"tags": [
"Agents"
],
"summary": "Delete an organization-scoped agent",
"parameters": [
{
"type": "string",
"default": "Bearer \u003cpersonal access token\u003e",
"description": "Insert your personal access token",
"name": "Authorization",
"in": "header",
"required": true
},
{
"type": "integer",
"description": "the organization's id",
"name": "org_id",
"in": "path",
"required": true
},
{
"type": "integer",
"description": "the agent's id",
"name": "agent_id",
"in": "path",
"required": true
}
],
"responses": {
"204": {
"description": "No Content"
}
}
},
"patch": {
"produces": [
"application/json"
],
"tags": [
"Agents"
],
"summary": "Update an organization-scoped agent",
"parameters": [
{
"type": "string",
"default": "Bearer \u003cpersonal access token\u003e",
"description": "Insert your personal access token",
"name": "Authorization",
"in": "header",
"required": true
},
{
"type": "integer",
"description": "the organization's id",
"name": "org_id",
"in": "path",
"required": true
},
{
"type": "integer",
"description": "the agent's id",
"name": "agent_id",
"in": "path",
"required": true
},
{
"description": "the agent's updated data",
"name": "agent",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/Agent"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/Agent"
}
}
}
}
},
"/orgs/{org_id}/permissions": {
"get": {
"produces": [
@ -3144,6 +3331,49 @@ const docTemplate = `{
}
}
},
"/repos/{repo_id}/pipelines/{number}/metadata": {
"get": {
"produces": [
"application/json"
],
"tags": [
"Pipelines"
],
"summary": "Get metadata for a pipeline or a specific workflow, including previous pipeline info",
"parameters": [
{
"type": "string",
"default": "Bearer \u003cpersonal access token\u003e",
"description": "Insert your personal access token",
"name": "Authorization",
"in": "header",
"required": true
},
{
"type": "integer",
"description": "the repository id",
"name": "repo_id",
"in": "path",
"required": true
},
{
"type": "integer",
"description": "the number of the pipeline",
"name": "number",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/metadata.Metadata"
}
}
}
}
},
"/repos/{repo_id}/pull_requests": {
"get": {
"produces": [
@ -4359,6 +4589,12 @@ const docTemplate = `{
"created": {
"type": "integer"
},
"custom_labels": {
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"id": {
"type": "integer"
},
@ -4375,6 +4611,10 @@ const docTemplate = `{
"no_schedule": {
"type": "boolean"
},
"org_id": {
"description": "OrgID is counted as unset if set to -1, this is done to ensure a new(Agent) still enforce the OrgID check by default",
"type": "integer"
},
"owner_id": {
"type": "integer"
},
@ -4415,8 +4655,7 @@ const docTemplate = `{
"branch": {
"type": "string"
},
"created_at": {
"description": "TODO change JSON field to \"created\" in 3.0",
"created": {
"type": "integer"
},
"creator_id": {
@ -4458,15 +4697,13 @@ const docTemplate = `{
"commit": {
"type": "string"
},
"created_at": {
"description": "TODO change JSON field to \"created\" in 3.0",
"created": {
"type": "integer"
},
"event": {
"type": "string"
},
"finished_at": {
"description": "TODO change JSON field to \"finished\" in 3.0",
"finished": {
"type": "integer"
},
"id": {
@ -4487,8 +4724,7 @@ const docTemplate = `{
"repo_id": {
"type": "integer"
},
"started_at": {
"description": "TODO change JSON field to \"started\" in 3.0",
"started": {
"type": "integer"
},
"status": {
@ -4645,8 +4881,7 @@ const docTemplate = `{
"commit": {
"type": "string"
},
"created_at": {
"description": "TODO change JSON field to \"created\" in 3.0",
"created": {
"type": "integer"
},
"deploy_task": {
@ -4664,8 +4899,7 @@ const docTemplate = `{
"event": {
"$ref": "#/definitions/WebhookEvent"
},
"finished_at": {
"description": "TODO change JSON field to \"finished\" in 3.0",
"finished": {
"type": "integer"
},
"forge_url": {
@ -4698,8 +4932,7 @@ const docTemplate = `{
"refspec": {
"type": "string"
},
"reviewed_at": {
"description": "TODO change JSON field to \"reviewed\" in 3.0",
"reviewed": {
"type": "integer"
},
"reviewed_by": {
@ -4709,8 +4942,7 @@ const docTemplate = `{
"description": "uses reported user for webhooks and name of cron for cron pipelines",
"type": "string"
},
"started_at": {
"description": "TODO change JSON field to \"started\" in 3.0",
"started": {
"type": "integer"
},
"status": {
@ -4722,8 +4954,7 @@ const docTemplate = `{
"title": {
"type": "string"
},
"updated_at": {
"description": "TODO change JSON field to \"updated\" in 3.0",
"updated": {
"type": "integer"
},
"variables": {
@ -4868,7 +5099,7 @@ const docTemplate = `{
"type": "integer"
},
"trusted": {
"type": "boolean"
"$ref": "#/definitions/model.TrustedConfiguration"
},
"visibility": {
"$ref": "#/definitions/RepoVisibility"
@ -4903,7 +5134,7 @@ const docTemplate = `{
"type": "integer"
},
"trusted": {
"type": "boolean"
"$ref": "#/definitions/model.TrustedConfigurationPatch"
},
"visibility": {
"type": "string"
@ -5012,15 +5243,15 @@ const docTemplate = `{
"Step": {
"type": "object",
"properties": {
"end_time": {
"type": "integer"
},
"error": {
"type": "string"
},
"exit_code": {
"type": "integer"
},
"finished": {
"type": "integer"
},
"id": {
"type": "integer"
},
@ -5036,7 +5267,7 @@ const docTemplate = `{
"ppid": {
"type": "integer"
},
"start_time": {
"started": {
"type": "integer"
},
"state": {
@ -5073,12 +5304,6 @@ const docTemplate = `{
"agent_id": {
"type": "integer"
},
"data": {
"type": "array",
"items": {
"type": "integer"
}
},
"dep_status": {
"type": "object",
"additionalProperties": {
@ -5163,6 +5388,239 @@ const docTemplate = `{
"EventManual"
]
},
"metadata.Author": {
"type": "object",
"properties": {
"avatar": {
"type": "string"
},
"email": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"metadata.Commit": {
"type": "object",
"properties": {
"author": {
"$ref": "#/definitions/metadata.Author"
},
"branch": {
"type": "string"
},
"changed_files": {
"type": "array",
"items": {
"type": "string"
}
},
"is_prerelease": {
"type": "boolean"
},
"labels": {
"type": "array",
"items": {
"type": "string"
}
},
"message": {
"type": "string"
},
"ref": {
"type": "string"
},
"refspec": {
"type": "string"
},
"sha": {
"type": "string"
}
}
},
"metadata.Forge": {
"type": "object",
"properties": {
"type": {
"type": "string"
},
"url": {
"type": "string"
}
}
},
"metadata.Metadata": {
"type": "object",
"properties": {
"curr": {
"$ref": "#/definitions/metadata.Pipeline"
},
"forge": {
"$ref": "#/definitions/metadata.Forge"
},
"id": {
"type": "string"
},
"prev": {
"$ref": "#/definitions/metadata.Pipeline"
},
"repo": {
"$ref": "#/definitions/metadata.Repo"
},
"step": {
"$ref": "#/definitions/metadata.Step"
},
"sys": {
"$ref": "#/definitions/metadata.System"
},
"workflow": {
"$ref": "#/definitions/metadata.Workflow"
}
}
},
"metadata.Pipeline": {
"type": "object",
"properties": {
"commit": {
"$ref": "#/definitions/metadata.Commit"
},
"created": {
"type": "integer"
},
"cron": {
"type": "string"
},
"event": {
"type": "string"
},
"finished": {
"type": "integer"
},
"forge_url": {
"type": "string"
},
"number": {
"type": "integer"
},
"parent": {
"type": "integer"
},
"started": {
"type": "integer"
},
"status": {
"type": "string"
},
"target": {
"type": "string"
},
"task": {
"type": "string"
}
}
},
"metadata.Repo": {
"type": "object",
"properties": {
"clone_url": {
"type": "string"
},
"clone_url_ssh": {
"type": "string"
},
"default_branch": {
"type": "string"
},
"forge_url": {
"type": "string"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"owner": {
"type": "string"
},
"private": {
"type": "boolean"
},
"remote_id": {
"type": "string"
},
"scm": {
"type": "string"
},
"trusted": {
"$ref": "#/definitions/metadata.TrustedConfiguration"
}
}
},
"metadata.Step": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"number": {
"type": "integer"
}
}
},
"metadata.System": {
"type": "object",
"properties": {
"arch": {
"type": "string"
},
"host": {
"type": "string"
},
"name": {
"type": "string"
},
"url": {
"type": "string"
},
"version": {
"type": "string"
}
}
},
"metadata.TrustedConfiguration": {
"type": "object",
"properties": {
"network": {
"type": "boolean"
},
"security": {
"type": "boolean"
},
"volumes": {
"type": "boolean"
}
}
},
"metadata.Workflow": {
"type": "object",
"properties": {
"matrix": {
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"name": {
"type": "string"
},
"number": {
"type": "integer"
}
}
},
"model.ForgeType": {
"type": "string",
"enum": [
@ -5184,6 +5642,34 @@ const docTemplate = `{
"ForgeTypeAddon"
]
},
"model.TrustedConfiguration": {
"type": "object",
"properties": {
"network": {
"type": "boolean"
},
"security": {
"type": "boolean"
},
"volumes": {
"type": "boolean"
}
}
},
"model.TrustedConfigurationPatch": {
"type": "object",
"properties": {
"network": {
"type": "boolean"
},
"security": {
"type": "boolean"
},
"volumes": {
"type": "boolean"
}
}
},
"model.Workflow": {
"type": "object",
"properties": {
@ -5196,9 +5682,6 @@ const docTemplate = `{
"$ref": "#/definitions/Step"
}
},
"end_time": {
"type": "integer"
},
"environ": {
"type": "object",
"additionalProperties": {
@ -5208,6 +5691,9 @@ const docTemplate = `{
"error": {
"type": "string"
},
"finished": {
"type": "integer"
},
"id": {
"type": "integer"
},
@ -5223,7 +5709,7 @@ const docTemplate = `{
"platform": {
"type": "string"
},
"start_time": {
"started": {
"type": "integer"
},
"state": {

View file

@ -27,14 +27,34 @@ import (
var flags = append([]cli.Flag{
&cli.BoolFlag{
Sources: cli.EnvVars("WOODPECKER_LOG_XORM"),
Name: "log-xorm",
Usage: "enable xorm logging",
Sources: cli.EnvVars("WOODPECKER_DATABASE_LOG", "WOODPECKER_LOG_XORM"),
Name: "db-log",
Aliases: []string{"log-xorm"}, // TODO: remove in v4.0.0
Usage: "enable logging in database engine (currently xorm)",
},
&cli.BoolFlag{
Sources: cli.EnvVars("WOODPECKER_LOG_XORM_SQL"),
Name: "log-xorm-sql",
Usage: "enable xorm sql command logging",
Sources: cli.EnvVars("WOODPECKER_DATABASE_LOG_SQL", "WOODPECKER_LOG_XORM_SQL"),
Name: "db-log-sql",
Aliases: []string{"log-xorm-sql"}, // TODO: remove in v4.0.0
Usage: "enable logging of sql commands",
},
&cli.IntFlag{
Sources: cli.EnvVars("WOODPECKER_DATABASE_MAX_CONNECTIONS"),
Name: "db-max-open-connections",
Usage: "max connections xorm is allowed create",
Value: 100,
},
&cli.IntFlag{
Sources: cli.EnvVars("WOODPECKER_DATABASE_IDLE_CONNECTIONS"),
Name: "db-max-idle-connections",
Usage: "amount of connections xorm will hold open",
Value: 2,
},
&cli.DurationFlag{
Sources: cli.EnvVars("WOODPECKER_DATABASE_CONNECTION_TIMEOUT"),
Name: "db-max-connection-timeout",
Usage: "time an active connection is allowed to stay open",
Value: 3 * time.Second,
},
&cli.StringFlag{
Sources: cli.EnvVars("WOODPECKER_HOST"),
@ -135,10 +155,11 @@ var flags = append([]cli.Flag{
Value: []string{"push", "pull_request"},
},
&cli.StringFlag{
Sources: cli.EnvVars("WOODPECKER_DEFAULT_CLONE_IMAGE"),
Name: "default-clone-image",
Sources: cli.EnvVars("WOODPECKER_DEFAULT_CLONE_PLUGIN", "WOODPECKER_DEFAULT_CLONE_IMAGE"),
Name: "default-clone-plugin",
Aliases: []string{"default-clone-image"},
Usage: "The default docker image to be used when cloning the repo",
Value: constant.DefaultCloneImage,
Value: constant.DefaultClonePlugin,
},
&cli.IntFlag{
Sources: cli.EnvVars("WOODPECKER_DEFAULT_PIPELINE_TIMEOUT"),
@ -159,10 +180,15 @@ var flags = append([]cli.Flag{
Value: time.Hour * 72,
},
&cli.StringSliceFlag{
Sources: cli.EnvVars("WOODPECKER_ESCALATE"),
Name: "escalate",
Usage: "images to run in privileged mode",
Value: constant.PrivilegedPlugins,
Sources: cli.EnvVars("WOODPECKER_PLUGINS_PRIVILEGED"),
Name: "plugins-privileged",
Usage: "Allow plugins to run in privileged mode, if environment variable is defined but empty there will be none",
},
&cli.StringSliceFlag{
Sources: cli.EnvVars("WOODPECKER_PLUGINS_TRUSTED_CLONE"),
Name: "plugins-trusted-clone",
Usage: "Plugins which are trusted to handle the netrc info in clone steps",
Value: constant.TrustedClonePlugins,
},
&cli.StringSliceFlag{
Sources: cli.EnvVars("WOODPECKER_VOLUME"),
@ -199,7 +225,8 @@ var flags = append([]cli.Flag{
},
&cli.StringFlag{
Sources: cli.EnvVars("WOODPECKER_DATABASE_DRIVER"),
Name: "driver",
Name: "db-driver",
Aliases: []string{"driver"}, // TODO: remove in v4.0.0
Usage: "database driver",
Value: "sqlite3",
},
@ -207,9 +234,10 @@ var flags = append([]cli.Flag{
Sources: cli.NewValueSourceChain(
cli.File(os.Getenv("WOODPECKER_DATABASE_DATASOURCE_FILE")),
cli.EnvVar("WOODPECKER_DATABASE_DATASOURCE")),
Name: "datasource",
Usage: "database driver configuration string",
Value: datasourceDefaultValue(),
Name: "db-datasource",
Aliases: []string{"datasource"}, // TODO: remove in v4.0.0
Usage: "database driver configuration string",
Value: datasourceDefaultValue(),
},
&cli.StringFlag{
Sources: cli.NewValueSourceChain(
@ -281,7 +309,7 @@ var flags = append([]cli.Flag{
Sources: cli.EnvVars("WOODPECKER_FORGE_TIMEOUT"),
Name: "forge-timeout",
Usage: "how many seconds before timeout when fetching the Woodpecker configuration from a Forge",
Value: time.Second * 3,
Value: time.Second * 5,
},
&cli.UintFlag{
Sources: cli.EnvVars("WOODPECKER_FORGE_RETRY"),
@ -289,36 +317,8 @@ var flags = append([]cli.Flag{
Usage: "How many retries of fetching the Woodpecker configuration from a forge are done before we fail",
Value: 3,
},
&cli.IntFlag{
Sources: cli.EnvVars("WOODPECKER_LIMIT_MEM_SWAP"),
Name: "limit-mem-swap",
Usage: "maximum memory used for swap in bytes",
},
&cli.IntFlag{
Sources: cli.EnvVars("WOODPECKER_LIMIT_MEM"),
Name: "limit-mem",
Usage: "maximum memory allowed in bytes",
},
&cli.IntFlag{
Sources: cli.EnvVars("WOODPECKER_LIMIT_SHM_SIZE"),
Name: "limit-shm-size",
Usage: "docker compose /dev/shm allowed in bytes",
},
&cli.IntFlag{
Sources: cli.EnvVars("WOODPECKER_LIMIT_CPU_QUOTA"),
Name: "limit-cpu-quota",
Usage: "impose a cpu quota",
},
&cli.IntFlag{
Sources: cli.EnvVars("WOODPECKER_LIMIT_CPU_SHARES"),
Name: "limit-cpu-shares",
Usage: "change the cpu shares",
},
&cli.StringFlag{
Sources: cli.EnvVars("WOODPECKER_LIMIT_CPU_SET"),
Name: "limit-cpu-set",
Usage: "set the cpus allowed to execute containers",
},
//
// generic forge settings
//
&cli.StringFlag{
Name: "forge-url",
@ -477,7 +477,7 @@ var flags = append([]cli.Flag{
// expert flags
//
&cli.StringFlag{
Sources: cli.EnvVars("WOODPECKER_EXPERT_WEBHOOK_HOST", "WOODPECKER_WEBHOOK_HOST"), // TODO: remove WOODPECKER_WEBHOOK_HOST in next major release
Sources: cli.EnvVars("WOODPECKER_EXPERT_WEBHOOK_HOST"),
Name: "server-webhook-host",
Usage: "!!!for experts!!! fully qualified woodpecker server url called by forge's webhooks. Format: <scheme>://<host>[/<prefix path>]",
},

View file

@ -33,7 +33,7 @@ import (
func runGrpcServer(ctx context.Context, c *cli.Command, _store store.Store) error {
lis, err := net.Listen("tcp", c.String("grpc-addr"))
if err != nil {
log.Fatal().Err(err).Msg("failed to listen on grpc-addr") //nolint:forbidigo
return fmt.Errorf("failed to listen on grpc-addr: %w", err)
}
jwtSecret := c.String("grpc-secret")

View file

@ -43,7 +43,6 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/server/store"
"go.woodpecker-ci.org/woodpecker/v2/server/store/datastore"
"go.woodpecker-ci.org/woodpecker/v2/server/store/types"
"go.woodpecker-ci.org/woodpecker/v2/shared/constant"
)
const (
@ -52,11 +51,14 @@ const (
)
func setupStore(ctx context.Context, c *cli.Command) (store.Store, error) {
datasource := c.String("datasource")
driver := c.String("driver")
datasource := c.String("db-datasource")
driver := c.String("db-driver")
xorm := store.XORM{
Log: c.Bool("log-xorm"),
ShowSQL: c.Bool("log-xorm-sql"),
Log: c.Bool("db-log"),
ShowSQL: c.Bool("db-log-sql"),
MaxOpenConns: int(c.Int("db-max-open-connections")),
MaxIdleConns: int(c.Int("db-max-idle-connections")),
ConnMaxLifetime: c.Duration("db-max-connection-timeout"),
}
if driver == "sqlite3" {
@ -104,8 +106,11 @@ func checkSqliteFileExist(path string) error {
return err
}
func setupQueue(ctx context.Context, s store.Store) queue.Queue {
return queue.WithTaskStore(ctx, queue.New(ctx), s)
func setupQueue(ctx context.Context, s store.Store) (queue.Queue, error) {
return queue.New(ctx, queue.Config{
Backend: queue.TypeMemory,
Store: s,
})
}
func setupMembershipService(_ context.Context, _store store.Store) cache.MembershipService {
@ -144,18 +149,19 @@ func setupJWTSecret(_store store.Store) (string, error) {
return jwtSecret, nil
}
func setupEvilGlobals(ctx context.Context, c *cli.Command, s store.Store) error {
func setupEvilGlobals(ctx context.Context, c *cli.Command, s store.Store) (err error) {
// services
server.Config.Services.Queue = setupQueue(ctx, s)
server.Config.Services.Logs = logging.New()
server.Config.Services.Pubsub = pubsub.New()
server.Config.Services.Membership = setupMembershipService(ctx, s)
serviceManager, err := services.NewManager(c, s, setup.Forge)
server.Config.Services.Queue, err = setupQueue(ctx, s)
if err != nil {
return fmt.Errorf("could not setup queue: %w", err)
}
server.Config.Services.Manager, err = services.NewManager(c, s, setup.Forge)
if err != nil {
return fmt.Errorf("could not setup service manager: %w", err)
}
server.Config.Services.Manager = serviceManager
server.Config.Services.LogStore, err = setupLogStore(c, s)
if err != nil {
return fmt.Errorf("could not setup log store: %w", err)
@ -165,8 +171,9 @@ func setupEvilGlobals(ctx context.Context, c *cli.Command, s store.Store) error
server.Config.Pipeline.AuthenticatePublicRepos = c.Bool("authenticate-public-repos")
// Cloning
server.Config.Pipeline.DefaultCloneImage = c.String("default-clone-image")
constant.TrustedCloneImages = append(constant.TrustedCloneImages, server.Config.Pipeline.DefaultCloneImage)
server.Config.Pipeline.DefaultClonePlugin = c.String("default-clone-plugin")
server.Config.Pipeline.TrustedClonePlugins = c.StringSlice("plugins-trusted-clone")
server.Config.Pipeline.TrustedClonePlugins = append(server.Config.Pipeline.TrustedClonePlugins, server.Config.Pipeline.DefaultClonePlugin)
// Execution
_events := c.StringSlice("default-cancel-previous-pipeline-events")
@ -178,14 +185,6 @@ func setupEvilGlobals(ctx context.Context, c *cli.Command, s store.Store) error
server.Config.Pipeline.DefaultTimeout = c.Int("default-pipeline-timeout")
server.Config.Pipeline.MaxTimeout = c.Int("max-pipeline-timeout")
// limits
server.Config.Pipeline.Limits.MemSwapLimit = c.Int("limit-mem-swap")
server.Config.Pipeline.Limits.MemLimit = c.Int("limit-mem")
server.Config.Pipeline.Limits.ShmSize = c.Int("limit-shm-size")
server.Config.Pipeline.Limits.CPUQuota = c.Int("limit-cpu-quota")
server.Config.Pipeline.Limits.CPUShares = c.Int("limit-cpu-shares")
server.Config.Pipeline.Limits.CPUSet = c.String("limit-cpu-set")
// backend options for pipeline compiler
server.Config.Pipeline.Proxy.No = c.String("backend-no-proxy")
server.Config.Pipeline.Proxy.HTTP = c.String("backend-http-proxy")
@ -222,9 +221,9 @@ func setupEvilGlobals(ctx context.Context, c *cli.Command, s store.Store) error
server.Config.Server.CustomJsFile = strings.TrimSpace(c.String("custom-js-file"))
server.Config.Pipeline.Networks = c.StringSlice("network")
server.Config.Pipeline.Volumes = c.StringSlice("volume")
server.Config.Pipeline.Privileged = c.StringSlice("escalate")
server.Config.WebUI.EnableSwagger = c.Bool("enable-swagger")
server.Config.WebUI.SkipVersionCheck = c.Bool("skip-version-check")
server.Config.Pipeline.PrivilegedPlugins = c.StringSlice("plugins-privileged")
// prometheus
server.Config.Prometheus.AuthToken = c.String("prometheus-auth-token")

View file

@ -33,7 +33,7 @@ func setupSwaggerStaticConfig() {
docs.SwaggerInfo.InfoInstanceName = "api"
docs.SwaggerInfo.Title = "Woodpecker CI API"
docs.SwaggerInfo.Version = version.String()
docs.SwaggerInfo.Description = "Woodpecker is a simple yet powerful CI/CD engine with great extensibility.\n" +
docs.SwaggerInfo.Description = "Woodpecker is a simple, yet powerful CI/CD engine with great extensibility.\n" +
"To get a personal access token (PAT) for authentication, please log in your Woodpecker server,\n" +
"and go to you personal profile page, by clicking the user icon at the top right."
}

View file

@ -24,6 +24,7 @@ package main
import (
"context"
"encoding/json"
"fmt"
"os"
"path"
@ -57,6 +58,7 @@ func main() {
// convert to OpenApi3
if err := toOpenApi3(filePath, filePath); err != nil {
fmt.Printf("converting '%s' from openapi v2 to v3 failed\n", filePath)
panic(err)
}
}
@ -77,18 +79,18 @@ func removeHost(jsonIn string) (string, error) {
func toOpenApi3(input, output string) error {
data2, err := os.ReadFile(input)
if err != nil {
return err
return fmt.Errorf("read input: %w", err)
}
var doc2 openapi2.T
err = json.Unmarshal(data2, &doc2)
if err != nil {
return err
return fmt.Errorf("unmarshal input: %w", err)
}
doc3, err := openapi2conv.ToV3(&doc2)
if err != nil {
return err
return fmt.Errorf("convert openapi v2 to v3: %w", err)
}
err = doc3.Validate(context.Background())
if err != nil {
@ -97,8 +99,12 @@ func toOpenApi3(input, output string) error {
data, err := json.Marshal(doc3)
if err != nil {
return err
return fmt.Errorf("Marshal converted: %w", err)
}
return os.WriteFile(output, data, 0o644)
if err = os.WriteFile(output, data, 0o644); err != nil {
return fmt.Errorf("write output: %w", err)
}
return nil
}

View file

@ -3,7 +3,7 @@ version: '3'
services:
gitea-database:
image: postgres:16.3-alpine
image: postgres:17.0-alpine
environment:
POSTGRES_USER: gitea
POSTGRES_PASSWORD: 123456

View file

@ -1,4 +1,4 @@
FROM --platform=$BUILDPLATFORM docker.io/golang:1.22 AS build
FROM --platform=$BUILDPLATFORM docker.io/golang:1.23 AS build
WORKDIR /src
COPY . .
@ -10,6 +10,8 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
FROM docker.io/alpine:3.20
RUN apk add -U --no-cache ca-certificates
ENV GODEBUG=netdns=go
# Internal setting do NOT change! Signals that woodpecker is running inside a container
ENV WOODPECKER_IN_CONTAINER=true
EXPOSE 3000
COPY --from=build /src/dist/woodpecker-agent /bin/

View file

@ -1,4 +1,4 @@
FROM --platform=$BUILDPLATFORM docker.io/golang:1.22 AS build
FROM --platform=$BUILDPLATFORM docker.io/golang:1.23 AS build
WORKDIR /src
COPY . .
@ -10,6 +10,8 @@ RUN mkdir -p /etc/woodpecker
FROM scratch
ENV GODEBUG=netdns=go
# Internal setting do NOT change! Signals that woodpecker is running inside a container
ENV WOODPECKER_IN_CONTAINER=true
EXPOSE 3000
# copy certs from build image

View file

@ -1,4 +1,4 @@
FROM --platform=$BUILDPLATFORM docker.io/golang:1.22 AS build
FROM --platform=$BUILDPLATFORM docker.io/golang:1.23 AS build
WORKDIR /src
COPY . .
@ -8,7 +8,10 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
make build-cli
FROM docker.io/alpine:3.20
WORKDIR /woodpecker
RUN apk add -U --no-cache ca-certificates
ENV GODEBUG=netdns=go
ENV WOODPECKER_DISABLE_UPDATE_CHECK=true

View file

@ -1,4 +1,4 @@
FROM --platform=$BUILDPLATFORM docker.io/golang:1.22 AS build
FROM --platform=$BUILDPLATFORM docker.io/golang:1.23 AS build
WORKDIR /src
COPY . .
@ -8,6 +8,8 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
make build-cli
FROM scratch
WORKDIR /woodpecker
ENV GODEBUG=netdns=go
ENV WOODPECKER_DISABLE_UPDATE_CHECK=true

View file

@ -1,19 +1,8 @@
# docker build --rm -f docker/Dockerfile.make -t woodpecker/make:local .
FROM docker.io/golang:1.22-alpine3.19 as golang_image
FROM docker.io/node:22-alpine3.19
FROM docker.io/golang:1.23-alpine as golang_image
FROM docker.io/node:23-alpine
# renovate: datasource=repology depName=alpine_3_19/make versioning=loose
ENV MAKE_VERSION="4.4.1-r2"
# renovate: datasource=repology depName=alpine_3_19/gcc versioning=loose
ENV GCC_VERSION="13.2.1_git20231014-r0"
# renovate: datasource=repology depName=alpine_3_19/binutils-gold versioning=loose
ENV BINUTILS_GOLD_VERSION="2.41-r0"
# renovate: datasource=repology depName=alpine_3_19/musl-dev versioning=loose
ENV MUSL_DEV_VERSION="1.2.4_git20230717-r4"
# renovate: datasource=repology depName=alpine_3_19/protoc versioning=loose
ENV PROTOC_VERSION="24.4-r0"
RUN apk add --no-cache --update make=${MAKE_VERSION} gcc=${GCC_VERSION} binutils-gold=${BINUTILS_GOLD_VERSION} musl-dev=${MUSL_DEV_VERSION} protoc=${PROTOC_VERSION} && \
RUN apk add --no-cache --update make gcc binutils-gold musl-dev protoc && \
corepack enable
# Build packages.

View file

@ -1,4 +1,4 @@
FROM --platform=$BUILDPLATFORM docker.io/golang:1.22 AS certs
FROM --platform=$BUILDPLATFORM docker.io/golang:1.23 AS certs
FROM scratch
ARG TARGETOS TARGETARCH

View file

@ -53,7 +53,7 @@ Security is pretty important to us and we want to make sure that no one can stea
## Migration notes
There have been a few more breaking changes. [Read more about what you need to do when upgrading!](../docs/migrations#200)
There have been a few more breaking changes. [Read more about what you need to do when upgrading!](/migrations#200)
## New features

View file

@ -0,0 +1,60 @@
---
title: '[Community] Podman-in-Podman image builds'
description: Build images in Podman with buildah
slug: podman-image-builds
authors:
- name: handlebargh
url: https://github.com/handlebargh
image_url: https://github.com/handlebargh.png
hide_table_of_contents: true
tags: [community, image, podman]
---
<!-- cspell:ignore buildah Containerfile roundcube -->
I run Woodpecker CI with podman backend instead of docker and just figured out how to build images with buildah. Since I couldn't find this anywhere documented, I thought I might as well just share it here.
<!-- truncate -->
It's actually pretty straight forward. Here's what my repository structure looks like:
```bash
.
├── roundcube
│   ├── Containerfile
│   ├── docker-entrypoint.sh
│   └── php.ini
└── .woodpecker
└── .build_roundcube.yml
```
As you can see I'm building a roundcube mail image.
This is the `.woodpecker/.build_roundcube.yaml`
```yaml
when:
event: [cron, manual]
cron: build_roundcube
steps:
build-image:
image: quay.io/buildah/stable:latest
pull: true
privileged: true
commands:
- echo $REGISTRY_LOGIN_TOKEN | buildah login -u <username> --password-stdin registry.gitlab.com
- cd roundcube
- buildah build --tag registry.gitlab.com/<namespace>/<repository_name>/roundcube:latest .
- buildah push registry.gitlab.com/<namespace>/<repository_name>/roundcube:latest
secrets: [registry_login_token]
```
As you can see, I'm using this workflow over at gitlab.com. It should work with GitHub as well, with adjusting the registry login.
You may have to adjust the `when:` to your needs. Furthermore, you must check the `trusted` checkbox in project settings. Therefore, be sure to run trusted code only in this setup.
This seems to work fine so far. I wonder if anybody else made this work a different way.
EDIT: Removed the additional step that would run buildah in a podman container. I didn't know it could be that easy to be honest.

View file

@ -0,0 +1,31 @@
---
title: '[Community] Debug pipeline steps'
description: Debug pipeline steps using sshx
slug: debug-pipeline-steps
authors:
- name: anbraten
url: https://github.com/anbraten
image_url: https://github.com/anbraten.png
hide_table_of_contents: true
tags: [community, debug]
---
<!-- cspell:ignore sshx -->
Sometimes you want to debug a pipeline.
Therefore I recently discovered: <https://github.com/ekzhang/sshx>
<!-- truncate -->
A simple step like should allow you to debug:
```yaml
steps:
- name: debug
image: alpine
commands:
- curl -sSf https://sshx.io/get | sh && sshx
# ^
# └ This will open a remote terminal session and print the URL. It
# should take under a second.
```

View file

@ -0,0 +1,140 @@
---
title: '[Community] Podman image build with sigstore'
description: Build images in Podman with sigstore signature checking and signing
slug: podman-image-build-sigstore
authors:
- name: handlebargh
url: https://github.com/handlebargh
image_url: https://github.com/handlebargh.png
hide_table_of_contents: false
tags: [community, image, podman, sigstore, signature]
---
<!-- cspell:ignore BQVUJ Containerfile cosing distroless fulcio keypair nonroot QVRFLS rekor skopeo -->
This example shows how to build a container image with podman while verifying the base image and signing the resulting image.
<!-- truncate -->
The image being pulled uses a keyless signature, while the image being built will be signed by a pre-generated private key.
## Prerequisites
### Generate signing keypair
You can use cosing or skopeo to generate the keypair.
Using skopeo:
```bash
skopeo generate-sigstore-key --output-prefix myKey
```
This command will generate a `myKey.private` and a `myKey.pub` keyfile.
Store the `myKey.private` as secret in Woodpecker. In the example below, the secret is called `sigstore_private_key`
### Configure hosts pulling the resulting image
See [here](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/building_running_and_managing_containers/assembly_signing-container-images_building-running-and-managing-containers#proc_verifying-sigstore-image-signatures-using-a-public-key_assembly_signing-container-images) on how to configure the hosts pulling the built and signed image.
## Repository structure
Consider the `Makefile` having a `build` target that will be used in the following workflow.
This target yields a Go binary with the filename `app` that will be placed in the root directory.
```bash
.
├── Containerfile
├── main.go
├── go.mod
├── go.sum
├── .woodpecker.yml
└── Makefile
```
### Containerfile
The Containerfile refers to the base image that will be verified when pulled.
```dockerfile
FROM gcr.io/distroless/static-debian12:nonroot
COPY app /app
CMD ["/app"]
```
### Woodpecker workflow
```yaml
steps:
build:
image: docker.io/library/golang:1.21
pull: true
commands:
- make build
publish:
image: quay.io/podman/stable:latest
# Caution: This image is built daily. It might fill up your image store quickly.
pull: true
# Fill in the trusted checkbox in Woodpecker's settings as well
privileged: true
commands:
# Configure podman to use sigstore attachments for both, the registry you pull from and the registry you push to.
- |
printf "docker:
registry.gitlab.com:
use-sigstore-attachments: true
gcr.io:
use-sigstore-attachments: true" >> /etc/containers/registries.d/default.yaml
# At pull, check the keyless sigstore signature of the distroless image.
# This is a very strict container policy. It allows pulling from gcr.io/distroless only. Every other registry will be rejected.
# See https://github.com/containers/image/blob/main/docs/containers-policy.json.5.md for more information.
# fulcio CA crt obtained from https://github.com/sigstore/sigstore/blob/main/pkg/tuf/repository/targets/fulcio_v1.crt.pem
# rekor public key obtained from https://github.com/sigstore/sigstore/blob/main/pkg/tuf/repository/targets/rekor.pub
# crt/key data is base64 encoded. --> echo "$CERT" | base64
- |
printf '{
"default": [
{
"type": "reject"
}
],
"transports": {
"docker": {
"gcr.io/distroless": [
{
"type": "sigstoreSigned",
"fulcio": {
"caData": "LS0tLS1CRUdJTiBDR...QVRFLS0tLS0K",
"oidcIssuer": "https://accounts.google.com",
"subjectEmail": "keyless@distroless.iam.gserviceaccount.com"
},
"rekorPublicKeyData": "LS0tLS1CRUdJTiBQVUJ...lDIEtFWS0tLS0tCg==",
"signedIdentity": { "type": "matchRepository" }
}
]
},
"docker-daemon": {
"": [
{
"type": "reject"
}
]
}
}
}' > /etc/containers/policy.json
# Use this key to sign the built image at push.
- echo "$SIGSTORE_PRIVATE_KEY" > key.private
# Login at the registry
- echo $REGISTRY_LOGIN_TOKEN | podman login -u <username> --password-stdin registry.gitlab.com
# Build the container image
- podman build --tag registry.gitlab.com/<namespace>/<repository_name>/<image_name>:latest .
# Sign and push the image
- podman push --sign-by-sigstore-private-key ./key.private registry.gitlab.com/<namespace>/<repository_name>/<image_name>:latest
secrets: [sigstore_private_key, registry_login_token]
```

View file

@ -87,4 +87,4 @@ be removed in the next major release:
- Use `WOODPECKER_EXPERT_FORGE_OAUTH_HOST` instead of `WOODPECKER_DEV_GITEA_OAUTH_URL` or `WOODPECKER_DEV_OAUTH_HOST`
- Deprecated `WOODPECKER_WEBHOOK_HOST` in favor of `WOODPECKER_EXPERT_WEBHOOK_HOST`
For a full list of deprecations that will be dropped in the `next` major release `3.0.0` (no eta yet), please check the [migrations](/docs/migrations#next) section.
For a full list of deprecations that will be dropped in the `next` major release `3.0.0` (no eta yet), please check the [migrations](/migrations#next) section.

View file

@ -86,16 +86,17 @@ Sometimes you have some tasks that you need to do in every project. For example,
If you want to get a Slack notification after your pipeline has finished, you can add a Slack plugin to your pipeline:
```yaml
---
- name: notify me on Slack
image: plugins/slack
settings:
channel: developers
username: woodpecker
password:
from_secret: slack_token
when:
status: [success, failure] # This will execute the step on success and failure
steps:
# ...
- name: notify me on Slack
image: plugins/slack
settings:
channel: developers
username: woodpecker
password:
from_secret: slack_token
when:
status: [success, failure] # This will execute the step on success and failure
```
To configure a plugin you can use the `settings` section.

View file

@ -7,18 +7,18 @@
- **Server**: The component of Woodpecker that handles webhooks from forges, orchestrates agents, and sends status back. It also serves the API and web UI for administration and configuration.
- **Agent**: A component of Woodpecker that executes [pipelines][Pipeline] (specifically one or more [workflows][Workflow]) with a specific backend (e.g. [Docker][], Kubernetes, [local][Local]). It connects to the server via GRPC.
- **CLI**: The Woodpecker command-line interface (CLI) is a terminal tool used to administer the server, to execute pipelines locally for debugging / testing purposes, and to perform tasks like linting pipelines.
- **Pipeline**: A sequence of [workflows][Workflow] that are executed on the code. [Pipelines][Pipeline] are triggered by events.
- **Workflow**: A sequence of steps and services that are executed as part of a [pipeline][Pipeline]. Workflows are represented by YAML files. Each [workflow][Workflow] has its own isolated [workspace][Workspace], and often additional resources like a shared network (docker).
- **[Pipeline][Pipeline]**: A sequence of [workflows][Workflow] that are executed on the code. Pipelines are triggered by events.
- **[Workflow][Workflow]**: A sequence of steps and services that are executed as part of a [pipeline][Pipeline]. Workflows are represented by YAML files. Each workflow has its own isolated [workspace][Workspace], and often additional resources like a shared network (docker).
- **Steps**: Individual commands, actions or tasks within a [workflow][Workflow].
- **Code**: Refers to the files tracked by the version control system used by the [forge][Forge].
- **Repos**: Short for repositories, these are storage locations where code is stored.
- **Forge**: The hosting platform or service where the repositories are hosted.
- **Workspace**: A folder shared between all steps of a [workflow][Workflow] containing the repository and all the generated data from previous steps.
- **Event**: Triggers the execution of a [pipeline][Pipeline], such as a [forge][Forge] event like `push`, or `manual` triggered manually from the UI.
- **[Forge][Forge]**: The hosting platform or service where the repositories are hosted.
- **[Workspace][workspace]**: A folder shared between all steps of a [workflow][Workflow] containing the repository and all the generated data from previous steps.
- **[Event][Event]**: Triggers the execution of a [pipeline][Pipeline], such as a [forge][Forge] event like `push`, or `manual` triggered manually from the UI.
- **Commit**: A defined state of the code, usually associated with a version control system like Git.
- **Matrix**: A configuration option that allows the execution of [workflows][Workflow] for each value in the [matrix][Matrix].
- **[Matrix][Matrix]**: A configuration option that allows the execution of [workflows][Workflow] for each value in the matrix.
- **Service**: A service is a step that is executed from the start of a [workflow][Workflow] until its end. It can be accessed by name via the network from other steps within the same [workflow][Workflow].
- **Plugins**: [Plugins][Plugin] are extensions that provide pre-defined actions or commands for a step in a [workflow][Workflow]. They can be configured via settings.
- **[Plugins][Plugin]**: Plugins are extensions that provide pre-defined actions or commands for a step in a [workflow][Workflow]. They can be configured via settings.
- **Container**: A lightweight and isolated environment where commands are executed.
- **YAML File**: A file format used to define and configure [workflows][Workflow].
- **Dependency**: [Workflows][Workflow] can depend on each other, and if possible, they are executed in parallel.
@ -33,16 +33,6 @@
![Relation between pipelines, workflows and steps](pipeline-workflow-step.svg)
## Pipeline events
- `push`: A push event is triggered when a commit is pushed to a branch.
- `pull_request`: A pull request event is triggered when a pull request is opened or a new commit is pushed to it.
- `pull_request_closed`: A pull request closed event is triggered when a pull request is closed or merged.
- `tag`: A tag event is triggered when a tag is pushed.
- `release`: A release event is triggered when a release, pre-release or draft is created. (You can apply further filters using [evaluate](../20-workflow-syntax.md#evaluate) with [environment variables](../50-environment.md#built-in-environment-variables).)
- `manual`: A manual event is triggered when a user manually triggers a pipeline.
- `cron`: A cron event is triggered when a cron job is executed.
## Conventions
Sometimes there are multiple terms that can be used to describe something. This section lists the preferred terms to use in Woodpecker:
@ -54,6 +44,7 @@ Sometimes there are multiple terms that can be used to describe something. This
<!-- References -->
[Event]: ../20-workflow-syntax.md#event
[Pipeline]: ../20-workflow-syntax.md
[Workflow]: ../25-workflows.md
[Forge]: ../../30-administration/11-forges/11-overview.md

View file

@ -104,7 +104,7 @@ When using the `local` backend, the `image` entry is used to specify the shell,
- go test
- name: publish
+ image: plugins/docker
+ image: woodpeckerci/plugin-kaniko
repo: foo/bar
services:
@ -179,12 +179,6 @@ Woodpecker provides the ability to pass environment variables to individual step
For more details, check the [environment docs](./50-environment.md).
### `secrets`
Woodpecker provides the ability to store named parameters external to the YAML configuration file, in a central secret store. These secrets can be passed to individual steps of the workflow at runtime.
For more details, check the [secrets docs](./40-secrets.md).
### `failure`
Some of the steps may be allowed to fail without causing the whole workflow and therefore pipeline to report a failure (e.g., a step executing a linting check). To enable this, add `failure: ignore` to your step. If Woodpecker encounters an error while executing the step, it will report it as failed but still executes the next steps of the workflow, if any, without affecting the status of the workflow.
@ -288,7 +282,16 @@ when:
#### `event`
Available events: `push`, `pull_request`, `pull_request_closed`, `tag`, `release`, `deployment`, `cron`, `manual`
The available events are:
- `push`: triggered when a commit is pushed to a branch.
- `pull_request`: triggered when a pull request is opened or a new commit is pushed to it.
- `pull_request_closed`: triggered when a pull request is closed or merged.
- `tag`: triggered when a tag is pushed.
- `release`: triggered when a release, pre-release or draft is created. (You can apply further filters using [evaluate](#evaluate) with [environment variables](./50-environment.md#built-in-environment-variables).)
- `deployment` (only available for GitHub): triggered when a deployment is created in the repository.
- `cron`: triggered when a cron job is executed.
- `manual`: triggered when a user manually triggers a pipeline.
Execute a step if the build event is a `tag`:
@ -475,7 +478,7 @@ Normally steps of a workflow are executed serially in the order in which they ar
- go build
- name: deploy
image: plugins/docker
image: woodpeckerci/plugin-kaniko
settings:
repo: foo/bar
+ depends_on: [build, test] # deploy will be executed after build and test finished
@ -601,7 +604,7 @@ For more details check the [matrix build docs](./30-matrix-workflows.md).
You can set labels for your workflow to select an agent to execute the workflow on. An agent will pick up and run a workflow when **every** label assigned to it matches the agents labels.
To set additional agent labels, check the [agent configuration options](../30-administration/15-agent-config.md#woodpecker_filter_labels). Agents will have at least four default labels: `platform=agent-os/agent-arch`, `hostname=my-agent`, `backend=docker` (type of the agent backend) and `repo=*`. Agents can use a `*` as a wildcard for a label. For example `repo=*` will match every repo.
To set additional agent labels, check the [agent configuration options](../30-administration/15-agent-config.md#woodpecker_agent_labels). Agents will have at least four default labels: `platform=agent-os/agent-arch`, `hostname=my-agent`, `backend=docker` (type of the agent backend) and `repo=*`. Agents can use a `*` as a wildcard for a label. For example `repo=*` will match every repo.
Workflow labels with an empty value will be ignored.
By default, each workflow has at least the `repo=your-user/your-repo-name` label. If you have set the [platform attribute](#platform) for your workflow it will have a label like `platform=your-os/your-arch` as well.

View file

@ -23,13 +23,13 @@ If you still need to pass artifacts between the workflows you need use some stor
```bash
.woodpecker/
├── .build.yaml
├── .deploy.yaml
├── .lint.yaml
└── .test.yaml
├── build.yaml
├── deploy.yaml
├── lint.yaml
└── test.yaml
```
```yaml title=".woodpecker/.build.yaml"
```yaml title=".woodpecker/build.yaml"
steps:
- name: build
image: debian:stable-slim
@ -38,7 +38,7 @@ steps:
- sleep 5
```
```yaml title=".woodpecker/.deploy.yaml"
```yaml title=".woodpecker/deploy.yaml"
steps:
- name: deploy
image: debian:stable-slim
@ -51,7 +51,7 @@ depends_on:
- test
```
```yaml title=".woodpecker/.test.yaml"
```yaml title=".woodpecker/test.yaml"
steps:
- name: test
image: debian:stable-slim
@ -63,7 +63,7 @@ depends_on:
- build
```
```yaml title=".woodpecker/.lint.yaml"
```yaml title=".woodpecker/lint.yaml"
steps:
- name: lint
image: debian:stable-slim

View file

@ -11,26 +11,7 @@ Woodpecker provides three different levels to add secrets to your pipeline. The
## Usage
### Use secrets in commands
Secrets are exposed to your pipeline steps and plugins as uppercase environment variables and can therefore be referenced in the commands section of your pipeline,
once their usage is declared in the `secrets` section:
```diff
steps:
- name: docker
image: docker
commands:
+ - echo $docker_username
+ - echo $DOCKER_PASSWORD
+ secrets: [ docker_username, DOCKER_PASSWORD ]
```
The case of the environment variables is not changed, but secret matching is done case-insensitively. In the example above, `DOCKER_PASSWORD` would also match if the secret is called `docker_password`.
### Use secrets in settings and environment
You can set an setting or environment value from secrets using the `from_secret` syntax.
You can set a setting or an environment value from secrets using the `from_secret` syntax.
In this example, the secret named `secret_token` would be passed to the setting named `token`,which will be available in the plugin as environment variable named `PLUGIN_TOKEN` (See [plugins](./51-plugins/20-creating-plugins.md#settings) for details), and to the environment variable `TOKEN_ENV`.
@ -55,11 +36,11 @@ Please note parameter expressions are subject to pre-processing. When using secr
- name: docker
image: docker
commands:
- - echo ${docker_username}
- - echo ${DOCKER_PASSWORD}
+ - echo $${docker_username}
+ - echo $${DOCKER_PASSWORD}
secrets: [ docker_username, DOCKER_PASSWORD ]
- - echo ${TOKEN_ENV}
+ - echo $${TOKEN_ENV}
environment:
TOKEN_ENV:
from_secret: secret_token
```
### Use in Pull Requests events
@ -70,9 +51,16 @@ Secrets are not exposed to pull requests by default. You can override this behav
Please be careful when exposing secrets to pull requests. If your repository is open source and accepts pull requests your secrets are not safe. A bad actor can submit a malicious pull request that exposes your secrets.
:::
## Image filter
## Plugins filter
To prevent abusing your secrets from malicious usage, you can limit a secret to a list of images. If enabled they are not available to any other plugin (steps without user-defined commands). If you or an attacker defines explicit commands, the secrets will not be available to the container to prevent leaking them.
To prevent abusing your secrets from malicious usage, you can limit a secret to a list of plugins. If enabled they are not available to any other plugin (steps without user-defined commands). If you or an attacker defines explicit commands, the secrets will not be available to the container to prevent leaking them.
:::note
If you specify a tag, the filter will respect it.
Just make sure you don't specify the same image without one, otherwise it will be ignored again.
:::
![plugins filter](./secrets-plugins-filter.png)
## Adding Secrets

View file

@ -35,10 +35,6 @@ Example registry hostname matching logic:
- Hostname `docker.io` matches `bradrydzewski/golang`
- Hostname `docker.io` matches `bradrydzewski/golang:latest`
:::note
The flow above doesn't work in Kubernetes. There is [workaround](../30-administration/22-backends/40-kubernetes.md#images-from-private-registries).
:::
## Global registry support
To make a private registry globally available, check the [server configuration docs](../30-administration/10-server-config.md#global-registry-setting).

View file

@ -23,12 +23,6 @@ To configure cron jobs you need at least push access to the repository.
![cron settings](./cron-settings.png)
The supported schedule syntax can be found at <https://pkg.go.dev/github.com/robfig/cron?utm_source=godoc#hdr-CRON_Expression_Format>. If you need general understanding of the cron syntax <https://it-tools.tech/crontab-generator> is a good place to start and experiment.
The supported schedule syntax can be found at <https://pkg.go.dev/github.com/gdgvda/cron#hdr-CRON_Expression_Format>. If you need general understanding of the cron syntax <https://it-tools.tech/crontab-generator> is a good place to start and experiment.
Examples: `@every 5m`, `@daily`, `0 30 * * * *` ...
:::info
Woodpeckers cron syntax starts with seconds instead of minutes as used by most linux cron schedulers.
Example: "At minute 30 every hour" would be `0 30 * * * *` instead of `30 * * * *`
:::
Examples: `@every 5m`, `@daily`, `30 * * * *` ...

View file

@ -48,97 +48,95 @@ Please note that the environment section is not able to expand environment varia
This is the reference list of all environment variables available to your pipeline containers. These are injected into your pipeline step and plugins containers, at runtime.
| NAME | Description |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `CI` | CI environment name (value: `woodpecker`) |
| | **Repository** |
| `CI_REPO` | repository full name `<owner>/<name>` |
| `CI_REPO_OWNER` | repository owner |
| `CI_REPO_NAME` | repository name |
| `CI_REPO_REMOTE_ID` | repository remote ID, is the UID it has in the forge |
| `CI_REPO_SCM` | repository SCM (git) |
| `CI_REPO_URL` | repository web URL |
| `CI_REPO_CLONE_URL` | repository clone URL |
| `CI_REPO_CLONE_SSH_URL` | repository SSH clone URL |
| `CI_REPO_DEFAULT_BRANCH` | repository default branch (main) |
| `CI_REPO_PRIVATE` | repository is private |
| `CI_REPO_TRUSTED` | repository is trusted |
| | **Current Commit** |
| `CI_COMMIT_SHA` | commit SHA |
| `CI_COMMIT_REF` | commit ref |
| `CI_COMMIT_REFSPEC` | commit ref spec |
| `CI_COMMIT_BRANCH` | commit branch (equals target branch for pull requests) |
| `CI_COMMIT_SOURCE_BRANCH` | commit source branch (empty if event is not `pull_request` or `pull_request_closed`) |
| `CI_COMMIT_TARGET_BRANCH` | commit target branch (empty if event is not `pull_request` or `pull_request_closed`) |
| `CI_COMMIT_TAG` | commit tag name (empty if event is not `tag`) |
| `CI_COMMIT_PULL_REQUEST` | commit pull request number (empty if event is not `pull_request` or `pull_request_closed`) |
| `CI_COMMIT_PULL_REQUEST_LABELS` | labels assigned to pull request (empty if event is not `pull_request` or `pull_request_closed`) |
| `CI_COMMIT_MESSAGE` | commit message |
| `CI_COMMIT_AUTHOR` | commit author username |
| `CI_COMMIT_AUTHOR_EMAIL` | commit author email address |
| `CI_COMMIT_AUTHOR_AVATAR` | commit author avatar |
| `CI_COMMIT_PRERELEASE` | release is a pre-release (empty if event is not `release`) |
| | **Current pipeline** |
| `CI_PIPELINE_NUMBER` | pipeline number |
| `CI_PIPELINE_PARENT` | number of parent pipeline |
| `CI_PIPELINE_EVENT` | pipeline event (see [pipeline events](../20-usage/15-terminology/index.md#pipeline-events)) |
| `CI_PIPELINE_URL` | link to the web UI for the pipeline |
| `CI_PIPELINE_FORGE_URL` | link to the forge's web UI for the commit(s) or tag that triggered the pipeline |
| `CI_PIPELINE_DEPLOY_TARGET` | pipeline deploy target for `deployment` events (i.e. production) |
| `CI_PIPELINE_DEPLOY_TASK` | pipeline deploy task for `deployment` events (i.e. migration) |
| `CI_PIPELINE_STATUS` | pipeline status (success, failure) |
| `CI_PIPELINE_CREATED` | pipeline created UNIX timestamp |
| `CI_PIPELINE_STARTED` | pipeline started UNIX timestamp |
| `CI_PIPELINE_FINISHED` | pipeline finished UNIX timestamp |
| `CI_PIPELINE_FILES` | changed files (empty if event is not `push` or `pull_request`), it is undefined if more than 500 files are touched |
| | **Current workflow** |
| `CI_WORKFLOW_NAME` | workflow name |
| | **Current step** |
| `CI_STEP_NAME` | step name |
| `CI_STEP_NUMBER` | step number |
| `CI_STEP_STATUS` | step status (success, failure) |
| `CI_STEP_STARTED` | step started UNIX timestamp |
| `CI_STEP_FINISHED` | step finished UNIX timestamp |
| `CI_STEP_URL` | URL to step in UI |
| | **Previous commit** |
| `CI_PREV_COMMIT_SHA` | previous commit SHA |
| `CI_PREV_COMMIT_REF` | previous commit ref |
| `CI_PREV_COMMIT_REFSPEC` | previous commit ref spec |
| `CI_PREV_COMMIT_BRANCH` | previous commit branch |
| `CI_PREV_COMMIT_SOURCE_BRANCH` | previous commit source branch |
| `CI_PREV_COMMIT_TARGET_BRANCH` | previous commit target branch |
| `CI_PREV_COMMIT_URL` | previous commit link in forge |
| `CI_PREV_COMMIT_MESSAGE` | previous commit message |
| `CI_PREV_COMMIT_AUTHOR` | previous commit author username |
| `CI_PREV_COMMIT_AUTHOR_EMAIL` | previous commit author email address |
| `CI_PREV_COMMIT_AUTHOR_AVATAR` | previous commit author avatar |
| | **Previous pipeline** |
| `CI_PREV_PIPELINE_NUMBER` | previous pipeline number |
| `CI_PREV_PIPELINE_PARENT` | previous pipeline number of parent pipeline |
| `CI_PREV_PIPELINE_EVENT` | previous pipeline event (see [pipeline events](../20-usage/15-terminology/index.md#pipeline-events)) |
| `CI_PREV_PIPELINE_URL` | previous pipeline link in CI |
| `CI_PREV_PIPELINE_FORGE_URL` | previous pipeline link to event in forge |
| `CI_PREV_PIPELINE_DEPLOY_TARGET` | previous pipeline deploy target for `deployment` events (ie production) |
| `CI_PREV_PIPELINE_DEPLOY_TASK` | previous pipeline deploy task for `deployment` events (ie migration) |
| `CI_PREV_PIPELINE_STATUS` | previous pipeline status (success, failure) |
| `CI_PREV_PIPELINE_CREATED` | previous pipeline created UNIX timestamp |
| `CI_PREV_PIPELINE_STARTED` | previous pipeline started UNIX timestamp |
| `CI_PREV_PIPELINE_FINISHED` | previous pipeline finished UNIX timestamp |
| | &emsp; |
| `CI_WORKSPACE` | Path of the workspace where source code gets cloned to |
| | **System** |
| `CI_SYSTEM_NAME` | name of the CI system: `woodpecker` |
| `CI_SYSTEM_URL` | link to CI system |
| `CI_SYSTEM_HOST` | hostname of CI server |
| `CI_SYSTEM_VERSION` | version of the server |
| | **Forge** |
| `CI_FORGE_TYPE` | name of forge (gitea, github, ...) |
| `CI_FORGE_URL` | root URL of configured forge |
| | **Internal** - Please don't use! |
| `CI_SCRIPT` | Internal script path. Used to call pipeline step commands. |
| `CI_NETRC_USERNAME` | Credentials for private repos to be able to clone data. (Only available for specific images) |
| `CI_NETRC_PASSWORD` | Credentials for private repos to be able to clone data. (Only available for specific images) |
| `CI_NETRC_MACHINE` | Credentials for private repos to be able to clone data. (Only available for specific images) |
| NAME | Description | Example |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ |
| `CI` | CI environment name | `woodpecker` |
| | **Repository** | |
| `CI_REPO` | repository full name `<owner>/<name>` | `john-doe/my-repo` |
| `CI_REPO_OWNER` | repository owner | `john-doe` |
| `CI_REPO_NAME` | repository name | `my-repo` |
| `CI_REPO_REMOTE_ID` | repository remote ID, is the UID it has in the forge | `82` |
| `CI_REPO_SCM` | repository SCM | `git` |
| `CI_REPO_URL` | repository web URL | `https://git.example.com/john-doe/my-repo` |
| `CI_REPO_CLONE_URL` | repository clone URL | `https://git.example.com/john-doe/my-repo.git` |
| `CI_REPO_CLONE_SSH_URL` | repository SSH clone URL | `git@git.example.com:john-doe/my-repo.git` |
| `CI_REPO_DEFAULT_BRANCH` | repository default branch | `main` |
| `CI_REPO_PRIVATE` | repository is private | `true` |
| `CI_REPO_TRUSTED_NETWORK` | repository has trusted network access | `false` |
| `CI_REPO_TRUSTED_VOLUMES` | repository has trusted volumes access | `false` |
| `CI_REPO_TRUSTED_SECURITY` | repository has trusted security access | `false` |
| | **Current Commit** | |
| `CI_COMMIT_SHA` | commit SHA | `eba09b46064473a1d345da7abf28b477468e8dbd` |
| `CI_COMMIT_REF` | commit ref | `refs/heads/main` |
| `CI_COMMIT_REFSPEC` | commit ref spec | `issue-branch:main` |
| `CI_COMMIT_BRANCH` | commit branch (equals target branch for pull requests) | `main` |
| `CI_COMMIT_SOURCE_BRANCH` | commit source branch (empty if event is not `pull_request` or `pull_request_closed`) | `issue-branch` |
| `CI_COMMIT_TARGET_BRANCH` | commit target branch (empty if event is not `pull_request` or `pull_request_closed`) | `main` |
| `CI_COMMIT_TAG` | commit tag name (empty if event is not `tag`) | `v1.10.3` |
| `CI_COMMIT_PULL_REQUEST` | commit pull request number (empty if event is not `pull_request` or `pull_request_closed`) | `1` |
| `CI_COMMIT_PULL_REQUEST_LABELS` | labels assigned to pull request (empty if event is not `pull_request` or `pull_request_closed`) | `server` |
| `CI_COMMIT_MESSAGE` | commit message | `Initial commit` |
| `CI_COMMIT_AUTHOR` | commit author username | `john-doe` |
| `CI_COMMIT_AUTHOR_EMAIL` | commit author email address | `john-doe@example.com` |
| `CI_COMMIT_AUTHOR_AVATAR` | commit author avatar | `https://git.example.com/avatars/5dcbcadbce6f87f8abef` |
| `CI_COMMIT_PRERELEASE` | release is a pre-release (empty if event is not `release`) | `false` |
| | **Current pipeline** | |
| `CI_PIPELINE_NUMBER` | pipeline number | `8` |
| `CI_PIPELINE_PARENT` | number of parent pipeline | `0` |
| `CI_PIPELINE_EVENT` | pipeline event (see [`event`](../20-usage/20-workflow-syntax.md#event)) | `push`, `pull_request`, `pull_request_closed`, `tag`, `release`, `manual`, `cron` |
| `CI_PIPELINE_URL` | link to the web UI for the pipeline | `https://ci.example.com/repos/7/pipeline/8` |
| `CI_PIPELINE_FORGE_URL` | link to the forge's web UI for the commit(s) or tag that triggered the pipeline | `https://git.example.com/john-doe/my-repo/commit/eba09b46064473a1d345da7abf28b477468e8dbd` |
| `CI_PIPELINE_DEPLOY_TARGET` | pipeline deploy target for `deployment` events | `production` |
| `CI_PIPELINE_DEPLOY_TASK` | pipeline deploy task for `deployment` events | `migration` |
| `CI_PIPELINE_CREATED` | pipeline created UNIX timestamp | `1722617519` |
| `CI_PIPELINE_STARTED` | pipeline started UNIX timestamp | `1722617519` |
| `CI_PIPELINE_FILES` | changed files (empty if event is not `push` or `pull_request`), it is undefined if more than 500 files are touched | `[]`, `[".woodpecker.yml","README.md"]` |
| | **Current workflow** | |
| `CI_WORKFLOW_NAME` | workflow name | `release` |
| | **Current step** | |
| `CI_STEP_NAME` | step name | `build package` |
| `CI_STEP_NUMBER` | step number | `0` |
| `CI_STEP_STARTED` | step started UNIX timestamp | `1722617519` |
| `CI_STEP_URL` | URL to step in UI | `https://ci.example.com/repos/7/pipeline/8` |
| | **Previous commit** | |
| `CI_PREV_COMMIT_SHA` | previous commit SHA | `15784117e4e103f36cba75a9e29da48046eb82c4` |
| `CI_PREV_COMMIT_REF` | previous commit ref | `refs/heads/main` |
| `CI_PREV_COMMIT_REFSPEC` | previous commit ref spec | `issue-branch:main` |
| `CI_PREV_COMMIT_BRANCH` | previous commit branch | `main` |
| `CI_PREV_COMMIT_SOURCE_BRANCH` | previous commit source branch | `issue-branch` |
| `CI_PREV_COMMIT_TARGET_BRANCH` | previous commit target branch | `main` |
| `CI_PREV_COMMIT_URL` | previous commit link in forge | `https://git.example.com/john-doe/my-repo/commit/15784117e4e103f36cba75a9e29da48046eb82c4` |
| `CI_PREV_COMMIT_MESSAGE` | previous commit message | `test` |
| `CI_PREV_COMMIT_AUTHOR` | previous commit author username | `john-doe` |
| `CI_PREV_COMMIT_AUTHOR_EMAIL` | previous commit author email address | `john-doe@example.com` |
| `CI_PREV_COMMIT_AUTHOR_AVATAR` | previous commit author avatar | `https://git.example.com/avatars/12` |
| | **Previous pipeline** | |
| `CI_PREV_PIPELINE_NUMBER` | previous pipeline number | `7` |
| `CI_PREV_PIPELINE_PARENT` | previous pipeline number of parent pipeline | `0` |
| `CI_PREV_PIPELINE_EVENT` | previous pipeline event (see [`event`](../20-usage/20-workflow-syntax.md#event)) | `push`, `pull_request`, `pull_request_closed`, `tag`, `release`, `manual`, `cron` |
| `CI_PREV_PIPELINE_URL` | previous pipeline link in CI | `https://ci.example.com/repos/7/pipeline/7` |
| `CI_PREV_PIPELINE_FORGE_URL` | previous pipeline link to event in forge | `https://git.example.com/john-doe/my-repo/commit/15784117e4e103f36cba75a9e29da48046eb82c4` |
| `CI_PREV_PIPELINE_DEPLOY_TARGET` | previous pipeline deploy target for `deployment` events | `production` |
| `CI_PREV_PIPELINE_DEPLOY_TASK` | previous pipeline deploy task for `deployment` events | `migration` |
| `CI_PREV_PIPELINE_STATUS` | previous pipeline status | `success`, `failure` |
| `CI_PREV_PIPELINE_CREATED` | previous pipeline created UNIX timestamp | `1722610173` |
| `CI_PREV_PIPELINE_STARTED` | previous pipeline started UNIX timestamp | `1722610173` |
| `CI_PREV_PIPELINE_FINISHED` | previous pipeline finished UNIX timestamp | `1722610383` |
| | &emsp; | |
| `CI_WORKSPACE` | Path of the workspace where source code gets cloned to | `/woodpecker/src/git.example.com/john-doe/my-repo` |
| | **System** | |
| `CI_SYSTEM_NAME` | name of the CI system | `woodpecker` |
| `CI_SYSTEM_URL` | link to CI system | `https://ci.example.com` |
| `CI_SYSTEM_HOST` | hostname of CI server | `ci.example.com` |
| `CI_SYSTEM_VERSION` | version of the server | `2.7.0` |
| | **Forge** | |
| `CI_FORGE_TYPE` | name of forge | `bitbucket` , `bitbucket_dc` , `forgejo` , `gitea` , `github` , `gitlab` |
| `CI_FORGE_URL` | root URL of configured forge | `https://git.example.com` |
| | **Internal** - Please don't use! | |
| `CI_SCRIPT` | Internal script path. Used to call pipeline step commands. | |
| `CI_NETRC_USERNAME` | Credentials for private repos to be able to clone data. (Only available for specific images) | |
| `CI_NETRC_PASSWORD` | Credentials for private repos to be able to clone data. (Only available for specific images) | |
| `CI_NETRC_MACHINE` | Credentials for private repos to be able to clone data. (Only available for specific images) | |
## Global environment variables
@ -172,7 +170,7 @@ Example commit substitution:
```diff
steps:
- name: docker
image: plugins/docker
image: woodpeckerci/plugin-kaniko
settings:
+ tags: ${CI_COMMIT_SHA}
```
@ -182,7 +180,7 @@ Example tag substitution:
```diff
steps:
- name: docker
image: plugins/docker
image: woodpeckerci/plugin-kaniko
settings:
+ tags: ${CI_COMMIT_TAG}
```
@ -210,7 +208,7 @@ Example variable substitution with substring:
```diff
steps:
- name: docker
image: plugins/docker
image: woodpeckerci/plugin-kaniko
settings:
+ tags: ${CI_COMMIT_SHA:0:8}
```
@ -220,7 +218,7 @@ Example variable substitution strips `v` prefix from `v.1.0.0`:
```diff
steps:
- name: docker
image: plugins/docker
image: woodpeckerci/plugin-kaniko
settings:
+ tags: ${CI_COMMIT_TAG##v}
```

View file

@ -42,7 +42,7 @@ Values like this are converted to JSON and then passed to your plugin. In the ex
### Secrets
Secrets should be passed as settings too. Therefore, users should use [`from_secret`](../40-secrets.md#use-secrets-in-settings-and-environment).
Secrets should be passed as settings too. Therefore, users should use [`from_secret`](../40-secrets.md#usage).
## Plugin library

View file

@ -34,7 +34,7 @@ steps:
- go test
- name: publish
image: plugins/docker
image: woodpeckerci/plugin-kaniko
settings:
repo: foo/bar
tags: latest
@ -50,9 +50,10 @@ steps:
Plugins are just pipeline steps. They share the build workspace, mounted as a volume, and therefore have access to your source tree.
While normal steps are all about arbitrary code execution, plugins should only allow the functions intended by the plugin author.
So there are a few limitations, like the workspace base is always mounted at `/woodpecker`, but the working directory is dynamically adjusted accordingly. So as user of a plugin you should not have to care about this.
Also instead of using environment variables the plugin should only care about one prefixed with `PLUGIN_` witch are the internal representation of the **settings** ([read more](./20-creating-plugins.md)).
That's why there are a few limitations. The workspace base is always mounted at `/woodpecker`, but the working directory is dynamically
adjusted accordingly, as user of a plugin you should not have to care about this. Also, you cannot use the plugin together with `commands`
or `entrypoint` which will fail. Using `environment` is possible, but in this case, the plugin is internally not treated as plugin
anymore. The container then cannot access secrets with plugin filter anymore and the containers won't be privileged without explicit definition.
## Finding Plugins

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View file

@ -32,9 +32,9 @@ In addition you need at least some kind of database which requires additional re
## Installation
You can install Woodpecker on multiple ways. If you are not sure which one to choose, we recommend using the [docker-compose](./05-deployment-methods/10-docker-compose.md) method for the beginning:
You can install Woodpecker on multiple ways. If you are not sure which one to choose, we recommend using the [docker compose](./05-deployment-methods/10-docker-compose.md) method for the beginning:
- Using [docker-compose](./05-deployment-methods/10-docker-compose.md) with the official [container images](./05-deployment-methods/10-docker-compose.md#docker-images)
- Using [docker compose](./05-deployment-methods/10-docker-compose.md) with the official [container images](./05-deployment-methods/10-docker-compose.md#docker-images)
- Using [Kubernetes](./05-deployment-methods/20-kubernetes.md) via the Woodpecker Helm chart
- Using binaries, DEBs or RPMs you can download from [latest release](https://github.com/woodpecker-ci/woodpecker/releases/latest)
- Or using a [third-party installation method](./05-deployment-methods/30-third-party.md)
@ -55,5 +55,5 @@ Check the [server configuration](./10-server-config.md) and [agent configuration
The agent is the worker which executes the [workflows](../20-usage/15-terminology/index.md).
Woodpecker agents can execute work using a [backend](../20-usage/15-terminology/index.md) like [docker](./22-backends/10-docker.md) or [kubernetes](./22-backends/40-kubernetes.md).
By default if you choose to deploy an agent using [docker-compose](./05-deployment-methods/10-docker-compose.md) the agent simply use docker for the backend as well.
By default if you choose to deploy an agent using [docker compose](./05-deployment-methods/10-docker-compose.md) the agent simply use docker for the backend as well.
So nothing to worry about here. If you still prefer to adjust the agent to your needs, check the [agent configuration](./15-agent-config.md) page.

View file

@ -1,12 +1,10 @@
# docker-compose
# docker compose
The below [docker-compose](https://docs.docker.com/compose/) configuration can be used to start a Woodpecker server with a single agent.
The below [docker compose](https://docs.docker.com/compose/) configuration can be used to start a Woodpecker server with a single agent.
It relies on a number of environment variables that you must set before running `docker-compose up`. The variables are described below.
It relies on a number of environment variables that you must set before running `docker compose up`. The variables are described below.
```yaml title="docker-compose.yaml"
version: '3'
services:
woodpecker-server:
image: woodpeckerci/woodpecker-server:latest
@ -43,8 +41,6 @@ volumes:
Woodpecker needs to know its own address. You must therefore provide the public address of it in `<scheme>://<hostname>` format. Please omit trailing slashes:
```diff title="docker-compose.yaml"
version: '3'
services:
woodpecker-server:
[...]
@ -53,11 +49,10 @@ Woodpecker needs to know its own address. You must therefore provide the public
+ - WOODPECKER_HOST=${WOODPECKER_HOST}
```
Woodpecker can also have its port's configured. It uses a separate port for gRPC and for HTTP. The agent performs gRPC calls and connects to the gRPC port.
Woodpecker can also have its ports configured. It uses a separate port for gRPC and for HTTP. The agent performs gRPC calls and connects to the gRPC port.
They can be configured with `*_ADDR` variables:
```diff title="docker-compose.yaml"
version: '3'
services:
woodpecker-server:
[...]
@ -70,7 +65,6 @@ They can be configured with `*_ADDR` variables:
Reverse proxying can also be [configured for gRPC](../40-advanced/10-proxy.md#caddy). If the agents are connecting over the internet, it should also be SSL encrypted. The agent then needs to be configured to be secure:
```diff title="docker-compose.yaml"
version: '3'
services:
woodpecker-server:
[...]
@ -83,8 +77,6 @@ Reverse proxying can also be [configured for gRPC](../40-advanced/10-proxy.md#ca
As agents run pipeline steps as docker containers they require access to the host machine's Docker daemon:
```diff title="docker-compose.yaml"
version: '3'
services:
[...]
woodpecker-agent:
@ -96,8 +88,6 @@ As agents run pipeline steps as docker containers they require access to the hos
Agents require the server address for agent-to-server communication. The agent connects to the server's gRPC port:
```diff title="docker-compose.yaml"
version: '3'
services:
woodpecker-agent:
[...]
@ -108,8 +98,6 @@ Agents require the server address for agent-to-server communication. The agent c
The server and agents use a shared secret to authenticate communication. This should be a random string of your choosing and should be kept private. You can generate such string with `openssl rand -hex 32`:
```diff title="docker-compose.yaml"
version: '3'
services:
woodpecker-server:
[...]

View file

@ -1,12 +1,12 @@
# Third-party installation methods
# Distribution packages
:::info
These installation methods are not officially supported. If you experience issues with them, please open issues in the specific repositories.
Woodpecker itself is not responsible for creating these packages. Please reach out to the people responsible for packaging Woodpecker for the individual distributions.
:::
- [Using NixOS](./40-nixos.md) via the [NixOS module](https://search.nixos.org/options?channel=unstable&size=200&sort=relevance&query=woodpecker)
- [On Alpine Edge](https://pkgs.alpinelinux.org/packages?name=woodpecker&branch=edge&repo=&arch=&maintainer=)
- [On Arch Linux](https://archlinux.org/packages/?q=woodpecker)
- [On openSUSE](https://software.opensuse.org/package/woodpecker)
- [Using YunoHost](https://apps.yunohost.org/app/woodpecker)
- [On Cloudron](https://www.cloudron.io/store/org.woodpecker_ci.cloudronapp.html)
- [NixOS](./40-nixos.md) via the [NixOS module](https://search.nixos.org/options?channel=unstable&size=200&sort=relevance&query=woodpecker)
- [Alpine (Edge)](https://pkgs.alpinelinux.org/packages?name=woodpecker&branch=edge&repo=&arch=&maintainer=)
- [Arch Linux](https://archlinux.org/packages/?q=woodpecker)
- [openSUSE](https://software.opensuse.org/package/woodpecker)
- [YunoHost](https://apps.yunohost.org/app/woodpecker)
- [Cloudron](https://www.cloudron.io/store/org.woodpecker_ci.cloudronapp.html)

View file

@ -87,4 +87,4 @@ All configuration options can be found via [NixOS Search](https://search.nixos.o
## Tips and tricks
There are some resources on how to utilize Woodpecker more effectively with NixOS on the [Awesome Woodpecker](../../92-awesome.md) page, like using the runners nix-store in the pipeline.
There are some resources on how to utilize Woodpecker more effectively with NixOS on the [Awesome Woodpecker](/awesome) page, like using the runners nix-store in the pipeline.

View file

@ -7,8 +7,6 @@ The default database engine of Woodpecker is an embedded SQLite database which r
By default Woodpecker uses a SQLite database stored under `/var/lib/woodpecker/`. If using containers, you can mount a [data volume](https://docs.docker.com/storage/volumes/#create-and-manage-volumes) to persist the SQLite database.
```diff title="docker-compose.yaml"
version: '3'
services:
woodpecker-server:
[...]

View file

@ -63,17 +63,15 @@ Point it to your server's docker config.
WOODPECKER_DOCKER_CONFIG=/root/.docker/config.json
```
## Handling sensitive data in docker-compose and docker-swarm
## Handling sensitive data in **docker compose** and **docker swarm**
To handle sensitive data in docker-compose or docker-swarm configurations there are several options:
To handle sensitive data in `docker compose` or `docker swarm` configurations there are several options:
For docker-compose you can use a `.env` file next to your compose configuration to store the secrets outside of the compose file. While this separates configuration from secrets it is still not very secure.
For docker compose you can use a `.env` file next to your compose configuration to store the secrets outside of the compose file. While this separates configuration from secrets it is still not very secure.
Alternatively use docker-secrets. As it may be difficult to use docker secrets for environment variables Woodpecker allows to read sensible data from files by providing a `*_FILE` option of all sensible configuration variables. Woodpecker will try to read the value directly from this file. Keep in mind that when the original environment variable gets specified at the same time it will override the value read from the file.
```diff title="docker-compose.yaml"
version: '3'
services:
woodpecker-server:
[...]
@ -161,17 +159,35 @@ Configures the logging level. Possible values are `trace`, `debug`, `info`, `war
Output destination for logs.
'stdout' and 'stderr' can be used as special keywords.
### `WOODPECKER_LOG_XORM`
### `WOODPECKER_DATABASE_LOG`
> Default: `false`
Enable XORM logs.
Enable logging in database engine (currently xorm).
### `WOODPECKER_LOG_XORM_SQL`
### `WOODPECKER_DATABASE_LOG_SQL`
> Default: `false`
Enable XORM SQL command logs.
Enable logging of sql commands.
### `WOODPECKER_DATABASE_MAX_CONNECTIONS`
> Default: `100`
Max database connections xorm is allowed create.
### `WOODPECKER_DATABASE_IDLE_CONNECTIONS`
> Default: `2`
Amount of database connections xorm will hold open.
### `WOODPECKER_DATABASE_CONNECTION_TIMEOUT`
> Default: `3 Seconds`
Time an active database connection is allowed to stay open.
### `WOODPECKER_DEBUG_PRETTY`
@ -197,14 +213,6 @@ Examples:
- `WOODPECKER_HOST=http://example.org/woodpecker`
- `WOODPECKER_HOST=http://example.org:1234/woodpecker`
### `WOODPECKER_WEBHOOK_HOST`
> Default: value from `WOODPECKER_HOST` config env
Server fully qualified URL of the Webhook-facing hostname and path prefix.
Example: `WOODPECKER_WEBHOOK_HOST=http://woodpecker-server.cicd.svc.cluster.local:8000`
### `WOODPECKER_SERVER_ADDR`
> Default: `:8000`
@ -327,11 +335,13 @@ Always use authentication to clone repositories even if they are public. Needed
List of event names that will be canceled when a new pipeline for the same context (tag, branch) is created.
### `WOODPECKER_DEFAULT_CLONE_IMAGE`
### `WOODPECKER_DEFAULT_CLONE_PLUGIN`
> Default is defined in [shared/constant/constant.go](https://github.com/woodpecker-ci/woodpecker/blob/main/shared/constant/constant.go)
The default docker image to be used when cloning the repo
The default docker image to be used when cloning the repo.
It is also added to the trusted clone plugin list.
### `WOODPECKER_DEFAULT_PIPELINE_TIMEOUT`
@ -354,11 +364,20 @@ Context: when someone does log into Woodpecker, a temporary session token is cre
As long as the session is valid (until it expires or log-out),
a user can log into Woodpecker, without re-authentication.
### `WOODPECKER_ESCALATE`
### `WOODPECKER_PLUGINS_PRIVILEGED`
Docker images to run in privileged mode. Only change if you are sure what you do!
You should specify the tag of your images too, as this enforces exact matches.
### WOODPECKER_PLUGINS_TRUSTED_CLONE
> Defaults are defined in [shared/constant/constant.go](https://github.com/woodpecker-ci/woodpecker/blob/main/shared/constant/constant.go)
Docker images to run in privileged mode. Only change if you are sure what you do!
Plugins which are trusted to handle the netrc info in clone steps.
If a clone step use an image not in this list, the netrc will not be injected and an user has to use other methods (e.g. secrets) to clone non public repos.
You should specify the tag of your images too, as this enforces exact matches.
<!--
### `WOODPECKER_VOLUME`
@ -475,44 +494,6 @@ Supported variables:
---
### `WOODPECKER_LIMIT_MEM_SWAP`
> Default: `0`
The maximum amount of memory a single pipeline container is allowed to swap to disk, configured in bytes. There is no limit if `0`.
### `WOODPECKER_LIMIT_MEM`
> Default: `0`
The maximum amount of memory a single pipeline container can use, configured in bytes. There is no limit if `0`.
### `WOODPECKER_LIMIT_SHM_SIZE`
> Default: `0`
The maximum amount of memory of `/dev/shm` allowed in bytes. There is no limit if `0`.
### `WOODPECKER_LIMIT_CPU_QUOTA`
> Default: `0`
The number of microseconds per CPU period that the container is limited to before throttled. There is no limit if `0`.
### `WOODPECKER_LIMIT_CPU_SHARES`
> Default: `0`
The relative weight vs. other containers.
### `WOODPECKER_LIMIT_CPU_SET`
> Default: empty
Comma-separated list to limit the specific CPUs or cores a pipeline container can use.
Example: `WOODPECKER_LIMIT_CPU_SET=1,2`
### `WOODPECKER_CONFIG_SERVICE_ENDPOINT`
> Default: empty
@ -521,7 +502,7 @@ Specify a configuration service endpoint, see [Configuration Extension](./40-adv
### `WOODPECKER_FORGE_TIMEOUT`
> Default: 3s
> Default: 5s
Specify timeout when fetching the Woodpecker configuration from forge. See <https://pkg.go.dev/time#ParseDuration> for syntax reference.

View file

@ -22,8 +22,6 @@ Otherwise, the communication should go via the `docker0` gateway (usually 172.17
To configure the Docker network if the network's name is `gitea`, configure it like this:
```diff title="docker-compose.yaml"
version: '3'
services:
[...]
woodpecker-agent:
@ -97,11 +95,3 @@ Read the value for `WOODPECKER_GITEA_SECRET` from the specified filepath
> Default: `false`
Configure if SSL verification should be skipped.
## Advanced options
### `WOODPECKER_DEV_GITEA_OAUTH_URL`
> Default: value of `WOODPECKER_GITEA_URL`
Configures the user-facing Gitea server address. Should be used if `WOODPECKER_GITEA_URL` points to an internal URL used for API requests.

View file

@ -4,10 +4,6 @@ toc_max_heading_level: 2
# Forgejo
:::warning
Forgejo support is experimental.
:::
Woodpecker comes with built-in support for Forgejo. To enable Forgejo you should configure the Woodpecker container using the following environment variables:
```ini

View file

@ -11,8 +11,6 @@ Woodpecker comes with experimental support for Bitbucket Datacenter / Server, fo
To enable Bitbucket Server you should configure the Woodpecker container using the following environment variables:
```diff title="docker-compose.yaml"
version: '3'
services:
woodpecker-server:
[...]

View file

@ -120,11 +120,14 @@ Configures the path of the agent config file.
Configures the number of parallel workflows.
### `WOODPECKER_FILTER_LABELS`
### `WOODPECKER_AGENT_LABELS`
> Default: empty
Configures labels to filter pipeline pick up. Use a list of key-value pairs like `key=value,second-key=*`. `*` can be used as a wildcard. By default, agents provide three additional labels `platform=os/arch`, `hostname=my-agent` and `repo=*` which can be overwritten if needed. To learn how labels work, check out the [pipeline syntax page](../20-usage/20-workflow-syntax.md#labels).
Configures custom labels for the agent, to let workflows filter by it.
Use a list of key-value pairs like `key=value,second-key=*`. `*` can be used as a wildcard.
By default, agents provide three additional labels `platform=os/arch`, `hostname=my-agent` and `repo=*` which can be overwritten if needed.
To learn how labels work, check out the [pipeline syntax page](../20-usage/20-workflow-syntax.md#labels).
### `WOODPECKER_HEALTHCHECK`

View file

@ -64,3 +64,41 @@ Enable IPv6 for the networks used by pipeline containers (steps). Make sure you
List of default volumes separated by comma to be mounted to all pipeline containers (steps). For example to use custom CA
certificates installed on host and host timezone use `/etc/ssl/certs:/etc/ssl/certs:ro,/etc/timezone:/etc/timezone`.
### `WOODPECKER_BACKEND_DOCKER_LIMIT_MEM_SWAP`
> Default: `0`
The maximum amount of memory a single pipeline container is allowed to swap to disk, configured in bytes. There is no limit if `0`.
### `WOODPECKER_BACKEND_DOCKER_LIMIT_MEM`
> Default: `0`
The maximum amount of memory a single pipeline container can use, configured in bytes. There is no limit if `0`.
### `WOODPECKER_BACKEND_DOCKER_LIMIT_SHM_SIZE`
> Default: `0`
The maximum amount of memory of `/dev/shm` allowed in bytes. There is no limit if `0`.
### `WOODPECKER_BACKEND_DOCKER_LIMIT_CPU_QUOTA`
> Default: `0`
The number of microseconds per CPU period that the container is limited to before throttled. There is no limit if `0`.
### `WOODPECKER_BACKEND_DOCKER_LIMIT_CPU_SHARES`
> Default: `0`
The relative weight vs. other containers.
### `WOODPECKER_BACKEND_DOCKER_LIMIT_CPU_SET`
> Default: empty
Comma-separated list to limit the specific CPUs or cores a pipeline container can use.
Example: `WOODPECKER_BACKEND_DOCKER_LIMIT_CPU_SET=1,2`

View file

@ -8,9 +8,9 @@ The Kubernetes backend executes steps inside standalone Pods. A temporary PVC is
## Images from private registries
In order to pull private container images defined in your pipeline YAML you must provide [registry credentials in Kubernetes Secret](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/).
As the Secret is Agent-wide, it has to be placed in namespace defined by `WOODPECKER_BACKEND_K8S_NAMESPACE`.
Besides, you need to provide the Secret name to Agent via `WOODPECKER_BACKEND_K8S_PULL_SECRET_NAMES`.
In addition to [registries specified in the UI](../../20-usage/41-registries.md), you may provide [registry credentials in Kubernetes Secrets](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/) to pull private container images defined in your pipeline YAML.
Place these Secrets in namespace defined by `WOODPECKER_BACKEND_K8S_NAMESPACE` and provide the Secret names to Agents via `WOODPECKER_BACKEND_K8S_PULL_SECRET_NAMES`.
## Job specific configuration
@ -197,7 +197,7 @@ backend_options:
```
:::note
AppArmor syntax follows [KEP-24](https://github.com/kubernetes/enhancements/blob/fddcbb9cbf3df39ded03bad71228265ac6e5215f/keps/sig-node/24-apparmor/README.md).
The feature requires Kubernetes v1.30 or above.
:::
### Annotations and labels

View file

@ -137,8 +137,6 @@ To install the Woodpecker server behind a [Traefik](https://traefik.io/) load ba
<!-- cspell:words redirectscheme certresolver -->
```yaml
version: '3.8'
services:
server:
image: woodpeckerci/woodpecker-server:latest

View file

@ -81,12 +81,11 @@ WOODPECKER_CONFIG_SERVICE_ENDPOINT=https://example.com/ciconfig
"updated_at": 0,
"verified": false
},
"configs": [
{
"name": ".woodpecker.yaml",
"data": "steps:\n - name: backend\n image: alpine\n commands:\n - echo \"Hello there from Repo (.woodpecker.yaml)\"\n"
}
]
"netrc": {
"machine": "https://example.com",
"login": "user",
"password": "password"
}
}
```

View file

@ -52,8 +52,6 @@ SSL support is provided using the [ListenAndServeTLS](https://golang.org/pkg/net
Update your configuration to expose the following ports:
```diff title="docker-compose.yaml"
version: '3'
services:
woodpecker-server:
[...]
@ -66,8 +64,6 @@ Update your configuration to expose the following ports:
Update your configuration to mount your certificate and key:
```diff title="docker-compose.yaml"
version: '3'
services:
woodpecker-server:
[...]
@ -79,8 +75,6 @@ Update your configuration to mount your certificate and key:
Update your configuration to provide the paths of your certificate and key:
```diff title="docker-compose.yaml"
version: '3'
services:
woodpecker-server:
[...]

View file

@ -6,13 +6,11 @@ Please note that the autoscaler is not feature-complete yet. You can follow the
## Setup
### docker-compose
### docker compose
If you are using docker-compose you can add the following to your `docker-compose.yaml` file:
If you are using docker compose you can add the following to your `docker-compose.yaml` file:
```yaml
version: '3'
services:
woodpecker-server:
image: woodpeckerci/woodpecker-server:next

View file

@ -54,8 +54,7 @@ A common config for debugging would look like this:
WOODPECKER_OPEN=true
WOODPECKER_ADMIN=your-username
# if you want to test webhooks with an online forge like GitHub this address needs to be accessible from public server
WOODPECKER_HOST=http://your-dev-address.com
WOODPECKER_HOST=http://localhost:8000
# github (sample for a forge config - see /docs/administration/forge/overview for other forges)
WOODPECKER_GITHUB=true
@ -70,8 +69,8 @@ WOODPECKER_MAX_WORKFLOWS=1
# enable if you want to develop the UI
# WOODPECKER_DEV_WWW_PROXY=http://localhost:8010
# used so you can login without using a public address
WOODPECKER_DEV_OAUTH_HOST=http://localhost:8000
# if you want to test webhooks with an online forge like GitHub this address needs to be set and accessible from public server
WOODPECKER_EXPERT_WEBHOOK_HOST=http://your-address.com
# disable health-checks while debugging (normally not needed while developing)
WOODPECKER_HEALTHCHECK=false
@ -82,7 +81,7 @@ WOODPECKER_HEALTHCHECK=false
### Setup OAuth
Create an OAuth app for your forge as described in the [forges documentation](../30-administration/11-forges/11-overview.md). If you set `WOODPECKER_DEV_OAUTH_HOST=http://localhost:8000` you can use that address with the path as explained for the specific forge to login without the need for a public address. For example for GitHub you would use `http://localhost:8000/authorize` as authorization callback URL.
Create an OAuth app for your forge as described in the [forges documentation](../30-administration/11-forges/11-overview.md).
## Developing with VS Code

View file

@ -21,3 +21,49 @@ To automatically execute the migration after the start of the server, the new mi
## Constants of official images
All official default images, are saved in [shared/constant/constant.go](https://github.com/woodpecker-ci/woodpecker/blob/main/shared/constant/constant.go) and must be pinned by an exact tag.
## Building images locally
### Server
```sh
### build web component
make vendor
cd web/
pnpm install --frozen-lockfile
pnpm build
cd ..
### define the platforms to build for (e.g. linux/amd64)
# (the | is not a typo here)
export PLATFORMS='linux|amd64'
make cross-compile-server
### build the image
docker buildx build --platform linux/amd64 -t username/repo:tag -f docker/Dockerfile.server.multiarch --push .
```
:::info
The `cross-compile-server` rule makes use of `xgo`, a go cross-compiler. You need to be on a `amd64` host to do this, as `xgo` is only available for `amd64` (see [xgo#213](https://github.com/techknowlogick/xgo/issues/213)).
You can try to use the `build-server` rule instead, however this one fails for some OS (e.g. macOS).
:::
### Agent
```sh
### build the agent
make build-agent
### build the image
docker buildx build --platform linux/amd64 -t username/repo:tag -f docker/Dockerfile.agent.multiarch --push .
```
### CLI
```sh
### build the CLI
make build-cli
### build the image
docker buildx build --platform linux/amd64 -t username/repo:tag -f docker/Dockerfile.cli.multiarch --push .
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

View file

@ -5,7 +5,7 @@ import * as path from 'path';
const config: Config = {
title: 'Woodpecker CI',
tagline: 'Woodpecker is a simple yet powerful CI/CD engine with great extensibility.',
tagline: 'Woodpecker is a simple, yet powerful CI/CD engine with great extensibility.',
url: 'https://woodpecker-ci.org',
baseUrl: '/',
onBrokenLinks: 'throw',
@ -50,13 +50,13 @@ const config: Config = {
position: 'left',
items: [
{
to: '/docs/next/migrations', // Always point to newest migration guide
activeBaseRegex: 'docs/(next/)?migrations',
to: '/migrations', // Always point to newest migration guide
activeBaseRegex: 'migrations',
label: 'Migrations',
},
{
to: '/docs/next/awesome', // Always point to newest awesome list
activeBaseRegex: 'docs/(next/)?awesome',
to: '/awesome', // Always point to newest awesome list
activeBaseRegex: 'awesome',
label: 'Awesome',
},
{
@ -147,7 +147,7 @@ const config: Config = {
],
},
],
copyright: `Copyright © ${new Date().getFullYear()} Woodpecker CI. Built with Docusaurus.`,
copyright: `Copyright © ${new Date().getFullYear()} Woodpecker Authors. Built with Docusaurus.`,
},
prism: {
theme: themes.github,
@ -264,6 +264,7 @@ const config: Config = {
blog: {
blogTitle: 'Blog',
blogDescription: 'A blog for release announcements, turorials...',
onInlineAuthors: 'ignore',
// postsPerPage: 'ALL',
// blogSidebarCount: 0,
},

View file

@ -14,19 +14,19 @@
"write-heading-ids": "docusaurus write-heading-ids"
},
"dependencies": {
"@docusaurus/core": "^3.1.0",
"@docusaurus/plugin-content-blog": "^3.1.0",
"@docusaurus/preset-classic": "^3.1.0",
"@easyops-cn/docusaurus-search-local": "^0.44.0",
"@mdx-js/react": "^3.0.0",
"@docusaurus/core": "^3.5.2",
"@docusaurus/plugin-content-blog": "^3.5.2",
"@docusaurus/preset-classic": "^3.5.2",
"@easyops-cn/docusaurus-search-local": "^0.45.0",
"@mdx-js/react": "^3.1.0",
"@svgr/webpack": "^8.1.0",
"clsx": "^2.1.0",
"esbuild-loader": "^4.1.0",
"clsx": "^2.1.1",
"esbuild-loader": "^4.2.2",
"file-loader": "^6.2.0",
"prism-react-renderer": "^2.3.1",
"prism-react-renderer": "^2.4.0",
"react": "^18.3.1",
"react-dom": "^18.2.0",
"redocusaurus": "^2.0.2",
"react-dom": "^18.3.1",
"redocusaurus": "^2.1.2",
"url-loader": "^4.1.1"
},
"browserslist": {
@ -42,18 +42,20 @@
]
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.1.0",
"@docusaurus/tsconfig": "3.4.0",
"@docusaurus/types": "^3.1.0",
"@types/node": "^20.11.30",
"@types/react": "^18.2.67",
"@docusaurus/module-type-aliases": "^3.5.2",
"@docusaurus/tsconfig": "3.5.2",
"@docusaurus/types": "^3.5.2",
"@types/node": "^20.17.1",
"@types/react": "^18.3.12",
"@types/react-helmet": "^6.1.11",
"@types/react-router-dom": "^5.3.3",
"typescript": "^5.4.3"
"typescript": "^5.6.3"
},
"pnpm": {
"overrides": {
"got": "^14.0.0"
"got": "^14.0.0",
"path-to-regexp": "^3.3.0",
"cookie": "^1.0.0"
}
}
}

View file

@ -16,9 +16,9 @@
"@tsconfig/docusaurus": "^2.0.3",
"@types/node": "^20.12.13",
"axios": "^1.7.2",
"concurrently": "^8.2.2",
"concurrently": "^9.0.0",
"isomorphic-dompurify": "^2.11.0",
"marked": "^13.0.0",
"marked": "^14.0.0",
"tslib": "^2.6.2",
"typescript": "^5.4.5"
},

View file

@ -40,11 +40,6 @@
"docs": "https://raw.githubusercontent.com/woodpecker-ci/plugin-extend-env/main/docs.md",
"verified": true
},
{
"name": "Block Git changes",
"docs": "https://codeberg.org/qwerty287/woodpecker-block-git-changes/raw/branch/main/docs.md",
"verified": false
},
{
"name": "Regex check",
"docs": "https://codeberg.org/qwerty287/woodpecker-regex-check/raw/branch/main/docs.md",
@ -219,6 +214,11 @@
"name": "Docker Tags",
"docs": "https://raw.githubusercontent.com/dvjn/woodpecker-docker-tags-plugin/main/docs.md",
"verified": false
},
{
"name": "Telegram",
"docs": "https://raw.githubusercontent.com/appleboy/drone-telegram/refs/heads/master/DOCS.md",
"verified": false
}
]
}

File diff suppressed because it is too large Load diff

18
docs/src/pages/about.md Normal file
View file

@ -0,0 +1,18 @@
# About
Woodpecker has been originally forked from Drone 0.8 as the Drone CI license was changed after the 0.8 release from Apache 2.0 to a proprietary license. Woodpecker is based on this latest freely available version.
## History
Woodpecker was originally forked by [@laszlocph](https://github.com/laszlocph) in 2019.
A few important time points:
- [`2fbaa56`](https://github.com/woodpecker-ci/woodpecker/commit/2fbaa56eee0f4be7a3ca4be03dbd00c1bf5d1274) is the first commit of the fork, made on Apr 3, 2019.
- The first release [v0.8.91](https://github.com/woodpecker-ci/woodpecker/releases/tag/v0.8.91) was published on Apr 6, 2019.
- On Aug 27, 2019, the project was renamed to "Woodpecker" ([`630c383`](https://github.com/woodpecker-ci/woodpecker/commit/630c383181b10c4ec375e500c812c4b76b3c52b8)).
- The first release under the name "Woodpecker" was published on Sep 9, 2019 ([v0.8.104](https://github.com/woodpecker-ci/woodpecker/releases/tag/v0.8.104)).
## Differences to Drone
Woodpecker is a community-focused software that still stay free and open source forever, while Drone is managed by [Harness](https://harness.io/) and published under [Polyform Small Business](https://polyformproject.org/licenses/small-business/1.0.0/) license.

View file

@ -55,12 +55,18 @@ If you have some missing resources, please feel free to [open a pull-request](ht
- [Deploying mdbook to codeberg pages using woodpecker CI](https://www.markpitblado.me/blog/deploying-mdbook-to-codeberg-pages-using-woodpecker-ci/)
- [Deploy a Fly app with Woodpecker CI](https://joeroe.io/2024/01/09/deploy-fly-woodpecker-ci.html)
- [Ansible - using Woodpecker as an alternative to Semaphore](https://pat-s.me/ansible-using-woodpecker-as-an-alternative-to-semaphore/)
- [Simple selfhosted CI/CD with Woodpecker](https://xyquadrat.ch/blog/simple-ci-with-woodpecker/)
- [Notes to self on Woodpecker-CI](https://jpmens.net/2023/09/22/notes-to-self-on-woodpecker-ci/)
- [CI/CD with Woodpecker and Gitea](https://wilw.dev/blog/2023/04/23/woodpecker-ci/)
## Videos
- [Replace Ansible Semaphore with Woodpecker CI](https://www.youtube.com/watch?v=d610YPvCB0E)
- ["unexpected EOF" error when trying to pair Woodpecker CI served through the Caddy with Gitea](https://www.youtube.com/watch?v=n7Hyvt71Np0)
- [CICD Environment in Docker Swarm behind Caddy Server - Part 2 Woodpeckerci](https://www.youtube.com/watch?v=rkbw_k7JvS0)
- [How to Build & Publish Custom Docker Container using Gitea & Woodpecker behind Caddy Server | TUNEIT](https://www.youtube.com/watch?v=9m7DbgL1mNk)
- [Radicle Woodpecker CI Integration](https://www.youtube.com/watch?v=Ks1nbYLn4P8)
- [woodpecker-ci/woodpecker - Gource visualisation](https://www.youtube.com/watch?v=38JuakZ6m5s)
## Plugins

View file

@ -14,7 +14,7 @@ function HomepageHeader() {
<h1 className="hero__title">{siteConfig.title}</h1>
<p className="hero__subtitle">{siteConfig.tagline}</p>
<div className={styles.buttons}>
<Link className="button button--secondary button--lg" to="/docs/intro">
<Link className="button button--lg button--secondary" to="/docs/intro">
Woodpecker Tutorial - 5min
</Link>
</div>
@ -28,7 +28,7 @@ export default function Home() {
return (
<Layout
title={`${siteConfig.title}`}
description="Woodpecker is a simple yet powerful CI/CD engine with great extensibility."
description="Woodpecker is a simple, yet powerful CI/CD engine with great extensibility."
>
<HomepageHeader />
<main>

View file

@ -1,33 +1,80 @@
# Migrations
Some versions need some changes to the server configuration or the pipeline configuration files.
<!--
## 3.0.0
- Update all webhooks by pressing the "Repair all" button in the admin settings as the webhook token claims have changed
-->
Some versions need some changes to the server configuration or the pipeline configuration files. If you are an user check the `User migrations` section of an version. As an admin of a Woodpecker server or agent check the `Admin migrations` section.
## `next`
- Removed `WOODPECKER_DEV_OAUTH_HOST` and `WOODPECKER_DEV_GITEA_OAUTH_URL` use `WOODPECKER_EXPERT_FORGE_OAUTH_HOST`
:::info
This will be the next version of Woodpecker.
:::
## User migrations
- Removed built-in environment variables:
- `CI_COMMIT_URL` use `CI_PIPELINE_FORGE_URL`
- `CI_STEP_FINISHED` as empty during execution
- `CI_PIPELINE_FINISHED` as empty during execution
- `CI_PIPELINE_STATUS` was always `success`
- `CI_STEP_STATUS` was always `success`
- Set `/woodpecker` as default workdir for the **woodpecker-cli** container
- Secret filters for plugins now check against tag if specified
- Compatibility mode of deprecated `pipeline:`, `platform:` and `branches:` pipeline config options are now removed and pipeline will now fail if still in use.
- Deprecated `steps.[name].group` in favor of `steps.[name].depends_on` (see [workflow syntax](./20-usage/20-workflow-syntax.md#depends_on) to learn how to set dependencies)
- Removed `WOODPECKER_ROOT_PATH` and `WOODPECKER_ROOT_URL` config variables. Use `WOODPECKER_HOST` with a path instead
- Removed `steps.[name].group` in favor of `steps.[name].depends_on` (see [workflow syntax](/docs/usage/workflow-syntax#depends_on) to learn how to set dependencies)
- Pipelines without a config file will now be skipped instead of failing
- Deprecated `includes` and `excludes` support from **event** filter
- Deprecated uppercasing all secret env vars, instead, the value of the `secrets` property is used. [Read more](./20-usage/40-secrets.md#use-secrets-in-commands)
- Deprecated alternative names for secrets, use `environment` with `from_secret`
- Deprecated slice definition for env vars
- Deprecated `environment` filter, use `when.evaluate`
- Deprecated `WOODPECKER_WEBHOOK_HOST` in favor of `WOODPECKER_EXPERT_WEBHOOK_HOST`
- Removed `includes` and `excludes` support from **event** filter
- Removed upper-casing all secret env vars, instead, the value of the `secrets` property is used. [Read more](/docs/usage/secrets#usage)
- Removed alternative names for secrets, use `environment` with `from_secret`
- Removed `environment` filter, use `when.evaluate`
- Removed `WOODPECKER_WEBHOOK_HOST` in favor of `WOODPECKER_EXPERT_WEBHOOK_HOST`
- Renamed `start_time`, `end_time`, `created_at`, `started_at`, `finished_at` and `reviewed_at` JSON fields to `started`, `finished`, `created`, `started`, `finished`, `reviewed`
- JSON field `trusted` on repo model was changed from boolean to object
- Update all webhooks by pressing the "Repair all" button in the admin settings as the webhook token claims have changed
- Crons now use standard Linux syntax without seconds
- Removed old API routes: `registry/` -> `registries`, `/authorize/token`
- Replaced `registry` command with `repo registry` in cli
- Deprecated `secrets`, use `environment` with `from_secret`
## Admin migrations
- Deprecate `WOODPECKER_LOG_XORM` and `WOODPECKER_LOG_XORM_SQL` use `"WOODPECKER_DATABASE_LOG` and `"WOODPECKER_DATABASE_LOG_SQL`
- Deprecate `WOODPECKER_FILTER_LABELS` use `WOODPECKER_AGENT_LABELS`
- Move docker resource limit settings from server into agent configuration
- Rename server environment variable `WOODPECKER_ESCALATE` to `WOODPECKER_PLUGINS_PRIVILEGED`
- All default privileged plugins (like `woodpeckerci/plugin-docker-buildx`) were removed. Please carefully [re-add those plugins](/docs/next/administration/server-config#woodpecker_plugins_privileged) you trust and rely on.
- `WOODPECKER_DEFAULT_CLONE_IMAGE` got deprecated use `WOODPECKER_DEFAULT_CLONE_PLUGIN`
- Check trusted-clone- and privileged-plugins by image name and tag (if tag is set)
- Removed `WOODPECKER_DEV_OAUTH_HOST` and `WOODPECKER_DEV_GITEA_OAUTH_URL` use `WOODPECKER_EXPERT_FORGE_OAUTH_HOST`
- Removed `WOODPECKER_ROOT_PATH` and `WOODPECKER_ROOT_URL` config variables. Use `WOODPECKER_HOST` with a path instead
- Removed implicitly defined `regcred` image pull secret name. Set it explicitly via `WOODPECKER_BACKEND_K8S_PULL_SECRET_NAMES`
- Removed slice definition for env vars
- Migrated to rfc9421 for webhook signatures
- Replaced `configs` object by `netrc` in external configuration APIs
- Disallow upgrades from 1.x, upgrade to 2.x first
## 2.7.2
To secure your instance, set `WOODPECKER_PLUGINS_PRIVILEGED` to only allow specific versions of the `woodpeckerci/plugin-docker-buildx` plugin, use version 5.0.0 or above. This prevents older, potentially unstable versions from being privileged.
For example, to allow only version 5.0.0, use:
```bash
WOODPECKER_PLUGINS_PRIVILEGED=woodpeckerci/plugin-docker-buildx:5.0.0
```
To allow multiple versions, you can separate them with commas:
```bash
WOODPECKER_PLUGINS_PRIVILEGED=woodpeckerci/plugin-docker-buildx:5.0.0,woodpeckerci/plugin-docker-buildx:5.1.0
```
This setup ensures only specified, stable plugin versions are given privileged access.
Read more about it in [#4213](https://github.com/woodpecker-ci/woodpecker/pull/4213)
## 2.0.0
- Dropped deprecated `CI_BUILD_*`, `CI_PREV_BUILD_*`, `CI_JOB_*`, `*_LINK`, `CI_SYSTEM_ARCH`, `CI_REPO_REMOTE` built-in environment variables
- Deprecated `platform:` filter in favor of `labels:`, [read more](./20-usage/20-workflow-syntax.md#filter-by-platform)
- Deprecated `platform:` filter in favor of `labels:`, [read more](/docs/usage/workflow-syntax#filter-by-platform)
- Secrets `event` property was renamed to `events` and `image` to `images` as both are lists. The new property `events` / `images` has to be used in the api. The old properties `event` and `image` were removed.
- The secrets `plugin_only` option was removed. Secrets with images are now always only available for plugins using listed by the `images` property. Existing secrets with a list of `images` will now only be available to the listed images if they are used as a plugin.
- Removed `build` alias for `pipeline` command in CLI
@ -39,8 +86,8 @@ Some versions need some changes to the server configuration or the pipeline conf
## 1.0.0
- The signature used to verify extension calls (like those used for the [config-extension](./30-administration/40-advanced/100-external-configuration-api.md)) done by the Woodpecker server switched from using a shared-secret HMac to an ed25519 key-pair. Read more about it at the [config-extensions](./30-administration/40-advanced/100-external-configuration-api.md) documentation.
- Refactored support for old agent filter labels and expressions. Learn how to use the new [filter](./20-usage/20-workflow-syntax.md#labels)
- The signature used to verify extension calls (like those used for the [config-extension](/docs/administration/advanced/external-configuration-api)) done by the Woodpecker server switched from using a shared-secret HMac to an ed25519 key-pair. Read more about it at the [config-extensions](/docs/administration/advanced/external-configuration-api) documentation.
- Refactored support for old agent filter labels and expressions. Learn how to use the new [filter](/docs/usage/workflow-syntax#labels)
- Renamed step environment variable `CI_SYSTEM_ARCH` to `CI_SYSTEM_PLATFORM`. Same applies for the cli exec variable.
- Renamed environment variables `CI_BUILD_*` and `CI_PREV_BUILD_*` to `CI_PIPELINE_*` and `CI_PREV_PIPELINE_*`, old ones are still available but deprecated
- Renamed environment variables `CI_JOB_*` to `CI_STEP_*`, old ones are still available but deprecated
@ -49,7 +96,7 @@ Some versions need some changes to the server configuration or the pipeline conf
- Renamed API endpoints for pipelines (`<owner>/<repo>/builds/<buildId>` -> `<owner>/<repo>/pipelines/<pipelineId>`), old ones are still available but deprecated
- Updated Prometheus gauge `build_*` to `pipeline_*`
- Updated Prometheus gauge `*_job_*` to `*_step_*`
- Renamed config env `WOODPECKER_MAX_PROCS` to `WOODPECKER_MAX_WORKFLOWS` (still available as fallback)
- Renamed config env `WOODPECKER_MAX_PROCS` to `WOODPECKER_MAX_WORKFLOWS` (still available as fallback) <!-- cspell:ignore PROCS -->
- The pipelines are now also read from `.yaml` files, the new default order is `.woodpecker/*.yml` and `.woodpecker/*.yaml` (without any prioritization) -> `.woodpecker.yml` -> `.woodpecker.yaml`
- Dropped support for [Coding](https://coding.net/), [Gogs](https://gogs.io) and Bitbucket Server (Stash).
- `/api/queue/resume` & `/api/queue/pause` endpoint methods were changed from `GET` to `POST`
@ -78,7 +125,7 @@ Some versions need some changes to the server configuration or the pipeline conf
Only projects created after updating will have an empty value by default. Existing projects will stick to the current pipeline path which is `.drone.yml` in most cases.
Read more about it at the [Project Settings](./20-usage/75-project-settings.md#pipeline-path)
Read more about it at the [Project Settings](/docs/usage/project-settings#pipeline-path)
- From version `0.15.0` ongoing there will be three types of docker images: `latest`, `next` and `x.x.x` with an alpine variant for each type like `latest-alpine`.
If you used `latest` before to try pre-release features you should switch to `next` after this release.
@ -113,7 +160,7 @@ Some versions need some changes to the server configuration or the pipeline conf
- CI_SOURCE_BRANCH => use CI_COMMIT_SOURCE_BRANCH
- CI_TARGET_BRANCH => use CI_COMMIT_TARGET_BRANCH
For all available variables and their descriptions have a look at [built-in-environment-variables](./20-usage/50-environment.md#built-in-environment-variables).
For all available variables and their descriptions have a look at [built-in-environment-variables](/docs/usage/environment#built-in-environment-variables).
- Prometheus metrics have been changed from `drone_*` to `woodpecker_*`

View file

@ -19,7 +19,7 @@ the actual release will be about a week later.
### Deprecations & migrations
All deprecations and migrations for Woodpecker users and instance admins are documented in the [migration guide](/docs/next/migrations).
All deprecations and migrations for Woodpecker users and instance admins are documented in the [migration guide](/migrations).
## Next version (current state of the `main` branch)
@ -33,7 +33,11 @@ Here you can find documentation for previous versions of Woodpecker.
| | | |
| ------- | ---------- | ------------------------------------------------------------------------------------- |
| 2.6.0 | 2024-07-18 | [Documentation](https://github.com/woodpecker-ci/woodpecker/tree/v2.6.0/docs/docs/) |
| 2.7.2 | 2024-11-03 | [Documentation](https://github.com/woodpecker-ci/woodpecker/tree/v2.7.2/docs/docs/) |
| 2.7.1 | 2024-09-07 | [Documentation](https://github.com/woodpecker-ci/woodpecker/tree/v2.7.1/docs/docs/) |
| 2.7.0 | 2024-07-18 | [Documentation](https://github.com/woodpecker-ci/woodpecker/tree/v2.7.0/docs/docs/) |
| 2.6.1 | 2024-07-19 | [Documentation](https://github.com/woodpecker-ci/woodpecker/tree/v2.6.1/docs/docs/) |
| 2.6.0 | 2024-06-13 | [Documentation](https://github.com/woodpecker-ci/woodpecker/tree/v2.6.0/docs/docs/) |
| 2.5.0 | 2024-06-01 | [Documentation](https://github.com/woodpecker-ci/woodpecker/tree/v2.5.0/docs/docs/) |
| 2.4.1 | 2024-03-20 | [Documentation](https://github.com/woodpecker-ci/woodpecker/tree/v2.4.1/docs/docs/) |
| 2.4.0 | 2024-03-19 | [Documentation](https://github.com/woodpecker-ci/woodpecker/tree/v2.4.0/docs/docs/) |

View file

@ -1,6 +1,6 @@
# Welcome to Woodpecker
Woodpecker is a simple yet powerful CI/CD engine with great extensibility. It focuses on executing pipelines inside [containers](https://opencontainers.org/).
Woodpecker is a simple, yet powerful CI/CD engine with great extensibility. It focuses on executing pipelines inside [containers](https://opencontainers.org/).
If you are already using containers in your daily workflow, you'll for sure love Woodpecker.
![woodpecker](woodpecker.png)

View file

@ -1,6 +1,6 @@
# Welcome to Woodpecker
Woodpecker is a simple yet powerful CI/CD engine with great extensibility. It focuses on executing pipelines inside [containers](https://opencontainers.org/).
Woodpecker is a simple, yet powerful CI/CD engine with great extensibility. It focuses on executing pipelines inside [containers](https://opencontainers.org/).
If you are already using containers in your daily workflow, you'll for sure love Woodpecker.
![woodpecker](woodpecker.png)

BIN
docs/woodpecker.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 728 KiB

View file

@ -5,11 +5,11 @@
"systems": "systems"
},
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"lastModified": 1726560853,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
"type": "github"
},
"original": {
@ -20,11 +20,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1720542800,
"narHash": "sha256-ZgnNHuKV6h2+fQ5LuqnUaqZey1Lqqt5dTUAiAnqH0QQ=",
"lastModified": 1729665710,
"narHash": "sha256-AlcmCXJZPIlO5dmFzV3V2XF6x/OpNWUV8Y/FMPGd8Z4=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "feb2849fdeb70028c70d73b848214b00d324a497",
"rev": "2768c7d042a37de65bb1b5b3268fc987e534c49d",
"type": "github"
},
"original": {

View file

@ -34,6 +34,10 @@
go-mockery
protobuf
sqlite
go-swag # for generate-swagger
addlicense
protoc-gen-go
protoc-gen-go-grpc
];
CFLAGS = "-I${pkgs.glibc.dev}/include";
LDFLAGS = "-L${pkgs.glibc}/lib";

129
go.mod
View file

@ -2,78 +2,78 @@ module go.woodpecker-ci.org/woodpecker/v2
go 1.22.0
toolchain go1.22.5
toolchain go1.23.2
require (
al.essio.dev/pkg/shellescape v1.5.0
code.gitea.io/sdk/gitea v0.18.0
al.essio.dev/pkg/shellescape v1.5.1
code.gitea.io/sdk/gitea v0.19.0
codeberg.org/6543/go-yaml2json v1.0.0
codeberg.org/6543/xyaml v1.1.0
codeberg.org/mvdkleijn/forgejo-sdk/forgejo v1.1.1
codeberg.org/mvdkleijn/forgejo-sdk/forgejo v1.2.0
github.com/6543/logfile-open v1.2.1
github.com/adrg/xdg v0.5.0
github.com/bmatcuk/doublestar/v4 v4.6.1
github.com/caddyserver/certmagic v0.21.3
github.com/adrg/xdg v0.5.2
github.com/bmatcuk/doublestar/v4 v4.7.1
github.com/caddyserver/certmagic v0.21.4
github.com/cenkalti/backoff/v4 v4.3.0
github.com/charmbracelet/huh v0.5.1
github.com/charmbracelet/huh v0.6.0
github.com/charmbracelet/huh/spinner v0.0.0-20240327025511-ec643317aa10
github.com/distribution/reference v0.6.0
github.com/docker/cli v27.1.1+incompatible
github.com/docker/docker v27.1.1+incompatible
github.com/docker/cli v27.3.1+incompatible
github.com/docker/docker v27.3.1+incompatible
github.com/docker/go-connections v0.5.0
github.com/docker/go-units v0.5.0
github.com/drone/envsubst v1.0.3
github.com/expr-lang/expr v1.16.9
github.com/franela/goblin v0.0.0-20211003143422-0a4f594942bf
github.com/fsnotify/fsnotify v1.7.0
github.com/getkin/kin-openapi v0.126.0
github.com/gdgvda/cron v0.3.0
github.com/getkin/kin-openapi v0.127.0
github.com/gin-gonic/gin v1.10.0
github.com/gitsight/go-vcsurl v1.0.1
github.com/go-sql-driver/mysql v1.8.1
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/google/go-github/v63 v63.0.0
github.com/google/go-github/v66 v66.0.0
github.com/google/tink/go v1.7.0
github.com/gorilla/securecookie v1.1.2
github.com/hashicorp/go-hclog v1.6.3
github.com/hashicorp/go-plugin v1.6.1
github.com/jellydator/ttlcache/v3 v3.2.0
github.com/hashicorp/go-plugin v1.6.2
github.com/jellydator/ttlcache/v3 v3.3.0
github.com/joho/godotenv v1.5.1
github.com/kinbiko/jsonassert v1.1.1
github.com/kinbiko/jsonassert v1.2.0
github.com/lib/pq v1.10.9
github.com/mattn/go-sqlite3 v1.14.22
github.com/mattn/go-sqlite3 v1.14.24
github.com/mitchellh/mapstructure v1.5.0
github.com/moby/moby v27.1.1+incompatible
github.com/moby/moby v27.3.1+incompatible
github.com/moby/term v0.5.0
github.com/muesli/termenv v0.15.2
github.com/muesli/termenv v0.15.3-0.20240912151726-82936c5ea257
github.com/neticdk/go-bitbucket v1.0.0
github.com/oklog/ulid/v2 v2.1.0
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.19.1
github.com/robfig/cron v1.2.0
github.com/prometheus/client_golang v1.20.5
github.com/rs/zerolog v1.33.0
github.com/stretchr/testify v1.9.0
github.com/swaggo/files v1.0.1
github.com/swaggo/gin-swagger v1.6.0
github.com/swaggo/swag v1.16.3
github.com/urfave/cli-docs/v3 v3.0.0-alpha5.0.20240714105325-1da00919bcb4
github.com/urfave/cli/v3 v3.0.0-alpha9.0.20240711030030-937cfe918cb1
github.com/xanzy/go-gitlab v0.107.0
github.com/swaggo/swag v1.16.4
github.com/urfave/cli-docs/v3 v3.0.0-alpha5
github.com/urfave/cli/v3 v3.0.0-alpha9.0.20241004184838-20ef97b2155a
github.com/xanzy/go-gitlab v0.112.0
github.com/xeipuuv/gojsonschema v1.2.0
github.com/yaronf/httpsign v0.3.1
github.com/zalando/go-keyring v0.2.5
github.com/zalando/go-keyring v0.2.6
go.uber.org/multierr v1.11.0
golang.org/x/crypto v0.25.0
golang.org/x/net v0.27.0
golang.org/x/oauth2 v0.21.0
golang.org/x/sync v0.7.0
golang.org/x/term v0.22.0
golang.org/x/text v0.16.0
google.golang.org/grpc v1.65.0
google.golang.org/protobuf v1.34.2
golang.org/x/crypto v0.28.0
golang.org/x/net v0.30.0
golang.org/x/oauth2 v0.23.0
golang.org/x/sync v0.8.0
golang.org/x/term v0.25.0
golang.org/x/text v0.19.0
google.golang.org/grpc v1.67.1
google.golang.org/protobuf v1.35.1
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.30.3
k8s.io/apimachinery v0.30.3
k8s.io/client-go v0.30.3
k8s.io/api v0.31.2
k8s.io/apimachinery v0.31.2
k8s.io/client-go v0.31.2
src.techknowlogick.com/xormigrate v1.7.1
xorm.io/builder v0.3.13
xorm.io/xorm v1.3.9
@ -81,10 +81,10 @@ require (
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/42wim/httpsig v1.2.2 // indirect
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/alessio/shellescape v1.4.1 // indirect
github.com/atotto/clipboard v0.1.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
@ -93,20 +93,18 @@ require (
github.com/caddyserver/zerossl v0.1.3 // indirect
github.com/catppuccin/go v0.2.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/charmbracelet/bubbles v0.18.0 // indirect
github.com/charmbracelet/bubbletea v0.26.4 // indirect
github.com/charmbracelet/lipgloss v0.11.0 // indirect
github.com/charmbracelet/x/ansi v0.1.2 // indirect
github.com/charmbracelet/x/exp/strings v0.0.0-20240617190524-788ec55faed1 // indirect
github.com/charmbracelet/x/input v0.1.2 // indirect
github.com/charmbracelet/x/term v0.1.1 // indirect
github.com/charmbracelet/x/windows v0.1.2 // indirect
github.com/charmbracelet/bubbles v0.20.0 // indirect
github.com/charmbracelet/bubbletea v1.1.0 // indirect
github.com/charmbracelet/lipgloss v0.13.0 // indirect
github.com/charmbracelet/x/ansi v0.2.3 // indirect
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect
github.com/charmbracelet/x/term v0.2.0 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/danieljoos/wincred v1.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/danieljoos/wincred v1.2.2 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/davidmz/go-pageant v1.0.2 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
github.com/docker/docker-credential-helpers v0.8.0 // indirect
@ -116,6 +114,7 @@ require (
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-fed/httpsig v1.1.0 // indirect
@ -147,7 +146,8 @@ require (
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/julienschmidt/httprouter v1.3.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
@ -161,10 +161,9 @@ require (
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-localereader v0.0.1 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mholt/acmez/v2 v2.0.1 // indirect
github.com/miekg/dns v1.1.59 // indirect
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mholt/acmez/v2 v2.0.3 // indirect
github.com/miekg/dns v1.1.62 // indirect
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
@ -179,10 +178,10 @@ require (
github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/perimeterx/marshmallow v1.1.5 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.48.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/segmentio/asm v1.2.0 // indirect
@ -192,10 +191,10 @@ require (
github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
github.com/zeebo/blake3 v0.2.3 // indirect
github.com/zeebo/blake3 v0.2.4 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
go.opentelemetry.io/otel v1.28.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 // indirect
@ -204,18 +203,18 @@ require (
go.opentelemetry.io/otel/trace v1.28.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/mod v0.18.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240722135656-d784300faade // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a // indirect
golang.org/x/tools v0.22.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gotest.tools/v3 v3.4.0 // indirect
k8s.io/klog/v2 v2.120.1 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
k8s.io/utils v0.0.0-20231127182322-b307cd553661 // indirect
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect

276
go.sum
View file

@ -1,18 +1,20 @@
al.essio.dev/pkg/shellescape v1.5.0 h1:7oTvSsQ5kg9WksA9O58y9wjYnY4jP0CL82/Q8WLUGKk=
al.essio.dev/pkg/shellescape v1.5.0/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890=
code.gitea.io/sdk/gitea v0.18.0 h1:+zZrwVmujIrgobt6wVBWCqITz6bn1aBjnCUHmpZrerI=
code.gitea.io/sdk/gitea v0.18.0/go.mod h1:IG9xZJoltDNeDSW0qiF2Vqx5orMWa7OhVWrjvrd5NpI=
al.essio.dev/pkg/shellescape v1.5.1 h1:86HrALUujYS/h+GtqoB26SBEdkWfmMI6FubjXlsXyho=
al.essio.dev/pkg/shellescape v1.5.1/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890=
code.gitea.io/sdk/gitea v0.19.0 h1:8I6s1s4RHgzxiPHhOQdgim1RWIRcr0LVMbHBjBFXq4Y=
code.gitea.io/sdk/gitea v0.19.0/go.mod h1:IG9xZJoltDNeDSW0qiF2Vqx5orMWa7OhVWrjvrd5NpI=
codeberg.org/6543/go-yaml2json v1.0.0 h1:heGqo9VEi7gY2yNqjj7X4ADs5nzlFIbGsJtgYDLrnig=
codeberg.org/6543/go-yaml2json v1.0.0/go.mod h1:mz61q14LWF4ZABrgMEDMmk3t9dPi6zgR1uBh2VKV2RQ=
codeberg.org/6543/xyaml v1.1.0 h1:0PWTy8OUqshshjrrnAXFWXSPUEa8R49DIh2ah07SxFc=
codeberg.org/6543/xyaml v1.1.0/go.mod h1:jI7afXLZUxeL4rNNsG1SlHh78L+gma9lK1bIebyFZwA=
codeberg.org/mvdkleijn/forgejo-sdk/forgejo v1.1.1 h1:WEI3FZdoQjaiaR15TRmyGfY091R7o+NAaso65ckbsq0=
codeberg.org/mvdkleijn/forgejo-sdk/forgejo v1.1.1/go.mod h1:09wAYX9H0+wBo1baX9DdSqdfreZc6ji5aELsnu9m14M=
codeberg.org/mvdkleijn/forgejo-sdk/forgejo v1.2.0 h1:/z7iYYHgTuP+BnJY5qnWj6UjlA1YsAFYhi36JZY1S7Y=
codeberg.org/mvdkleijn/forgejo-sdk/forgejo v1.2.0/go.mod h1:qGzzS6EYParzgmXvnf1QANdnQmHFSyAlJN3SiRZp7e8=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
gitee.com/travelliu/dm v1.8.11192/go.mod h1:DHTzyhCrM843x9VdKVbZ+GKXGRbKM2sJ4LxihRxShkE=
github.com/42wim/httpsig v1.2.2 h1:ofAYoHUNs/MJOLqQ8hIxeyz2QxOz8qdSVvp3PX/oPgA=
github.com/42wim/httpsig v1.2.2/go.mod h1:P/UYo7ytNBFwc+dg35IubuAUIs8zj5zzFIgUCEl55WY=
github.com/6543/logfile-open v1.2.1 h1:az+TtNHclTAKaHfFCTSbuduMllANox1gM9qLQr7LV5I=
github.com/6543/logfile-open v1.2.1/go.mod h1:ZoEy7pW2mexmQxiZIqPCeh8vUxVuiHYXmSZNbvEb51g=
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw=
@ -23,13 +25,13 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg6
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/adrg/xdg v0.5.0 h1:dDaZvhMXatArP1NPHhnfaQUqWBLBsmx1h1HXQdMoFCY=
github.com/adrg/xdg v0.5.0/go.mod h1:dDdY4M4DF9Rjy4kHPeNL+ilVF+p2lK8IdM9/rTSGcI4=
github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0=
github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30=
github.com/adrg/xdg v0.5.2 h1:HNeVffMIG56GLMaoKTcTcyFhD2xS/dhyuBlKSNCM6Ug=
github.com/adrg/xdg v0.5.2/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
@ -38,16 +40,16 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I=
github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/bmatcuk/doublestar/v4 v4.7.1 h1:fdDeAqgT47acgwd9bd9HxJRDmc9UAmPpc+2m0CXv75Q=
github.com/bmatcuk/doublestar/v4 v4.7.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/caddyserver/certmagic v0.21.3 h1:pqRRry3yuB4CWBVq9+cUqu+Y6E2z8TswbhNx1AZeYm0=
github.com/caddyserver/certmagic v0.21.3/go.mod h1:Zq6pklO9nVRl3DIFUw9gVUfXKdpc/0qwTUAQMBlfgtI=
github.com/caddyserver/certmagic v0.21.4 h1:e7VobB8rffHv8ZZpSiZtEwnLDHUwLVYLWzWSa1FfKI0=
github.com/caddyserver/certmagic v0.21.4/go.mod h1:swUXjQ1T9ZtMv95qj7/InJvWLXURU85r+CfG0T+ZbDE=
github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA=
github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4=
github.com/catppuccin/go v0.2.0 h1:ktBeIrIP42b/8FGiScP9sgrWOss3lw0Z5SktRoithGA=
@ -56,28 +58,22 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/charmbracelet/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0=
github.com/charmbracelet/bubbles v0.18.0/go.mod h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw=
github.com/charmbracelet/bubbletea v0.26.4 h1:2gDkkzLZaTjMl/dQBpNVtnvcCxsh/FCkimep7FC9c40=
github.com/charmbracelet/bubbletea v0.26.4/go.mod h1:P+r+RRA5qtI1DOHNFn0otoNwB4rn+zNAzSj/EXz6xU0=
github.com/charmbracelet/huh v0.5.1 h1:t5j6g9sMjAE2a9AQuc4lNL7pf/0X4WdHiiMGkL8v/aM=
github.com/charmbracelet/huh v0.5.1/go.mod h1:gs7b2brpzXkY0PBWUqJrlzvOowTCL0vNAR6OTItc+kA=
github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE=
github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU=
github.com/charmbracelet/bubbletea v1.1.0 h1:FjAl9eAL3HBCHenhz/ZPjkKdScmaS5SK69JAK2YJK9c=
github.com/charmbracelet/bubbletea v1.1.0/go.mod h1:9Ogk0HrdbHolIKHdjfFpyXJmiCzGwy+FesYkZr7hYU4=
github.com/charmbracelet/huh v0.6.0 h1:mZM8VvZGuE0hoDXq6XLxRtgfWyTI3b2jZNKh0xWmax8=
github.com/charmbracelet/huh v0.6.0/go.mod h1:GGNKeWCeNzKpEOh/OJD8WBwTQjV3prFAtQPpLv+AVwU=
github.com/charmbracelet/huh/spinner v0.0.0-20240327025511-ec643317aa10 h1:/HZJSyFVH5rB1MlCDfkhQhRbLPD2Er29ngWXiUQ8bik=
github.com/charmbracelet/huh/spinner v0.0.0-20240327025511-ec643317aa10/go.mod h1:nrBG0YEHaxdbqHXW1xvG1hPqkuac9Eg7RTMvogiXuz0=
github.com/charmbracelet/lipgloss v0.11.0 h1:UoAcbQ6Qml8hDwSWs0Y1cB5TEQuZkDPH/ZqwWWYTG4g=
github.com/charmbracelet/lipgloss v0.11.0/go.mod h1:1UdRTH9gYgpcdNN5oBtjbu/IzNKtzVtb7sqN1t9LNn8=
github.com/charmbracelet/x/ansi v0.1.2 h1:6+LR39uG8DE6zAmbu023YlqjJHkYXDF1z36ZwzO4xZY=
github.com/charmbracelet/x/ansi v0.1.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
github.com/charmbracelet/x/exp/strings v0.0.0-20240617190524-788ec55faed1 h1:VZIQzjwFE0EamzG2v8HfemeisB8X02Tl0BZBnJ0PeU8=
github.com/charmbracelet/x/exp/strings v0.0.0-20240617190524-788ec55faed1/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ=
github.com/charmbracelet/x/exp/term v0.0.0-20240524151031-ff83003bf67a h1:k/s6UoOSVynWiw7PlclyGO2VdVs5ZLbMIHiGp4shFZE=
github.com/charmbracelet/x/exp/term v0.0.0-20240524151031-ff83003bf67a/go.mod h1:YBotIGhfoWhHDlnUpJMkjebGV2pdGRCn1Y4/Nk/vVcU=
github.com/charmbracelet/x/input v0.1.2 h1:QJAZr33eOhDowkkEQ24rsJy4Llxlm+fRDf/cQrmqJa0=
github.com/charmbracelet/x/input v0.1.2/go.mod h1:LGBim0maUY4Pitjn/4fHnuXb4KirU3DODsyuHuXdOyA=
github.com/charmbracelet/x/term v0.1.1 h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI=
github.com/charmbracelet/x/term v0.1.1/go.mod h1:wB1fHt5ECsu3mXYusyzcngVWWlu1KKUmmLhfgr/Flxw=
github.com/charmbracelet/x/windows v0.1.2 h1:Iumiwq2G+BRmgoayww/qfcvof7W/3uLoelhxojXlRWg=
github.com/charmbracelet/x/windows v0.1.2/go.mod h1:GLEO/l+lizvFDBPLIOk+49gdX49L9YWMB5t+DZd0jkQ=
github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw=
github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY=
github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY=
github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 h1:qko3AQ4gK1MTS/de7F5hPGx6/k1u0w4TeYmBFwzYVP4=
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ=
github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0=
github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0=
github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY=
github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic=
github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@ -96,11 +92,12 @@ github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE=
github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0SkRa/eYHgec=
github.com/danieljoos/wincred v1.2.2 h1:774zMFJrqaeYCK2W57BgAem/MLi6mtSE47MB6BOJ0i0=
github.com/danieljoos/wincred v1.2.2/go.mod h1:w7w4Utbrz8lqeMbDAK0lkNJUv5sAOkFi7nd/ogr0Uh8=
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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0=
github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
@ -110,10 +107,10 @@ github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDror
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/docker/cli v27.1.1+incompatible h1:goaZxOqs4QKxznZjjBWKONQci/MywhtRv2oNn0GkeZE=
github.com/docker/cli v27.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY=
github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/cli v27.3.1+incompatible h1:qEGdFBF3Xu6SCvCYhc7CzaQTlBmqDuzxPDpigSyeKQQ=
github.com/docker/cli v27.3.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI=
github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8=
github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
@ -143,10 +140,14 @@ github.com/franela/goblin v0.0.0-20211003143422-0a4f594942bf/go.mod h1:VzmDKDJVZ
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/getkin/kin-openapi v0.126.0 h1:c2cSgLnAsS0xYfKsgt5oBV6MYRM/giU8/RtwUY4wyfY=
github.com/getkin/kin-openapi v0.126.0/go.mod h1:7mONz8IwmSRg6RttPu6v8U/OJ+gr+J99qSFNjPGSQqw=
github.com/gdgvda/cron v0.3.0 h1:Wjj9NSYGzvtjkdZxOjpU749OuJGpcqr/tSxzeeBQGVI=
github.com/gdgvda/cron v0.3.0/go.mod h1:caBF+mzTZGtQqFE05T1m6u9OmCASY3EK51XAICf3wio=
github.com/getkin/kin-openapi v0.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY=
github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM=
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
@ -184,8 +185,8 @@ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
@ -221,15 +222,16 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-github/v63 v63.0.0 h1:13xwK/wk9alSokujB9lJkuzdmQuVn2QCPeck76wR3nE=
github.com/google/go-github/v63 v63.0.0/go.mod h1:IqbcrgUmIcEaioWrGYei/09o+ge5vhffGOcxrO0AfmA=
github.com/google/go-github/v66 v66.0.0 h1:ADJsaXj9UotwdgK8/iFZtv7MLc8E8WBl62WLd/D/9+M=
github.com/google/go-github/v66 v66.0.0/go.mod h1:+4SO9Zkuyf8ytMj0csN1NR/5OTR+MfqPp8P8dVlcvY4=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM=
github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
@ -246,8 +248,8 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-plugin v1.6.1 h1:P7MR2UP6gNKGPp+y7EZw2kOiq4IR9WiqLvp0XOsVdwI=
github.com/hashicorp/go-plugin v1.6.1/go.mod h1:XPHFku2tFo3o3QKFgSYo+cghcUhw1NA1hZyMK0PWAw0=
github.com/hashicorp/go-plugin v1.6.2 h1:zdGAEd0V1lCaU0u+MxWQhtSDQmahpkwOun8U8EiRVog=
github.com/hashicorp/go-plugin v1.6.2/go.mod h1:CkgLQ5CZqNmdL9U9JzM532t8ZiYQ35+pj3b1FD37R0Q=
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
@ -300,8 +302,8 @@ github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0f
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jellydator/ttlcache/v3 v3.2.0 h1:6lqVJ8X3ZaUwvzENqPAobDsXNExfUJd61u++uW8a3LE=
github.com/jellydator/ttlcache/v3 v3.2.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4=
github.com/jellydator/ttlcache/v3 v3.3.0 h1:BdoC9cE81qXfrxeb9eoJi9dWrdhSuwXMAnHTbnBm4Wc=
github.com/jellydator/ttlcache/v3 v3.3.0/go.mod h1:bj2/e0l4jRnQdrnSTaGTsh4GSXvMjQcy41i7th0GVGw=
github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
@ -315,14 +317,15 @@ github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4d
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kinbiko/jsonassert v1.1.1 h1:DB12divY+YB+cVpHULLuKePSi6+ui4M/shHSzJISkSE=
github.com/kinbiko/jsonassert v1.1.1/go.mod h1:NO4lzrogohtIdNUNzx8sdzB55M4R4Q1bsrWVdqQ7C+A=
github.com/kinbiko/jsonassert v1.2.0 h1:+/JthIVXdIrThrOtSN9ry0mNtWKXMWuvxR0nU7gQ+tI=
github.com/kinbiko/jsonassert v1.2.0/go.mod h1:pCc3uudOt+lVAbkji9O0uw8MSVt4s+1ZJ0y8Ux2F1Og=
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/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@ -334,6 +337,8 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
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/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k=
@ -377,26 +382,24 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mholt/acmez/v2 v2.0.1 h1:3/3N0u1pLjMK4sNEAFSI+bcvzbPhRpY383sy1kLHJ6k=
github.com/mholt/acmez/v2 v2.0.1/go.mod h1:fX4c9r5jYwMyMsC+7tkYRxHibkOTgta5DIFGoe67e1U=
github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs=
github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk=
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mholt/acmez/v2 v2.0.3 h1:CgDBlEwg3QBp6s45tPQmFIBrkRIkBT4rW4orMM6p4sw=
github.com/mholt/acmez/v2 v2.0.3/go.mod h1:pQ1ysaDeGrIMvJ9dfJMk5kJNkn7L2sb3UhyrX6Q91cw=
github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
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/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/moby v27.1.1+incompatible h1:WdCIKJ4WIxhrKti5c+Z7sj2SLADbsuB/reEBpQ4rtOQ=
github.com/moby/moby v27.1.1+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
github.com/moby/moby v27.3.1+incompatible h1:KQbXBjo7PavKpzIl7UkHT31y9lw/e71Uvrqhr4X+zMA=
github.com/moby/moby v27.3.1+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@ -413,8 +416,8 @@ github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
github.com/muesli/termenv v0.15.3-0.20240912151726-82936c5ea257 h1:RNw/zu+CJemcRlDFPjElZUbY2UlI/MA2B3I6PM3Isiw=
github.com/muesli/termenv v0.15.3-0.20240912151726-82936c5ea257/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/neticdk/go-bitbucket v1.0.0 h1:FPvHEgPHoDwD2VHbpyu2R2gnoWQ867RxZd2FivS4wSw=
@ -426,11 +429,11 @@ github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNs
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.31.0 h1:54UJxxj6cPInHS3a35wm6BK/F9nHYueZ1NVujHDrnXE=
github.com/onsi/gomega v1.31.0/go.mod h1:DW9aCi7U6Yi40wNVAvT6kzFnEVEI5n3DloYBiKiT6zk=
github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
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/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
@ -444,23 +447,22 @@ github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
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 v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
@ -511,20 +513,22 @@ github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M=
github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo=
github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg=
github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk=
github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A=
github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/urfave/cli-docs/v3 v3.0.0-alpha5.0.20240714105325-1da00919bcb4 h1:exFN/ZOxXslYr9t2AjrniP7wPjp/VLLAJhgazj92EBg=
github.com/urfave/cli-docs/v3 v3.0.0-alpha5.0.20240714105325-1da00919bcb4/go.mod h1:AIqom6Q60U4tiqHp41i7+/AB2XHgi1WvQ7jOFlccmZ4=
github.com/urfave/cli/v3 v3.0.0-alpha9.0.20240711030030-937cfe918cb1 h1:oxO/Jem1QPy4lxbDtX8PMiFbL79dNMA6CNAfbC06rn4=
github.com/urfave/cli/v3 v3.0.0-alpha9.0.20240711030030-937cfe918cb1/go.mod h1:Z1ItyMma7t6I7zHG9OpbExhHQOSkFf/96n+mAZ9MtVI=
github.com/xanzy/go-gitlab v0.107.0 h1:P2CT9Uy9yN9lJo3FLxpMZ4xj6uWcpnigXsjvqJ6nd2Y=
github.com/xanzy/go-gitlab v0.107.0/go.mod h1:wKNKh3GkYDMOsGmnfuX+ITCmDuSDWFO0G+C4AygL9RY=
github.com/urfave/cli-docs/v3 v3.0.0-alpha5 h1:H1oWnR2/GN0dNm2PVylws+GxSOD6YOwW/jI5l78YfPk=
github.com/urfave/cli-docs/v3 v3.0.0-alpha5/go.mod h1:AIqom6Q60U4tiqHp41i7+/AB2XHgi1WvQ7jOFlccmZ4=
github.com/urfave/cli/v3 v3.0.0-alpha9.0.20241004184838-20ef97b2155a h1:ipFw/N7kumxX+CA9UoKXX86MNfYsfsom8YOdUC+Rsfw=
github.com/urfave/cli/v3 v3.0.0-alpha9.0.20241004184838-20ef97b2155a/go.mod h1:Z1ItyMma7t6I7zHG9OpbExhHQOSkFf/96n+mAZ9MtVI=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xanzy/go-gitlab v0.112.0 h1:6Z0cqEooCvBMfBIHw+CgO4AKGRV8na/9781xOb0+DKw=
github.com/xanzy/go-gitlab v0.112.0/go.mod h1:wKNKh3GkYDMOsGmnfuX+ITCmDuSDWFO0G+C4AygL9RY=
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=
@ -532,19 +536,17 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo
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/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
github.com/yaronf/httpsign v0.3.1 h1:A4pqjwOVCwlExyy/mPTTryCHcXn+xhq4+wxq4BKhi2k=
github.com/yaronf/httpsign v0.3.1/go.mod h1:+7d6GccMcoljvE3QtU00NCmR1iTXCVNfbMe5nqaxRG4=
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.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zalando/go-keyring v0.2.5 h1:Bc2HHpjALryKD62ppdEzaFG6VxL6Bc+5v0LYpN8Lba8=
github.com/zalando/go-keyring v0.2.5/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk=
github.com/zalando/go-keyring v0.2.6 h1:r7Yc3+H+Ux0+M72zacZoItR3UDxeWfKTcabvkI8ua9s=
github.com/zalando/go-keyring v0.2.6/go.mod h1:2TCrxYrbUNYfNS/Kgy/LSrkSQzZ5UPVH85RwfczwvcI=
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=
github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ=
github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI=
github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE=
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
@ -599,18 +601,16 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@ -624,17 +624,17 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
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.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/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-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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -664,14 +664,14 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
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.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@ -679,8 +679,8 @@ golang.org/x/text v0.3.4/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.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -697,22 +697,22 @@ golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4f
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.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/api v0.0.0-20240722135656-d784300faade h1:WxZOF2yayUHpHSbUE6NMzumUzBxYc3YGwo0YHnbzsJY=
google.golang.org/genproto/googleapis/api v0.0.0-20240722135656-d784300faade/go.mod h1:mw8MG/Qz5wfgYr6VqVCiZcHe/GJEfI+oGGDCohaVgB0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a h1:hqK4+jJZXCU4pW7jsAdGOVFIfLHQeV7LaizZKnZ84HI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8=
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/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 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
@ -737,18 +737,18 @@ 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.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
k8s.io/api v0.30.3 h1:ImHwK9DCsPA9uoU3rVh4QHAHHK5dTSv1nxJUapx8hoQ=
k8s.io/api v0.30.3/go.mod h1:GPc8jlzoe5JG3pb0KJCSLX5oAFIW3/qNJITlDj8BH04=
k8s.io/apimachinery v0.30.3 h1:q1laaWCmrszyQuSQCfNB8cFgCuDAoPszKY4ucAjDwHc=
k8s.io/apimachinery v0.30.3/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
k8s.io/client-go v0.30.3 h1:bHrJu3xQZNXIi8/MoxYtZBBWQQXwy16zqJwloXXfD3k=
k8s.io/client-go v0.30.3/go.mod h1:8d4pf8vYu665/kUbsxWAQ/JDBNWqfFeZnvFiVdmx89U=
k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0=
k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk=
k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw=
k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc=
k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
k8s.io/utils v0.0.0-20231127182322-b307cd553661 h1:FepOBzJ0GXm8t0su67ln2wAZjbQ6RxQGZDnzuLcrUTI=
k8s.io/utils v0.0.0-20231127182322-b307cd553661/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=

View file

@ -10,3 +10,7 @@ section: daemon/system
contents:
- src: ./dist/agent/linux_amd64/woodpecker-agent
dst: /usr/local/bin/woodpecker-agent
- src: ./nfpm/woodpecker-agent.service
dst: /usr/local/lib/systemd/system/
- src: ./nfpm/woodpecker-agent.env.example
dst: /etc/woodpecker/

View file

@ -10,3 +10,7 @@ section: daemon/system
contents:
- src: ./dist/server/linux_amd64/woodpecker-server
dst: /usr/local/bin/woodpecker-server
- src: ./nfpm/woodpecker-server.service
dst: /usr/local/lib/systemd/system/
- src: ./nfpm/woodpecker-server.env.example
dst: /etc/woodpecker/

View file

@ -0,0 +1,7 @@
# Example for a woodpecker-agent.env file
# Check the documentation for the agent:
# https://woodpecker-ci.org/docs/administration/agent-config
# Add all required environment variables for your setup in the form of VARIABLE=value
VARIABLE=value

View file

@ -0,0 +1,19 @@
[Unit]
Description=WoodpeckerCI agent
Documentation=https://woodpecker-ci.org/docs/administration/agent-config
Requires=network.target
After=network.target
ConditionFileNotEmpty=/etc/woodpecker/woodpecker-agent.env
ConditionPathExists=/etc/woodpecker/woodpecker-agent.env
[Service]
Type=simple
EnvironmentFile=/etc/woodpecker/woodpecker-agent.env
User=woodpecker
Group=woodpecker
ExecStart=/usr/local/bin/woodpecker-agent
WorkingDirectory=/var/lib/woodpecker/
StateDirectory=woodpecker
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,7 @@
# Example for a woodpecker-server.env file
# Check the documentation for the server:
# https://woodpecker-ci.org/docs/administration/server-config
# Add all required environment variables for your setup in the form of VARIABLE=value
VARIABLE=value

Some files were not shown because too many files have changed in this diff Show more