Merge branch 'main' into fix/code-highlight-colors

This commit is contained in:
pat-s 2024-12-18 14:18:11 +01:00
commit c6d78971ff
No known key found for this signature in database
GPG key ID: 3C6318841EF78925
95 changed files with 3973 additions and 2589 deletions

View file

@ -2,7 +2,7 @@ variables:
- &golang_image 'docker.io/golang:1.23'
- &node_image 'docker.io/node:23-alpine'
- &xgo_image 'docker.io/techknowlogick/xgo:go-1.23.x'
- &buildx_plugin 'docker.io/woodpeckerci/plugin-docker-buildx:5.0.0'
- &buildx_plugin 'docker.io/woodpeckerci/plugin-docker-buildx:5.1.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.23'
- &node_image 'docker.io/node:23-alpine'
- &alpine_image 'docker.io/alpine:3.20'
- &alpine_image 'docker.io/alpine:3.21'
- path: &when_path
- 'docs/**'
- '.woodpecker/docs.yaml'

31
.woodpecker/links.yaml Normal file
View file

@ -0,0 +1,31 @@
when:
- event: cron
cron: links
steps:
- name: links
image: docker.io/lycheeverse/lychee:0.15.1
failure: ignore
depends_on: []
commands:
- lychee pipeline/frontend/yaml/linter/schema/schema.json > links.md
- lychee --exclude localhost docs/docs/ >> links.md
- lychee --exclude localhost docs/src/pages/ >> links.md
- echo -e "\nLast checked:$(date)" >> links.md
- name: Update issue
image: docker.io/alpine:3.21
depends_on: links
environment:
GITHUB_TOKEN:
from_secret: github_token
commands:
- apk add -q --no-cache jq curl
- export ISSUE_NUMBER=4514
- export DESCRIPTION=$(cat links.md)
- |
curl -X PATCH \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/${CI_REPO}/issues/$ISSUE_NUMBER \
-d "$(jq -n --arg body "$DESCRIPTION" '{body: $body}')"

View file

@ -1,15 +1,15 @@
when:
- event: push
branch:
- ${CI_REPO_DEFAULT_BRANCH}
- release/*
steps:
- name: release-helper
image: docker.io/woodpeckerci/plugin-ready-release-go:2.1.1
image: docker.io/woodpeckerci/plugin-ready-release-go:3.1.0
settings:
release_branch: ${CI_COMMIT_BRANCH}
forge_type: github
git_email: woodpecker-bot@obermui.de
github_token:
from_secret: GITHUB_TOKEN
when:
- event: push
branch:
- ${CI_REPO_DEFAULT_BRANCH}
- release/*

View file

@ -1,5 +1,5 @@
when:
- event: [pull_request, cron]
- event: [pull_request]
- event: push
branch:
- ${CI_REPO_DEFAULT_BRANCH}

View file

@ -19,15 +19,7 @@ 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.2.0
image: docker.io/woodpeckerci/plugin-prettier:1.0.0
depends_on: []
settings:
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 --user-agent "curl/8.4.0" --exclude localhost docs/docs/
- lychee --user-agent "curl/8.4.0" --exclude localhost docs/src/pages/

View file

@ -36,7 +36,7 @@ steps:
environment:
WOODPECKER_DISABLE_UPDATE_CHECK: true
WOODPECKER_LINT_STRICT: true
WOODPECKER_PLUGINS_PRIVILEGED: 'docker.io/woodpeckerci/plugin-docker-buildx:5.0.0'
WOODPECKER_PLUGINS_PRIVILEGED: 'docker.io/woodpeckerci/plugin-docker-buildx'
when:
- event: pull_request
path:
@ -125,7 +125,7 @@ steps:
- test
- sqlite
pull: true
image: docker.io/woodpeckerci/plugin-codecov:2.1.5
image: docker.io/woodpeckerci/plugin-codecov:2.1.6
settings:
files:
- agent-coverage.out

View file

@ -1,5 +1,320 @@
# Changelog
## [3.0.0](https://github.com/woodpecker-ci/woodpecker/releases/tag/v3.0.0) - 2024-12-13
### ❤️ Thanks to all contributors! ❤️
@6543, @Fishbowler, @M0Rf30, @anbraten, @cduchenoy, @fernandrone, @gnowland, @greenaar, @hg, @j04n-f, @jenrik, @johanneskastl, @jolheiser, @lafriks, @lukashass, @meln5674, @not-my-profile, @pat-s, @qwerty287, @smainz, @tori-27, @tsufeki, @xoxys, @xtexChooser, @zc-devs
### 💥 Breaking changes
- Drop native Let's Encrypt support [[#4541](https://github.com/woodpecker-ci/woodpecker/pull/4541)]
- Set new default approval mode based on repo visibility [[#4456](https://github.com/woodpecker-ci/woodpecker/pull/4456)]
- Do not set empty environment variables [[#4193](https://github.com/woodpecker-ci/woodpecker/pull/4193)]
- Unify cli commands and flags [[#4481](https://github.com/woodpecker-ci/woodpecker/pull/4481)]
- Move pipeline logs command [[#4480](https://github.com/woodpecker-ci/woodpecker/pull/4480)]
- Fix woodpecker-go repo model to match server [[#4479](https://github.com/woodpecker-ci/woodpecker/pull/4479)]
- Restructure cli commands [[#4467](https://github.com/woodpecker-ci/woodpecker/pull/4467)]
- Add pagination options to all supported endpoints in sdk [[#4463](https://github.com/woodpecker-ci/woodpecker/pull/4463)]
- Allow to set custom trusted clone plugins [[#4352](https://github.com/woodpecker-ci/woodpecker/pull/4352)]
- Add PipelineListsOptions to woodpecker-go [[#3652](https://github.com/woodpecker-ci/woodpecker/pull/3652)]
- Remove `secrets` in favor of `from_secret` [[#4363](https://github.com/woodpecker-ci/woodpecker/pull/4363)]
- Kubernetes | Docker: Add support for rootless images [[#4151](https://github.com/woodpecker-ci/woodpecker/pull/4151)]
- Split repo trusted setting [[#4025](https://github.com/woodpecker-ci/woodpecker/pull/4025)]
- Move docker resource limit settings from server to agent [[#3174](https://github.com/woodpecker-ci/woodpecker/pull/3174)]
- Set `/woodpecker` as default workdir for the **woodpecker-cli** container [[#4130](https://github.com/woodpecker-ci/woodpecker/pull/4130)]
- Require upgrade from 2.x [[#4112](https://github.com/woodpecker-ci/woodpecker/pull/4112)]
- Don't expose task data via api [[#4108](https://github.com/woodpecker-ci/woodpecker/pull/4108)]
- Remove some ci environment variables [[#3846](https://github.com/woodpecker-ci/woodpecker/pull/3846)]
- Remove all default privileged plugins [[#4053](https://github.com/woodpecker-ci/woodpecker/pull/4053)]
- Add option to filter secrets by plugins with specific tags [[#4069](https://github.com/woodpecker-ci/woodpecker/pull/4069)]
- Remove old pipeline options [[#4016](https://github.com/woodpecker-ci/woodpecker/pull/4016)]
- Remove various deprecations [[#4017](https://github.com/woodpecker-ci/woodpecker/pull/4017)]
- Drop repo name fallback for hooks [[#4013](https://github.com/woodpecker-ci/woodpecker/pull/4013)]
- Improve local backend detection [[#4006](https://github.com/woodpecker-ci/woodpecker/pull/4006)]
- Refactor JSON and SDK fields [[#3968](https://github.com/woodpecker-ci/woodpecker/pull/3968)]
- Migrate to maintained cron lib and remove seconds [[#3785](https://github.com/woodpecker-ci/woodpecker/pull/3785)]
- Switch to profile-based AppArmor configuration [[#4008](https://github.com/woodpecker-ci/woodpecker/pull/4008)]
- Remove Kubernetes default image pull secret name `regcred` [[#4005](https://github.com/woodpecker-ci/woodpecker/pull/4005)]
- Drop "WOODPECKER_WEBHOOK_HOST" env var and adjust docs [[#3969](https://github.com/woodpecker-ci/woodpecker/pull/3969)]
- Drop version in schema [[#3970](https://github.com/woodpecker-ci/woodpecker/pull/3970)]
- Update docker to v27 [[#3972](https://github.com/woodpecker-ci/woodpecker/pull/3972)]
- Require gitlab 12.4 [[#3966](https://github.com/woodpecker-ci/woodpecker/pull/3966)]
- Migrate to maintained httpsign library [[#3839](https://github.com/woodpecker-ci/woodpecker/pull/3839)]
- Remove `WOODPECKER_DEV_OAUTH_HOST` and `WOODPECKER_DEV_GITEA_OAUTH_URL` [[#3961](https://github.com/woodpecker-ci/woodpecker/pull/3961)]
- Remove deprecated pipeline keywords: `pipeline:`, `platform:`, `branches:` [[#3916](https://github.com/woodpecker-ci/woodpecker/pull/3916)]
- server: remove old unused routes [[#3845](https://github.com/woodpecker-ci/woodpecker/pull/3845)]
- CLI: remove step-id and add step-number as option to logs [[#3927](https://github.com/woodpecker-ci/woodpecker/pull/3927)]
### 🔒 Security
- Add server config to disable user registered agents [[#4206](https://github.com/woodpecker-ci/woodpecker/pull/4206)]
- chore: fix `http-proxy-middleware` CVE [[#4257](https://github.com/woodpecker-ci/woodpecker/pull/4257)]
- Allow altering trusted clone plugins and filter them via tag [[#4074](https://github.com/woodpecker-ci/woodpecker/pull/4074)]
- Update gitea sdk [[#4012](https://github.com/woodpecker-ci/woodpecker/pull/4012)]
- Update Forgejo SDK [[#3948](https://github.com/woodpecker-ci/woodpecker/pull/3948)]
### ✨ Features
- Add user as docker backend_option [[#4526](https://github.com/woodpecker-ci/woodpecker/pull/4526)]
- Implement org/user agents [[#3539](https://github.com/woodpecker-ci/woodpecker/pull/3539)]
- Replay pipeline using `cli exec` by downloading metadata [[#4103](https://github.com/woodpecker-ci/woodpecker/pull/4103)]
- Update clone plugin to support sha256 [[#4136](https://github.com/woodpecker-ci/woodpecker/pull/4136)]
### 🐛 Bug Fixes
- Fix BB ambiguous commit status key [[#4544](https://github.com/woodpecker-ci/woodpecker/pull/4544)]
- fix: addon JSON pointers [[#4508](https://github.com/woodpecker-ci/woodpecker/pull/4508)]
- Fix apparmorProfile being ignored when it's the only field [[#4507](https://github.com/woodpecker-ci/woodpecker/pull/4507)]
- Sanitize strings in table output [[#4466](https://github.com/woodpecker-ci/woodpecker/pull/4466)]
- Cleanup openapi generation [[#4331](https://github.com/woodpecker-ci/woodpecker/pull/4331)]
- Support github refresh tokens [[#3811](https://github.com/woodpecker-ci/woodpecker/pull/3811)]
- Fix not working overflow on repo list message [[#4420](https://github.com/woodpecker-ci/woodpecker/pull/4420)]
- Fix avatar column type [[#4340](https://github.com/woodpecker-ci/woodpecker/pull/4340)]
- fix `error="io: read/write on closed pipe"` on k8s backend [[#4281](https://github.com/woodpecker-ci/woodpecker/pull/4281)]
- Move update notifier dot into settings button [[#4334](https://github.com/woodpecker-ci/woodpecker/pull/4334)]
- gitea: add check if pull_request webhook is missing pull info [[#4305](https://github.com/woodpecker-ci/woodpecker/pull/4305)]
- Refresh token before loading branches [[#4284](https://github.com/woodpecker-ci/woodpecker/pull/4284)]
- Delete GitLab webhooks with partial URL match [[#4259](https://github.com/woodpecker-ci/woodpecker/pull/4259)]
- Increase `WOODPECKER_FORGE_TIMEOUT` to fix config fetching for GitLab [[#4262](https://github.com/woodpecker-ci/woodpecker/pull/4262)]
- Ensure cli exec has by default not the same prefix [[#4132](https://github.com/woodpecker-ci/woodpecker/pull/4132)]
- Fix repo add loading spinner [[#4135](https://github.com/woodpecker-ci/woodpecker/pull/4135)]
- Fix migration registries table [[#4111](https://github.com/woodpecker-ci/woodpecker/pull/4111)]
- Wait for tracer to be done before finishing workflow [[#4068](https://github.com/woodpecker-ci/woodpecker/pull/4068)]
- Fix schema with detached steps [[#4066](https://github.com/woodpecker-ci/woodpecker/pull/4066)]
- Fix schema with commands and entrypoint [[#4065](https://github.com/woodpecker-ci/woodpecker/pull/4065)]
- Read long log lines from file storage correctly [[#4048](https://github.com/woodpecker-ci/woodpecker/pull/4048)]
- Set refspec for gitlab MR [[#4021](https://github.com/woodpecker-ci/woodpecker/pull/4021)]
- Set `CI_PREV_COMMIT_{SOURCE,TARGET}_BRANCH` as mentioned in the documentation [[#4001](https://github.com/woodpecker-ci/woodpecker/pull/4001)]
- [Bitbucket Datacenter] Return empty list instead of null [[#4010](https://github.com/woodpecker-ci/woodpecker/pull/4010)]
- Fix BB PR pipeline ref [[#3985](https://github.com/woodpecker-ci/woodpecker/pull/3985)]
- 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)]
- Truncate creation in list [[#3952](https://github.com/woodpecker-ci/woodpecker/pull/3952)]
- Fix panic if forge is unreachable [[#3944](https://github.com/woodpecker-ci/woodpecker/pull/3944)]
### 📚 Documentation
- Show client flags [[#4542](https://github.com/woodpecker-ci/woodpecker/pull/4542)]
- chore(deps): update react monorepo to v19 (major) [[#4523](https://github.com/woodpecker-ci/woodpecker/pull/4523)]
- chore(deps): update docs npm deps non-major [[#4519](https://github.com/woodpecker-ci/woodpecker/pull/4519)]
- chore(deps): lock file maintenance [[#4502](https://github.com/woodpecker-ci/woodpecker/pull/4502)]
- chore(deps): lock file maintenance [[#4501](https://github.com/woodpecker-ci/woodpecker/pull/4501)]
- chore(deps): update dependency isomorphic-dompurify to v2.18.0 [[#4493](https://github.com/woodpecker-ci/woodpecker/pull/4493)]
- fix(deps): update docs npm deps non-major [[#4484](https://github.com/woodpecker-ci/woodpecker/pull/4484)]
- Add migration notes for restructured cli commands [[#4476](https://github.com/woodpecker-ci/woodpecker/pull/4476)]
- Various fixes for `awesome.md` [[#4448](https://github.com/woodpecker-ci/woodpecker/pull/4448)]
- chore(deps): lock file maintenance [[#4453](https://github.com/woodpecker-ci/woodpecker/pull/4453)]
- chore(deps): update dependency isomorphic-dompurify to v2.17.0 [[#4449](https://github.com/woodpecker-ci/woodpecker/pull/4449)]
- fix(deps): update docs npm deps non-major [[#4441](https://github.com/woodpecker-ci/woodpecker/pull/4441)]
- chore(deps): update dependency @docusaurus/tsconfig to v3.6.2 [[#4433](https://github.com/woodpecker-ci/woodpecker/pull/4433)]
- chore(deps): lock file maintenance [[#4435](https://github.com/woodpecker-ci/woodpecker/pull/4435)]
- Bump minimum nodejs to v20 [[#4417](https://github.com/woodpecker-ci/woodpecker/pull/4417)]
- chore(deps): lock file maintenance [[#4402](https://github.com/woodpecker-ci/woodpecker/pull/4402)]
- Add microsoft teams plugin [[#4400](https://github.com/woodpecker-ci/woodpecker/pull/4400)]
- fix(deps): update docs npm deps non-major [[#4394](https://github.com/woodpecker-ci/woodpecker/pull/4394)]
- chore(deps): update dependency @types/node to v22 [[#4395](https://github.com/woodpecker-ci/woodpecker/pull/4395)]
- chore(deps): update dependency marked to v15 [[#4396](https://github.com/woodpecker-ci/woodpecker/pull/4396)]
- Podman is not (official) supported [[#4367](https://github.com/woodpecker-ci/woodpecker/pull/4367)]
- Add EditorConfig-Checker Plugin to docs [[#4371](https://github.com/woodpecker-ci/woodpecker/pull/4371)]
- Update netrc option description [[#4342](https://github.com/woodpecker-ci/woodpecker/pull/4342)]
- Fix deployment event note [[#4283](https://github.com/woodpecker-ci/woodpecker/pull/4283)]
- Improve migration notes [[#4291](https://github.com/woodpecker-ci/woodpecker/pull/4291)]
- Add instructions how to build images locally [[#4277](https://github.com/woodpecker-ci/woodpecker/pull/4277)]
- chore(deps): update docs npm deps non-major [[#4238](https://github.com/woodpecker-ci/woodpecker/pull/4238)]
- Correct spelling [[#4279](https://github.com/woodpecker-ci/woodpecker/pull/4279)]
- Add Telegram plugin [[#4229](https://github.com/woodpecker-ci/woodpecker/pull/4229)]
- Remove archived plugin [[#4227](https://github.com/woodpecker-ci/woodpecker/pull/4227)]
- Use "Woodpecker Authors" as copyright on website [[#4225](https://github.com/woodpecker-ci/woodpecker/pull/4225)]
- chore(deps): update dependency cookie to v1 [[#4224](https://github.com/woodpecker-ci/woodpecker/pull/4224)]
- fix(deps): update docs npm deps non-major [[#4221](https://github.com/woodpecker-ci/woodpecker/pull/4221)]
- Fix errant apostrophe in docker-compose documentation [[#4203](https://github.com/woodpecker-ci/woodpecker/pull/4203)]
- chore(deps): lock file maintenance [[#4186](https://github.com/woodpecker-ci/woodpecker/pull/4186)]
- chore(deps): update dependency concurrently to v9 [[#4176](https://github.com/woodpecker-ci/woodpecker/pull/4176)]
- chore(deps): update docs npm deps non-major [[#4164](https://github.com/woodpecker-ci/woodpecker/pull/4164)]
- Update image filter error message [[#4143](https://github.com/woodpecker-ci/woodpecker/pull/4143)]
- Docs: reference to built-in docker compose and remove deprecated version from compose examples [[#4123](https://github.com/woodpecker-ci/woodpecker/pull/4123)]
- directory key is allowed for services [[#4127](https://github.com/woodpecker-ci/woodpecker/pull/4127)]
- [docs] Removes dot prefix from pipeline configuration filenames [[#4105](https://github.com/woodpecker-ci/woodpecker/pull/4105)]
- Use kaniko plugin in docs as example [[#4072](https://github.com/woodpecker-ci/woodpecker/pull/4072)]
- Add some posts and videos [[#4070](https://github.com/woodpecker-ci/woodpecker/pull/4070)]
- Move event type descriptions from Terminology to Workflow Syntax [[#4062](https://github.com/woodpecker-ci/woodpecker/pull/4062)]
- Add community posts from discussions [[#4058](https://github.com/woodpecker-ci/woodpecker/pull/4058)]
- Add a pull request template with some basic guidelines [[#4055](https://github.com/woodpecker-ci/woodpecker/pull/4055)]
- Add examples of CI environment variable values [[#4009](https://github.com/woodpecker-ci/woodpecker/pull/4009)]
- Fix inline author warning [[#4040](https://github.com/woodpecker-ci/woodpecker/pull/4040)]
- Updated Secrets image filter docs [[#4028](https://github.com/woodpecker-ci/woodpecker/pull/4028)]
- Update dependency marked to v14 [[#4036](https://github.com/woodpecker-ci/woodpecker/pull/4036)]
- Update docs npm deps non-major [[#4033](https://github.com/woodpecker-ci/woodpecker/pull/4033)]
- Overhaul README [[#3995](https://github.com/woodpecker-ci/woodpecker/pull/3995)]
- fix(deps): update docs npm deps non-major [[#3990](https://github.com/woodpecker-ci/woodpecker/pull/3990)]
- Add spellchecking for docs [[#3787](https://github.com/woodpecker-ci/woodpecker/pull/3787)]
### 📈 Enhancement
- Use docusaurus faster [[#4528](https://github.com/woodpecker-ci/woodpecker/pull/4528)]
- Use pagination helper to list pipelines in cli [[#4478](https://github.com/woodpecker-ci/woodpecker/pull/4478)]
- Some UI improvements [[#4497](https://github.com/woodpecker-ci/woodpecker/pull/4497)]
- Add status filter to list pipeline API [[#4494](https://github.com/woodpecker-ci/woodpecker/pull/4494)]
- Use JS-native date/time formatting [[#4488](https://github.com/woodpecker-ci/woodpecker/pull/4488)]
- Add pipeline purge command to cli [[#4470](https://github.com/woodpecker-ci/woodpecker/pull/4470)]
- Add option to limit the resultset returned by paginate helper [[#4475](https://github.com/woodpecker-ci/woodpecker/pull/4475)]
- Add filter to list repository pipelines API [[#4416](https://github.com/woodpecker-ci/woodpecker/pull/4416)]
- Increase log level when failing to fetch YAML [[#4107](https://github.com/woodpecker-ci/woodpecker/pull/4107)]
- Trim space to all config flags that allow to read value from file [[#4468](https://github.com/woodpecker-ci/woodpecker/pull/4468)]
- Change default icon size to 20 [[#4458](https://github.com/woodpecker-ci/woodpecker/pull/4458)]
- Add visibility icon to repo list [[#4460](https://github.com/woodpecker-ci/woodpecker/pull/4460)]
- Unify pipeline status icons [[#4414](https://github.com/woodpecker-ci/woodpecker/pull/4414)]
- Improve project settings descriptions [[#4410](https://github.com/woodpecker-ci/woodpecker/pull/4410)]
- Add count badge to visualize counters in tab title [[#4419](https://github.com/woodpecker-ci/woodpecker/pull/4419)]
- Redesign repo list and include last pipeline [[#4386](https://github.com/woodpecker-ci/woodpecker/pull/4386)]
- Use KeyValueEditor for DeployPipelinePopup too [[#4412](https://github.com/woodpecker-ci/woodpecker/pull/4412)]
- Use separate routes instead of anchors [[#4285](https://github.com/woodpecker-ci/woodpecker/pull/4285)]
- Untangle settings / header slots [[#4403](https://github.com/woodpecker-ci/woodpecker/pull/4403)]
- Fix responsiveness of the settings template [[#4383](https://github.com/woodpecker-ci/woodpecker/pull/4383)]
- Use squared spinner for active pipelines [[#4379](https://github.com/woodpecker-ci/woodpecker/pull/4379)]
- Add server configuration option to add default set of labels for workflows that has no labels specified [[#4326](https://github.com/woodpecker-ci/woodpecker/pull/4326)]
- Add `cli lint` option to treat warnings as errors [[#4373](https://github.com/woodpecker-ci/woodpecker/pull/4373)]
- Improve error message for wrong secrets / environment config [[#4359](https://github.com/woodpecker-ci/woodpecker/pull/4359)]
- Improve linter messages in UI [[#4351](https://github.com/woodpecker-ci/woodpecker/pull/4351)]
- Pass settings to services [[#4338](https://github.com/woodpecker-ci/woodpecker/pull/4338)]
- Inline model types for migrations [[#4293](https://github.com/woodpecker-ci/woodpecker/pull/4293)]
- Add options to control the database connections (open,idle,timeout) [[#4212](https://github.com/woodpecker-ci/woodpecker/pull/4212)]
- Move Queue creation behind new func that evaluates queue type [[#4252](https://github.com/woodpecker-ci/woodpecker/pull/4252)]
- Add additional error message on swagger v2 to v3 convert [[#4254](https://github.com/woodpecker-ci/woodpecker/pull/4254)]
- Deprecate `secrets` [[#4235](https://github.com/woodpecker-ci/woodpecker/pull/4235)]
- Agent edit/detail view: change the help url based on the backend [[#4219](https://github.com/woodpecker-ci/woodpecker/pull/4219)]
- Use middleware to load org [[#4208](https://github.com/woodpecker-ci/woodpecker/pull/4208)]
- Assign workflows to agents with the best label matches [[#4201](https://github.com/woodpecker-ci/woodpecker/pull/4201)]
- Report custom labels set by agent admins back [[#4141](https://github.com/woodpecker-ci/woodpecker/pull/4141)]
- Highlight invalid entries in manual pipeline trigger [[#4153](https://github.com/woodpecker-ci/woodpecker/pull/4153)]
- Print agent labels in debug mode [[#4155](https://github.com/woodpecker-ci/woodpecker/pull/4155)]
- Implement registries for Kubernetes backend [[#4092](https://github.com/woodpecker-ci/woodpecker/pull/4092)]
- Correct cli exec flags and remove ineffective ones [[#4129](https://github.com/woodpecker-ci/woodpecker/pull/4129)]
- Set repo user to repairing user when old user is missing [[#4128](https://github.com/woodpecker-ci/woodpecker/pull/4128)]
- Restart tasks on dead agents sooner [[#4114](https://github.com/woodpecker-ci/woodpecker/pull/4114)]
- Adjust cli exec metadata structure to equal server metadata [[#4119](https://github.com/woodpecker-ci/woodpecker/pull/4119)]
- Allow to restart declined pipelines [[#4109](https://github.com/woodpecker-ci/woodpecker/pull/4109)]
- Add indices to repo table [[#4087](https://github.com/woodpecker-ci/woodpecker/pull/4087)]
- Add systemd unit files to the RPM/DEB packages [[#3986](https://github.com/woodpecker-ci/woodpecker/pull/3986)]
- Duplicate key `workflow_id` in the agent logs [[#4046](https://github.com/woodpecker-ci/woodpecker/pull/4046)]
- Improve error on config loading [[#4024](https://github.com/woodpecker-ci/woodpecker/pull/4024)]
- Show error if secret name is missing [[#4014](https://github.com/woodpecker-ci/woodpecker/pull/4014)]
- Show error returned from API [[#3980](https://github.com/woodpecker-ci/woodpecker/pull/3980)]
- Move manual popup to own page [[#3981](https://github.com/woodpecker-ci/woodpecker/pull/3981)]
- Fail on InvalidImageName [[#4007](https://github.com/woodpecker-ci/woodpecker/pull/4007)]
- Use Bitbucket PR title for pipeline message [[#3984](https://github.com/woodpecker-ci/woodpecker/pull/3984)]
- Show logs if step has error [[#3979](https://github.com/woodpecker-ci/woodpecker/pull/3979)]
- Refactor docker backend and add more test coverage [[#2700](https://github.com/woodpecker-ci/woodpecker/pull/2700)]
- Make cli plugin log purge recognize steps by name [[#3953](https://github.com/woodpecker-ci/woodpecker/pull/3953)]
- Pin page size [[#3946](https://github.com/woodpecker-ci/woodpecker/pull/3946)]
- Improve cron list [[#3947](https://github.com/woodpecker-ci/woodpecker/pull/3947)]
- Add PULLREQUEST_DRONE_PULL_REQUEST drone env [[#3939](https://github.com/woodpecker-ci/woodpecker/pull/3939)]
- Make agent gRPC errors distinguishable [[#3936](https://github.com/woodpecker-ci/woodpecker/pull/3936)]
### 📦️ Dependency
- fix(deps): update module google.golang.org/grpc to v1.69.0 [[#4563](https://github.com/woodpecker-ci/woodpecker/pull/4563)]
- fix(deps): update golang-packages [[#4553](https://github.com/woodpecker-ci/woodpecker/pull/4553)]
- Update kin-openapi [[#4560](https://github.com/woodpecker-ci/woodpecker/pull/4560)]
- fix(deps): update module golang.org/x/crypto to v0.31.0 [security] [[#4557](https://github.com/woodpecker-ci/woodpecker/pull/4557)]
- fix(deps): update golang-packages [[#4546](https://github.com/woodpecker-ci/woodpecker/pull/4546)]
- chore(deps): update docker.io/woodpeckerci/plugin-ready-release-go docker tag to v3.1.0 [[#4536](https://github.com/woodpecker-ci/woodpecker/pull/4536)]
- chore(deps): update docker.io/curlimages/curl docker tag to v8.11.0 [[#4530](https://github.com/woodpecker-ci/woodpecker/pull/4530)]
- fix(deps): update golang-packages [[#4496](https://github.com/woodpecker-ci/woodpecker/pull/4496)]
- chore(deps): update docker.io/woodpeckerci/plugin-docker-buildx docker tag to v5.1.0 [[#4524](https://github.com/woodpecker-ci/woodpecker/pull/4524)]
- chore(deps): update docker.io/woodpeckerci/plugin-prettier docker tag to v1 [[#4522](https://github.com/woodpecker-ci/woodpecker/pull/4522)]
- chore(deps): update docker.io/alpine docker tag to v3.21 [[#4520](https://github.com/woodpecker-ci/woodpecker/pull/4520)]
- chore(deps): update dependency vite to v6 [[#4485](https://github.com/woodpecker-ci/woodpecker/pull/4485)]
- chore(deps): update docker.io/woodpeckerci/plugin-ready-release-go docker tag to v3 [[#4506](https://github.com/woodpecker-ci/woodpecker/pull/4506)]
- chore(deps): update docker.io/woodpeckerci/plugin-surge-preview docker tag to v1.3.3 [[#4495](https://github.com/woodpecker-ci/woodpecker/pull/4495)]
- fix(deps): update golang-packages [[#4477](https://github.com/woodpecker-ci/woodpecker/pull/4477)]
- fix(deps): update dependency @vueuse/core to v12 [[#4486](https://github.com/woodpecker-ci/woodpecker/pull/4486)]
- fix(deps): update module github.com/google/go-github/v66 to v67 [[#4487](https://github.com/woodpecker-ci/woodpecker/pull/4487)]
- chore(deps): update woodpeckerci/plugin-release docker tag to v0.2.2 [[#4483](https://github.com/woodpecker-ci/woodpecker/pull/4483)]
- chore(deps): update pre-commit hook golangci/golangci-lint to v1.62.2 [[#4482](https://github.com/woodpecker-ci/woodpecker/pull/4482)]
- fix(deps): update golang-packages [[#4452](https://github.com/woodpecker-ci/woodpecker/pull/4452)]
- fix(deps): update golang-packages [[#4411](https://github.com/woodpecker-ci/woodpecker/pull/4411)]
- chore(deps): update pre-commit hook igorshubovych/markdownlint-cli to v0.43.0 [[#4443](https://github.com/woodpecker-ci/woodpecker/pull/4443)]
- chore(deps): update postgres docker tag to v17.2 [[#4442](https://github.com/woodpecker-ci/woodpecker/pull/4442)]
- chore(deps): update docker.io/woodpeckerci/plugin-trivy docker tag to v1.3.0 [[#4434](https://github.com/woodpecker-ci/woodpecker/pull/4434)]
- chore(deps): update web npm deps non-major [[#4432](https://github.com/woodpecker-ci/woodpecker/pull/4432)]
- fix(deps): update golang-packages [[#4401](https://github.com/woodpecker-ci/woodpecker/pull/4401)]
- chore(deps): update web npm deps non-major [[#4391](https://github.com/woodpecker-ci/woodpecker/pull/4391)]
- fix(deps): update dependency @intlify/unplugin-vue-i18n to v6 [[#4397](https://github.com/woodpecker-ci/woodpecker/pull/4397)]
- chore(deps): update pre-commit hook golangci/golangci-lint to v1.62.0 [[#4390](https://github.com/woodpecker-ci/woodpecker/pull/4390)]
- chore(deps): update postgres docker tag to v17.1 [[#4389](https://github.com/woodpecker-ci/woodpecker/pull/4389)]
- chore(deps): update docker.io/techknowlogick/xgo docker tag to go-1.23.x [[#4388](https://github.com/woodpecker-ci/woodpecker/pull/4388)]
- chore(config): migrate renovate config [[#4296](https://github.com/woodpecker-ci/woodpecker/pull/4296)]
- chore(deps): update docker.io/woodpeckerci/plugin-trivy docker tag to v1.2.0 [[#4289](https://github.com/woodpecker-ci/woodpecker/pull/4289)]
- chore(deps): update docker.io/techknowlogick/xgo docker tag to go-1.23.x [[#4282](https://github.com/woodpecker-ci/woodpecker/pull/4282)]
- fix(deps): update golang-packages [[#4251](https://github.com/woodpecker-ci/woodpecker/pull/4251)]
- fix(deps): update web npm deps non-major [[#4258](https://github.com/woodpecker-ci/woodpecker/pull/4258)]
- chore(deps): update web npm deps non-major [[#4250](https://github.com/woodpecker-ci/woodpecker/pull/4250)]
- chore(deps): update node.js to v23 [[#4239](https://github.com/woodpecker-ci/woodpecker/pull/4239)]
- chore(deps): update web npm deps non-major [[#4237](https://github.com/woodpecker-ci/woodpecker/pull/4237)]
- chore(deps): update docker.io/mysql docker tag to v9.1.0 [[#4236](https://github.com/woodpecker-ci/woodpecker/pull/4236)]
- fix(deps): update dependency simple-icons to v13.14.0 [[#4226](https://github.com/woodpecker-ci/woodpecker/pull/4226)]
- fix(deps): update web npm deps non-major [[#4223](https://github.com/woodpecker-ci/woodpecker/pull/4223)]
- fix(deps): update golang-packages [[#4215](https://github.com/woodpecker-ci/woodpecker/pull/4215)]
- fix(deps): update golang-packages [[#4210](https://github.com/woodpecker-ci/woodpecker/pull/4210)]
- fix(deps): update module github.com/google/go-github/v65 to v66 [[#4205](https://github.com/woodpecker-ci/woodpecker/pull/4205)]
- fix(deps): update dependency vue-i18n to v10.0.4 [[#4200](https://github.com/woodpecker-ci/woodpecker/pull/4200)]
- chore(deps): update pre-commit hook pre-commit/pre-commit-hooks to v5 [[#4192](https://github.com/woodpecker-ci/woodpecker/pull/4192)]
- fix(deps): update dependency simple-icons to v13.13.0 [[#4196](https://github.com/woodpecker-ci/woodpecker/pull/4196)]
- chore(deps): update web npm deps non-major [[#4174](https://github.com/woodpecker-ci/woodpecker/pull/4174)]
- chore(deps): update docker.io/postgres docker tag to v17 [[#4179](https://github.com/woodpecker-ci/woodpecker/pull/4179)]
- fix(deps): update dependency @intlify/unplugin-vue-i18n to v5 [[#4183](https://github.com/woodpecker-ci/woodpecker/pull/4183)]
- fix(deps): update dependency @vueuse/core to v11 [[#4184](https://github.com/woodpecker-ci/woodpecker/pull/4184)]
- chore(deps): update docker.io/woodpeckerci/plugin-codecov docker tag to v2.1.5 [[#4167](https://github.com/woodpecker-ci/woodpecker/pull/4167)]
- fix(deps): update module github.com/google/go-github/v64 to v65 [[#4185](https://github.com/woodpecker-ci/woodpecker/pull/4185)]
- chore(deps): update docker.io/mysql docker tag to v9 [[#4178](https://github.com/woodpecker-ci/woodpecker/pull/4178)]
- chore(deps): update docker.io/alpine docker tag to v3.20 [[#4169](https://github.com/woodpecker-ci/woodpecker/pull/4169)]
- fix(deps): update github.com/urfave/cli/v3 digest to 20ef97b [[#4166](https://github.com/woodpecker-ci/woodpecker/pull/4166)]
- chore(deps): update docker.io/woodpeckerci/plugin-surge-preview docker tag to v1.3.2 [[#4168](https://github.com/woodpecker-ci/woodpecker/pull/4168)]
- chore(deps): update woodpeckerci/plugin-release docker tag to v0.2.1 [[#4175](https://github.com/woodpecker-ci/woodpecker/pull/4175)]
- chore(deps): update woodpeckerci/plugin-ready-release-go docker tag to v2 [[#4182](https://github.com/woodpecker-ci/woodpecker/pull/4182)]
- fix(deps): update github.com/muesli/termenv digest to 82936c5 [[#4165](https://github.com/woodpecker-ci/woodpecker/pull/4165)]
- chore(deps): update postgres docker tag to v17 [[#4181](https://github.com/woodpecker-ci/woodpecker/pull/4181)]
- chore(deps): update pre-commit non-major [[#4173](https://github.com/woodpecker-ci/woodpecker/pull/4173)]
- chore(deps): update docker.io/golang docker tag to v1.23 [[#4170](https://github.com/woodpecker-ci/woodpecker/pull/4170)]
- chore(deps): update node.js to v22 [[#4180](https://github.com/woodpecker-ci/woodpecker/pull/4180)]
- fix(deps): update golang-packages [[#4161](https://github.com/woodpecker-ci/woodpecker/pull/4161)]
- chore(deps): update dependency @antfu/eslint-config to v3 [[#4095](https://github.com/woodpecker-ci/woodpecker/pull/4095)]
- chore(deps): update dependency jsdom to v25 [[#4094](https://github.com/woodpecker-ci/woodpecker/pull/4094)]
- chore(deps): update docker.io/golang docker tag to v1.23 [[#4081](https://github.com/woodpecker-ci/woodpecker/pull/4081)]
- chore(deps): update docker.io/woodpeckerci/plugin-prettier docker tag to v0.2.0 [[#4082](https://github.com/woodpecker-ci/woodpecker/pull/4082)]
- fix(deps): update module github.com/google/go-github/v63 to v64 [[#4073](https://github.com/woodpecker-ci/woodpecker/pull/4073)]
- fix(deps): update golang-packages [[#4059](https://github.com/woodpecker-ci/woodpecker/pull/4059)]
- Update github.com/urfave/cli/v3 digest to fc07a8c [[#4043](https://github.com/woodpecker-ci/woodpecker/pull/4043)]
- Update woodpeckerci/plugin-git Docker tag to v2.5.2 [[#4041](https://github.com/woodpecker-ci/woodpecker/pull/4041)]
- Update web npm deps non-major [[#4034](https://github.com/woodpecker-ci/woodpecker/pull/4034)]
- Update dependency simple-icons to v13 [[#4037](https://github.com/woodpecker-ci/woodpecker/pull/4037)]
- chore(deps): lock file maintenance [[#3991](https://github.com/woodpecker-ci/woodpecker/pull/3991)]
- fix(deps): update golang-packages [[#3958](https://github.com/woodpecker-ci/woodpecker/pull/3958)]
### Misc
- Move link checks into cron-curated issue dashboard [[#4515](https://github.com/woodpecker-ci/woodpecker/pull/4515)]
- Add settings title action [[#4499](https://github.com/woodpecker-ci/woodpecker/pull/4499)]
- Use same default sort for repo and org repo list [[#4461](https://github.com/woodpecker-ci/woodpecker/pull/4461)]
- Add dns config option to official feature set [[#4418](https://github.com/woodpecker-ci/woodpecker/pull/4418)]
- Remove `renovate` branch triggers [[#4437](https://github.com/woodpecker-ci/woodpecker/pull/4437)]
- Improve tab layout and add hover effect [[#4431](https://github.com/woodpecker-ci/woodpecker/pull/4431)]
- Dont run pipeline on push events to renovate branches [[#4406](https://github.com/woodpecker-ci/woodpecker/pull/4406)]
- Harden and correct fifo task queue tests [[#4377](https://github.com/woodpecker-ci/woodpecker/pull/4377)]
- Kubernetes documentation enhancements [[#4374](https://github.com/woodpecker-ci/woodpecker/pull/4374)]
- Use release-helper for release/* branches [[#4301](https://github.com/woodpecker-ci/woodpecker/pull/4301)]
- Fix wording for privileged plugins linter error [[#4280](https://github.com/woodpecker-ci/woodpecker/pull/4280)]
- Fix renovate support for `xgo` [[#4276](https://github.com/woodpecker-ci/woodpecker/pull/4276)]
- Improve nix development environment [[#4256](https://github.com/woodpecker-ci/woodpecker/pull/4256)]
- [pre-commit.ci] pre-commit autoupdate [[#4209](https://github.com/woodpecker-ci/woodpecker/pull/4209)]
- Add `.lycheeignore` [[#4154](https://github.com/woodpecker-ci/woodpecker/pull/4154)]
- Add eslint-plugin-promise back [[#4022](https://github.com/woodpecker-ci/woodpecker/pull/4022)]
- Improve wording [[#3951](https://github.com/woodpecker-ci/woodpecker/pull/3951)]
- Fix typos and optimize wording [[#3940](https://github.com/woodpecker-ci/woodpecker/pull/3940)]
## [2.7.2](https://github.com/woodpecker-ci/woodpecker/releases/tag/v2.7.2) - 2024-11-03
### Important

View file

@ -48,19 +48,16 @@ var GlobalFlags = append([]cli.Flag{
Sources: cli.EnvVars("WOODPECKER_SKIP_VERIFY"),
Name: "skip-verify",
Usage: "skip ssl verification",
Hidden: true,
},
&cli.StringFlag{
Sources: cli.EnvVars("SOCKS_PROXY"),
Name: "socks-proxy",
Usage: "socks proxy address",
Hidden: true,
},
&cli.BoolFlag{
Sources: cli.EnvVars("SOCKS_PROXY_OFF"),
Name: "socks-proxy-off",
Usage: "socks proxy ignored",
Hidden: true,
},
}, logger.GlobalLoggerFlags...)

View file

@ -9,7 +9,7 @@ import (
"text/tabwriter"
"unicode"
"github.com/mitchellh/mapstructure"
"github.com/go-viper/mapstructure/v2"
)
// NewTable creates a new Table.

View file

@ -74,5 +74,5 @@ func pipelineCreate(ctx context.Context, c *cli.Command) error {
return err
}
return pipelineOutput(c, []woodpecker.Pipeline{*pipeline})
return pipelineOutput(c, []*woodpecker.Pipeline{pipeline})
}

View file

@ -58,5 +58,5 @@ func pipelineLast(ctx context.Context, c *cli.Command) error {
return err
}
return pipelineOutput(c, []woodpecker.Pipeline{*pipeline})
return pipelineOutput(c, []*woodpecker.Pipeline{pipeline})
}

View file

@ -22,6 +22,7 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
shared_utils "go.woodpecker-ci.org/woodpecker/v2/shared/utils"
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
)
@ -77,60 +78,51 @@ func List(ctx context.Context, c *cli.Command) error {
if err != nil {
return err
}
resources, err := pipelineList(c, client)
pipelines, err := pipelineList(c, client)
if err != nil {
return err
}
return pipelineOutput(c, resources)
return pipelineOutput(c, pipelines)
}
func pipelineList(c *cli.Command, client woodpecker.Client) ([]woodpecker.Pipeline, error) {
resources := make([]woodpecker.Pipeline, 0)
func pipelineList(c *cli.Command, client woodpecker.Client) ([]*woodpecker.Pipeline, error) {
repoIDOrFullName := c.Args().First()
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
if err != nil {
return resources, err
return nil, err
}
opt := woodpecker.PipelineListOptions{}
before := c.Timestamp("before")
after := c.Timestamp("after")
if !before.IsZero() {
if before := c.Timestamp("before"); !before.IsZero() {
opt.Before = before
}
if !after.IsZero() {
if after := c.Timestamp("after"); !after.IsZero() {
opt.After = after
}
pipelines, err := client.PipelineList(repoID, opt)
if err != nil {
return resources, err
}
branch := c.String("branch")
event := c.String("event")
status := c.String("status")
limit := int(c.Int("limit"))
var count int
for _, pipeline := range pipelines {
if count >= limit {
break
}
if branch != "" && pipeline.Branch != branch {
continue
}
if event != "" && pipeline.Event != event {
continue
}
if status != "" && pipeline.Status != status {
continue
}
resources = append(resources, *pipeline)
count++
pipelines, err := shared_utils.Paginate(func(page int) ([]*woodpecker.Pipeline, error) {
return client.PipelineList(repoID,
woodpecker.PipelineListOptions{
ListOptions: woodpecker.ListOptions{
Page: page,
},
Before: opt.Before,
After: opt.After,
Branch: branch,
Events: []string{event},
Status: status,
},
)
}, limit)
if err != nil {
return nil, err
}
return resources, nil
return pipelines, nil
}

View file

@ -22,7 +22,7 @@ func TestPipelineList(t *testing.T) {
pipelines []*woodpecker.Pipeline
pipelineErr error
args []string
expected []woodpecker.Pipeline
expected []*woodpecker.Pipeline
wantErr error
}{
{
@ -34,53 +34,12 @@ func TestPipelineList(t *testing.T) {
{ID: 3, Branch: "main", Event: "push", Status: "failure"},
},
args: []string{"ls", "repo/name"},
expected: []woodpecker.Pipeline{
expected: []*woodpecker.Pipeline{
{ID: 1, Branch: "main", Event: "push", Status: "success"},
{ID: 2, Branch: "develop", Event: "pull_request", Status: "running"},
{ID: 3, Branch: "main", Event: "push", Status: "failure"},
},
},
{
name: "filter by branch",
repoID: 1,
pipelines: []*woodpecker.Pipeline{
{ID: 1, Branch: "main", Event: "push", Status: "success"},
{ID: 2, Branch: "develop", Event: "pull_request", Status: "running"},
{ID: 3, Branch: "main", Event: "push", Status: "failure"},
},
args: []string{"ls", "--branch", "main", "repo/name"},
expected: []woodpecker.Pipeline{
{ID: 1, Branch: "main", Event: "push", Status: "success"},
{ID: 3, Branch: "main", Event: "push", Status: "failure"},
},
},
{
name: "filter by event",
repoID: 1,
pipelines: []*woodpecker.Pipeline{
{ID: 1, Branch: "main", Event: "push", Status: "success"},
{ID: 2, Branch: "develop", Event: "pull_request", Status: "running"},
{ID: 3, Branch: "main", Event: "push", Status: "failure"},
},
args: []string{"ls", "--event", "push", "repo/name"},
expected: []woodpecker.Pipeline{
{ID: 1, Branch: "main", Event: "push", Status: "success"},
{ID: 3, Branch: "main", Event: "push", Status: "failure"},
},
},
{
name: "filter by status",
repoID: 1,
pipelines: []*woodpecker.Pipeline{
{ID: 1, Branch: "main", Event: "push", Status: "success"},
{ID: 2, Branch: "develop", Event: "pull_request", Status: "running"},
{ID: 3, Branch: "main", Event: "push", Status: "failure"},
},
args: []string{"ls", "--status", "success", "repo/name"},
expected: []woodpecker.Pipeline{
{ID: 1, Branch: "main", Event: "push", Status: "success"},
},
},
{
name: "limit results",
repoID: 1,
@ -90,7 +49,7 @@ func TestPipelineList(t *testing.T) {
{ID: 3, Branch: "main", Event: "push", Status: "failure"},
},
args: []string{"ls", "--limit", "2", "repo/name"},
expected: []woodpecker.Pipeline{
expected: []*woodpecker.Pipeline{
{ID: 1, Branch: "main", Event: "push", Status: "success"},
{ID: 2, Branch: "develop", Event: "pull_request", Status: "running"},
},
@ -107,7 +66,15 @@ func TestPipelineList(t *testing.T) {
for _, tt := range testtases {
t.Run(tt.name, func(t *testing.T) {
mockClient := mocks.NewClient(t)
mockClient.On("PipelineList", mock.Anything, mock.Anything).Return(tt.pipelines, tt.pipelineErr)
mockClient.On("PipelineList", mock.Anything, mock.Anything).Return(func(_ int64, opt woodpecker.PipelineListOptions) ([]*woodpecker.Pipeline, error) {
if tt.pipelineErr != nil {
return nil, tt.pipelineErr
}
if opt.Page == 1 {
return tt.pipelines, nil
}
return []*woodpecker.Pipeline{}, nil
}).Maybe()
mockClient.On("RepoLookup", mock.Anything).Return(&woodpecker.Repo{ID: tt.repoID}, nil)
command := buildPipelineListCmd()

View file

@ -50,7 +50,7 @@ var Command = &cli.Command{
},
}
func pipelineOutput(c *cli.Command, resources []woodpecker.Pipeline, fd ...io.Writer) error {
func pipelineOutput(c *cli.Command, pipelines []*woodpecker.Pipeline, fd ...io.Writer) error {
outFmt, outOpt := output.ParseOutputOptions(c.String("output"))
noHeader := c.Bool("output-no-headers")
@ -74,7 +74,7 @@ func pipelineOutput(c *cli.Command, resources []woodpecker.Pipeline, fd ...io.Wr
if err != nil {
return err
}
if err := tmpl.Execute(out, resources); err != nil {
if err := tmpl.Execute(out, pipelines); err != nil {
return err
}
case "table":
@ -89,7 +89,7 @@ func pipelineOutput(c *cli.Command, resources []woodpecker.Pipeline, fd ...io.Wr
if !noHeader {
table.WriteHeader(cols)
}
for _, resource := range resources {
for _, resource := range pipelines {
if err := table.Write(cols, resource); err != nil {
return err
}

View file

@ -47,7 +47,7 @@ func TestPipelineOutput(t *testing.T) {
},
}
pipelines := []woodpecker.Pipeline{
pipelines := []*woodpecker.Pipeline{
{
Number: 1,
Status: "success",

View file

@ -1,4 +1,4 @@
// Copyright 2022 Woodpecker Authors
// 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.
@ -16,7 +16,9 @@ package pipeline
import (
"context"
"errors"
"fmt"
"net/http"
"time"
"github.com/rs/zerolog/log"
@ -96,13 +98,13 @@ func pipelinePurge(c *cli.Command, client woodpecker.Client) (err error) {
// Create a map of pipeline IDs to keep
keepMap := make(map[int64]struct{})
for _, p := range pipelinesKeep {
keepMap[p.ID] = struct{}{}
keepMap[p.Number] = struct{}{}
}
// Filter pipelines to only include those not in keepMap
var pipelinesToPurge []*woodpecker.Pipeline
for _, p := range pipelines {
if _, exists := keepMap[p.ID]; !exists {
if _, exists := keepMap[p.Number]; !exists {
pipelinesToPurge = append(pipelinesToPurge, p)
}
}
@ -114,13 +116,18 @@ func pipelinePurge(c *cli.Command, client woodpecker.Client) (err error) {
for i, p := range pipelinesToPurge {
// cspell:words spurge
log.Debug().Msgf("%spurge %v/%v pipelines from repo '%v'", msgPrefix, i+1, len(pipelinesToPurge), repoIDOrFullName)
log.Debug().Msgf("%spurge %v/%v pipelines from repo '%v' (pipeline %v)", msgPrefix, i+1, len(pipelinesToPurge), repoIDOrFullName, p.Number)
if dryRun {
continue
}
err := client.PipelineDelete(repoID, p.ID)
err := client.PipelineDelete(repoID, p.Number)
if err != nil {
var clientErr *woodpecker.ClientError
if errors.As(err, &clientErr) && clientErr.StatusCode == http.StatusUnprocessableEntity {
log.Error().Err(err).Msgf("failed to delete pipeline %d", p.Number)
continue
}
return err
}
}
@ -150,7 +157,7 @@ func fetchPipelines(client woodpecker.Client, repoID int64, duration time.Durati
ListOptions: woodpecker.ListOptions{
Page: page,
},
After: time.Now().Add(-duration),
Before: time.Now().Add(-duration),
},
)
}, -1)

View file

@ -16,20 +16,21 @@ import (
func TestPipelinePurge(t *testing.T) {
tests := []struct {
name string
repoID int64
args []string
pipelinesKeep []*woodpecker.Pipeline
pipelines []*woodpecker.Pipeline
wantDelete int
wantErr error
name string
repoID int64
args []string
pipelinesKeep []*woodpecker.Pipeline
pipelines []*woodpecker.Pipeline
mockDeleteError error
wantDelete int
wantErr error
}{
{
name: "success with no pipelines to purge",
repoID: 1,
args: []string{"purge", "--older-than", "1h", "repo/name"},
pipelinesKeep: []*woodpecker.Pipeline{
{ID: 1},
{Number: 1},
},
pipelines: []*woodpecker.Pipeline{},
},
@ -38,12 +39,12 @@ func TestPipelinePurge(t *testing.T) {
repoID: 1,
args: []string{"purge", "--older-than", "1h", "repo/name"},
pipelinesKeep: []*woodpecker.Pipeline{
{ID: 1},
{Number: 1},
},
pipelines: []*woodpecker.Pipeline{
{ID: 1},
{ID: 2},
{ID: 3},
{Number: 1},
{Number: 2},
{Number: 3},
},
wantDelete: 2,
},
@ -53,6 +54,24 @@ func TestPipelinePurge(t *testing.T) {
args: []string{"purge", "--older-than", "invalid", "repo/name"},
wantErr: errors.New("time: invalid duration \"invalid\""),
},
{
name: "continue on 422 error",
repoID: 1,
args: []string{"purge", "--older-than", "1h", "repo/name"},
pipelinesKeep: []*woodpecker.Pipeline{
{Number: 1},
},
pipelines: []*woodpecker.Pipeline{
{Number: 1},
{Number: 2},
{Number: 3},
},
wantDelete: 2,
mockDeleteError: &woodpecker.ClientError{
StatusCode: 422,
Message: "test error",
},
},
}
for _, tt := range tests {
@ -62,15 +81,15 @@ func TestPipelinePurge(t *testing.T) {
mockClient.On("PipelineList", mock.Anything, mock.Anything).Return(func(_ int64, opt woodpecker.PipelineListOptions) ([]*woodpecker.Pipeline, error) {
// Return keep pipelines for first call
if opt.After.IsZero() {
if opt.Before.IsZero() {
if opt.Page == 1 {
return tt.pipelinesKeep, nil
}
return []*woodpecker.Pipeline{}, nil
}
// Return pipelines to purge for calls with After filter
if !opt.After.IsZero() {
// Return pipelines to purge for calls with Before filter
if !opt.Before.IsZero() {
if opt.Page == 1 {
return tt.pipelines, nil
}
@ -80,7 +99,9 @@ func TestPipelinePurge(t *testing.T) {
return []*woodpecker.Pipeline{}, nil
}).Maybe()
if tt.wantDelete > 0 {
if tt.mockDeleteError != nil {
mockClient.On("PipelineDelete", tt.repoID, mock.Anything).Return(tt.mockDeleteError)
} else if tt.wantDelete > 0 {
mockClient.On("PipelineDelete", tt.repoID, mock.Anything).Return(nil).Times(tt.wantDelete)
}

View file

@ -65,5 +65,5 @@ func pipelineShow(ctx context.Context, c *cli.Command) error {
return err
}
return pipelineOutput(c, []woodpecker.Pipeline{*pipeline})
return pipelineOutput(c, []*woodpecker.Pipeline{pipeline})
}

View file

@ -36,8 +36,8 @@ var repoUpdateCmd = &cli.Command{
Usage: "repository is trusted",
},
&cli.BoolFlag{
Name: "gated",
Usage: "repository is gated",
Name: "gated", // TODO: remove in next release
Hidden: true,
},
&cli.StringFlag{
Name: "require-approval",
@ -82,7 +82,6 @@ func repoUpdate(ctx context.Context, c *cli.Command) error {
config = c.String("config")
timeout = c.Duration("timeout")
trusted = c.Bool("trusted")
gated = c.Bool("gated")
requireApproval = c.String("require-approval")
pipelineCounter = int(c.Int("pipeline-counter"))
unsafe = c.Bool("unsafe")
@ -92,29 +91,18 @@ func repoUpdate(ctx context.Context, c *cli.Command) error {
if c.IsSet("trusted") {
patch.IsTrusted = &trusted
}
// TODO: remove isGated in next major release
// TODO: remove in next release
if c.IsSet("gated") {
if gated {
patch.RequireApproval = &woodpecker.RequireApprovalAllEvents
} else {
patch.RequireApproval = &woodpecker.RequireApprovalNone
}
return fmt.Errorf("'gated' option has been set in version 2.8, use 'require-approval' in >= 3.0")
}
if c.IsSet("require-approval") {
if mode := woodpecker.ApprovalMode(requireApproval); mode.Valid() {
patch.RequireApproval = &mode
} else {
return fmt.Errorf("update approval mode failed: '%s' is no valid mode", mode)
}
// TODO: remove isGated in next major release
if requireApproval == string(woodpecker.RequireApprovalAllEvents) {
trueBool := true
patch.IsGated = &trueBool
} else if requireApproval == string(woodpecker.RequireApprovalNone) {
falseBool := false
patch.IsGated = &falseBool
}
}
if c.IsSet("timeout") {
v := int64(timeout / time.Minute)

View file

@ -93,16 +93,6 @@ var flags = append([]cli.Flag{
Name: "custom-js-file",
Usage: "file path for the server to serve a custom .JS file, used for customizing the UI",
},
&cli.StringFlag{
Sources: cli.EnvVars("WOODPECKER_LETS_ENCRYPT_EMAIL"),
Name: "lets-encrypt-email",
Usage: "let's encrypt email",
},
&cli.BoolFlag{
Sources: cli.EnvVars("WOODPECKER_LETS_ENCRYPT"),
Name: "lets-encrypt",
Usage: "enable let's encrypt",
},
&cli.StringFlag{
Sources: cli.EnvVars("WOODPECKER_GRPC_ADDR"),
Name: "grpc-addr",

View file

@ -39,7 +39,7 @@ func pinger(_ context.Context, c *cli.Command) error {
}
// if woodpecker do ssl on it's own
if c.String("server-cert") != "" || c.Bool("lets-encrypt") {
if c.String("server-cert") != "" {
scheme = "https"
}

View file

@ -25,7 +25,6 @@ import (
"strings"
"time"
"github.com/caddyserver/certmagic"
"github.com/gin-gonic/gin"
prometheus_http "github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/rs/zerolog"
@ -167,8 +166,7 @@ func run(ctx context.Context, c *cli.Command) error {
middleware.Store(_store),
)
switch {
case c.String("server-cert") != "":
if c.String("server-cert") != "" {
// start the server with tls enabled
serviceWaitingGroup.Go(func() error {
tlsServer := &http.Server{
@ -234,32 +232,7 @@ func run(ctx context.Context, c *cli.Command) error {
}
return nil
})
case c.Bool("lets-encrypt"):
// start the server with lets-encrypt
certmagic.DefaultACME.Email = c.String("lets-encrypt-email")
certmagic.DefaultACME.Agreed = true
address, err := url.Parse(strings.TrimSuffix(c.String("server-host"), "/"))
if err != nil {
return err
}
serviceWaitingGroup.Go(func() error {
go func() {
<-ctx.Done()
log.Error().Msg("there is no certmagic.HTTPS alternative who is context aware we will fail in 2 seconds")
time.Sleep(time.Second * 2)
log.Fatal().Msg("we kill certmagic by fail") //nolint:forbidigo
}()
log.Info().Msg("starting certmagic server ...")
if err := certmagic.HTTPS([]string{address.Host}, handler); err != nil {
log.Error().Err(err).Msg("certmagic does not work")
stopServerFunc(fmt.Errorf("certmagic failed: %w", err))
}
return nil
})
default:
} else {
// start the server without tls
serviceWaitingGroup.Go(func() error {
httpServer := &http.Server{

View file

@ -7,7 +7,7 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/go/pkg \
make build-agent
FROM docker.io/alpine:3.20
FROM docker.io/alpine:3.21
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

View file

@ -7,7 +7,7 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/go/pkg \
make build-cli
FROM docker.io/alpine:3.20
FROM docker.io/alpine:3.21
WORKDIR /woodpecker
RUN apk add -U --no-cache ca-certificates

View file

@ -1,5 +1,5 @@
# docker build --rm -f docker/Dockerfile.make -t woodpecker/make:local .
FROM docker.io/golang:1.23-alpine as golang_image
# docker build --rm -f docker/Dockerfile.make -t woodpecker/make:local .
FROM docker.io/golang:1.23-alpine AS golang_image
FROM docker.io/node:23-alpine
RUN apk add --no-cache --update make gcc binutils-gold musl-dev protoc && \
@ -10,6 +10,7 @@ COPY --from=golang_image /usr/local/go /usr/local/go
COPY Makefile /
ENV PATH=$PATH:/usr/local/go/bin
ENV COREPACK_ENABLE_DOWNLOAD_PROMPT=0
ENV COREPACK_ENABLE_AUTO_PIN=0
# Cache tools
RUN GOBIN=/usr/local/go/bin make install-tools && \

View file

@ -1,4 +1,4 @@
FROM docker.io/alpine:3.20
FROM docker.io/alpine:3.21
ARG TARGETOS TARGETARCH
RUN apk add -U --no-cache ca-certificates

View file

@ -1,3 +0,0 @@
module.exports = {
presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
};

View file

@ -11,17 +11,27 @@ Woodpecker provides three different levels to add secrets to your pipeline. The
## Usage
You can set a setting or an environment value from secrets using the `from_secret` syntax.
You can set a setting or 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`.
The example below passes a secret called `secret_token` as an environment variable that will be called `TOKEN_ENV`:
```diff
steps:
- name: docker
image: my-plugin
env-secret-example:
image: alpine
commands:
+ - echo "The secret is $TOKEN_ENV"
+ environment:
+ TOKEN_ENV:
+ from_secret: secret_token
```
You can use the same syntax to pass secrets to settings. For example, you can pass a secret named `secret_token` to the settings called `token`, which will then be available in the plugin as environment variable named `PLUGIN_TOKEN` (See [plugins](./51-plugins/20-creating-plugins.md#settings) for details).
```diff
steps:
- name: settings-secret-example
image: my-plugin
+ settings:
+ token:
+ from_secret: secret_token

View file

@ -70,11 +70,11 @@ This is the reference list of all environment variables available to your pipeli
| `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_SOURCE_BRANCH` | commit source branch (set only for `pull_request` and `pull_request_closed` events) | `issue-branch` |
| `CI_COMMIT_TARGET_BRANCH` | commit target branch (set only for `pull_request` and `pull_request_closed` events) | `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_PULL_REQUEST` | commit pull request number (set only for `pull_request` and `pull_request_closed` events) | `1` |
| `CI_COMMIT_PULL_REQUEST_LABELS` | labels assigned to pull request (set only for `pull_request` and `pull_request_closed` events) | `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` |
@ -103,8 +103,8 @@ This is the reference list of all environment variables available to your pipeli
| `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_SOURCE_BRANCH` | previous commit source branch (set only for `pull_request` and `pull_request_closed` events) | `issue-branch` |
| `CI_PREV_COMMIT_TARGET_BRANCH` | previous commit target branch (set only for `pull_request` and `pull_request_closed` events) | `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` |

View file

@ -275,12 +275,6 @@ The file must be UTF-8 encoded, to ensure all special characters are preserved.
Example: `WOODPECKER_CUSTOM_JS_FILE=/usr/local/www/woodpecker.js`
### `WOODPECKER_LETS_ENCRYPT`
> Default: `false`
Automatically generates an SSL certificate using Let's Encrypt, and configures the server to accept HTTPS requests.
### `WOODPECKER_GRPC_ADDR`
> Default: `:9000`

View file

@ -38,7 +38,7 @@ Addons use RPC to communicate to the server and are implemented using the [`go-p
This example will use the Go language.
Directly import Woodpecker's Go packages (`go.woodpecker-ci.org/woodpecker/woodpecker/v2`) and use the interfaces and types defined there.
Directly import Woodpecker's Go packages (`go.woodpecker-ci.org/woodpecker/v2`) and use the interfaces and types defined there.
In the `main` function, just call `"go.woodpecker-ci.org/woodpecker/v2/server/forge/addon".Serve` with a `"go.woodpecker-ci.org/woodpecker/v2/server/forge".Forge` as argument.
This will take care of connecting the addon forge to the server.

View file

@ -18,6 +18,25 @@ FROM woodpeckerci/woodpecker-server:latest-alpine
RUN apk add -U --no-cache docker-credential-ecr-login
```
## Step specific configuration
### Run user
By default the docker backend starts the step container without the `--user` flag. This means the step container will use the default user of the container. To change this behavior you can set the `user` backend option to the preferred user/group:
```yaml
steps:
- name: example
image: alpine
commands:
- whoami
backend_options:
docker:
user: 65534:65534
```
The syntax is the same as the [docker run](https://docs.docker.com/engine/reference/run/#user) `--user` flag.
## Image cleanup
The agent **will not** automatically remove images from the host. This task should be managed by the host system. For example, you can use a cron job to periodically do clean-up tasks for the CI runner.

View file

@ -12,7 +12,7 @@ In addition to [registries specified in the UI](../../20-usage/41-registries.md)
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
## Step specific configuration
### Resources
@ -67,7 +67,7 @@ To give steps access to the Kubernetes API via service account, take a look at [
### Node selector
`nodeSelector` specifies the labels which are used to select the node on which the job will be executed.
`nodeSelector` specifies the labels which are used to select the node on which the step will be executed.
Labels defined here will be appended to a list which already contains `"kubernetes.io/arch"`.
By default `"kubernetes.io/arch"` is inferred from the agents' platform. One can override it by setting that label in the `nodeSelector` section of the `backend_options`.

View file

@ -1,35 +1,5 @@
# SSL
Woodpecker supports two ways of enabling SSL communication. You can either use Let's Encrypt to get automated SSL support with
renewal or provide your own SSL certificates.
## Let's Encrypt
Woodpecker supports automated SSL configuration and updates using Let's Encrypt.
You can enable Let's Encrypt by making the following modifications to your server configuration:
```ini
WOODPECKER_LETS_ENCRYPT=true
WOODPECKER_LETS_ENCRYPT_EMAIL=ssl-admin@example.tld
```
Note that Woodpecker uses the hostname from the `WOODPECKER_HOST` environment variable when requesting certificates. For example, if `WOODPECKER_HOST=https://example.com` is set the certificate is requested for `example.com`. To receive emails before certificates expire Let's Encrypt requires an email address. You can set it with `WOODPECKER_LETS_ENCRYPT_EMAIL=ssl-admin@example.tld`.
The SSL certificates are stored in `$HOME/.local/share/certmagic` for binary versions of Woodpecker and in `/var/lib/woodpecker` for the Container versions of it. You can set a custom path by setting `XDG_DATA_HOME` if required.
> Once enabled you can visit the Woodpecker UI with http and the HTTPS address. HTTP will be redirected to HTTPS.
### Certificate Cache
Woodpecker writes the certificates to `/var/lib/woodpecker/certmagic/`.
### Certificate Updates
Woodpecker uses the official Go acme library which will handle certificate upgrades. There should be no addition configuration or management required.
## SSL with own certificates
Woodpecker supports SSL configuration by mounting certificates into your container.
```ini
@ -37,17 +7,17 @@ WOODPECKER_SERVER_CERT=/etc/certs/woodpecker.example.com/server.crt
WOODPECKER_SERVER_KEY=/etc/certs/woodpecker.example.com/server.key
```
### Certificate Chain
## Certificate Chain
The most common problem encountered is providing a certificate file without the intermediate chain.
> LoadX509KeyPair reads and parses a public/private key pair from a pair of files. The files must contain PEM encoded data. The certificate file may contain intermediate certificates following the leaf certificate to form a certificate chain.
### Certificate Errors
## Certificate Errors
SSL support is provided using the [ListenAndServeTLS](https://golang.org/pkg/net/http/#ListenAndServeTLS) function from the Go standard library. If you receive certificate errors or warnings please examine your configuration more closely.
### Running in containers
## Running in containers
Update your configuration to expose the following ports:

View file

@ -1,10 +1,10 @@
# 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.
Woodpecker is a community-driven open source CI/CD tool. It is lightweight, fast and simple to use. It can be used with many different Git providers and runners.
## History
Woodpecker was originally forked by [@laszlocph](https://github.com/laszlocph) in 2019.
Woodpecker was originally forked from Drone 0.8 by [@laszlocph](https://github.com/laszlocph) in 2019 after its license model was changed.
A few important time points:
@ -15,4 +15,5 @@ A few important time points:
## 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.
Woodpecker is a community-driven open source software published under the Apache License 2.0 and will always remain so. Drone CI is managed by [Harness](https://harness.io/) and is available in two editions: [Open Source under Apache License 2.0 and Enterprise under Polyform Small Business license](https://docs.drone.io/enterprise/#is-drone-open-source).
In terms of Drone's feature set, Woodpecker is somewhere between [Drone Enterprise and OSS](https://docs.drone.io/enterprise/#what-is-the-difference-between-open-source-and-enterprise), but also has some unique features.

View file

@ -3,7 +3,7 @@ import type { Config } from '@docusaurus/types';
import type * as Preset from '@docusaurus/preset-classic';
import * as path from 'path';
const config: Config = {
const config = {
title: 'Woodpecker CI',
tagline: 'Woodpecker is a simple, yet powerful CI/CD engine with great extensibility.',
url: 'https://woodpecker-ci.org',
@ -248,7 +248,7 @@ const config: Config = {
label: '2.8.x',
},
'2.7': {
label: '2.7.x',
label: '2.7.x 💀',
banner: 'unmaintained',
},
'2.6': {
@ -265,8 +265,6 @@ const config: Config = {
blogTitle: 'Blog',
blogDescription: 'A blog for release announcements, turorials...',
onInlineAuthors: 'ignore',
// postsPerPage: 'ALL',
// blogSidebarCount: 0,
},
theme: {
customCss: require.resolve('./src/css/custom.css'),
@ -291,19 +289,12 @@ const config: Config = {
},
],
],
webpack: {
jsLoader: (isServer) => ({
loader: require.resolve('esbuild-loader'),
options: {
loader: 'tsx',
target: isServer ? 'node12' : 'es2017',
supported: { 'dynamic-import': false },
},
}),
},
markdown: {
format: 'detect',
},
};
future: {
experimental_faster: true,
},
} satisfies Config;
export default config;

View file

@ -15,19 +15,15 @@
},
"dependencies": {
"@docusaurus/core": "^3.6.3",
"@docusaurus/faster": "^3.6.3",
"@docusaurus/plugin-content-blog": "^3.6.3",
"@docusaurus/preset-classic": "^3.6.3",
"@easyops-cn/docusaurus-search-local": "^0.46.0",
"@mdx-js/react": "^3.1.0",
"@svgr/webpack": "^8.1.0",
"clsx": "^2.1.1",
"esbuild-loader": "^4.2.2",
"file-loader": "^6.2.0",
"prism-react-renderer": "^2.4.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"redocusaurus": "^2.2.0",
"url-loader": "^4.1.1"
"redocusaurus": "^2.2.0"
},
"browserslist": {
"production": [
@ -46,16 +42,9 @@
"@docusaurus/tsconfig": "3.6.3",
"@docusaurus/types": "^3.6.3",
"@types/node": "^22.9.3",
"@types/react": "^18.3.12",
"@types/react": "^18.3.1",
"@types/react-helmet": "^6.1.11",
"@types/react-router-dom": "^5.3.3",
"typescript": "^5.7.2"
},
"pnpm": {
"overrides": {
"got": "^14.0.0",
"path-to-regexp": "^3.3.0",
"cookie": "^1.0.0"
}
}
}

View file

@ -23,8 +23,8 @@
"typescript": "^5.7.2"
},
"peerDependencies": {
"react": "^17.0.2 || ^18.0.0",
"react-dom": "^17.0.2 || ^18.0.0"
"react": "^17.0.2 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0"
},
"dependencies": {
"fuse.js": "^7.0.0",

File diff suppressed because it is too large Load diff

View file

@ -1,66 +1,171 @@
# Migrations
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`
:::info
This will be the next version of Woodpecker.
:::
- No changes
## User migrations
## 3.0.0
- 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.
- 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
- 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`
- CLI commands got restructured to provide a simplified structure:
- `woodpecker-cli secret [add|rm|...] --global` is now `woodpecker-cli admin secret [add|rm|...]`
- `woodpecker-cli user` is now `woodpecker-cli admin user`
- `woodpecker-cli log-level` is now `woodpecker-cli admin log-level`
- `woodpecker-cli secret [add|rm|...] --organization` is now `woodpecker-cli org secret [add|rm|...]`
- `woodpecker-cli deploy` is now `woodpecker-cli pipeline deploy`
- `woodpecker-cli log` is now `woodpecker-cli pipeline log`
- `woodpecker-cli cron` is now `woodpecker-cli repo cron`
- `woodpecker-cli secret [add|rm|...] --repository` is now `woodpecker-cli repo secret [add|rm|...]`
- `woodpecker-cli pipeline logs` is now `woodpecker-cli pipeline log show`
- `woodpecker-cli [registry|secret|...] info` is now `woodpecker-cli [registry|secret|...] show`
### User-facing migrations
## Admin migrations
#### Security
- The "gated" option, which restricted which pipelines can start right away without requiring approval, has been replaced by "require-approval" option. Even though this feature ([#3348](https://github.com/woodpecker-ci/woodpecker/pull/3348)) was backported to 2.8, no default is explicitly set.
The new default in 3.0 is to require approval only for forked repositories.
This allows easier management of dependency bots and other trusted entities having write access to the repository.
#### Environment variables
- Environment variables must now be defined as maps. List definitions are disallowed. ([#4016](https://github.com/woodpecker-ci/woodpecker/pull/4016))
2.x:
```yaml
environment:
- ENV1=value1
```
3.x:
```yaml
environment:
ENV1: value1
```
The following built-in environment variables have been removed/replaced:
- `CI_COMMIT_URL` has been deprecated in favor of `CI_PIPELINE_FORGE_URL`
- `CI_STEP_FINISHED` as it was empty during execution
- `CI_PIPELINE_FINISHED` as it was empty during execution
- `CI_PIPELINE_STATUS` due to always being set to `success`
- `CI_STEP_STATUS` due to always being set to `success`
- `WOODPECKER_WEBHOOK_HOST` in favor of `WOODPECKER_EXPERT_WEBHOOK_HOST`
Environment variables which are empty after workflow parsing are not being injected into the build but filtered out beforehand ([#4193](https://github.com/woodpecker-ci/woodpecker/pull/4193))
#### Former deprecations
The following syntax deprecations will now result in an error:
- `pipeline:` ([#3916](https://github.com/woodpecker-ci/woodpecker/pull/3916))
- `platform:` ([#3916](https://github.com/woodpecker-ci/woodpecker/pull/3916))
- `branches:` ([#3916](https://github.com/woodpecker-ci/woodpecker/pull/3916))
#### Workflow syntax changes
- Grouping of steps via `steps.[name].group` should now be done using `steps.[name].depends_on`
- The `includes` and `excludes` event filter options have been removed
- Previously, env vars have been automatically sanitized to uppercase.
As this has been confusing, the type-case of the secret definition is now respected ([#3375](https://github.com/woodpecker-ci/woodpecker/pull/3375)).
- `secrets` have been entirely removed in favor of `environment` combined with the `from_secret` syntax.
As `secrets` are just normal env vars which are masked, the goal was to allow them to be declared next to normal env vars and at the same time reduce the keyword syntax count.
Additionally, the `from_secret` syntax gives more flexibility in naming.
Whereas beforehand `secrets` where always named after their initial secret name, the `from_secret` reference can now be different.
Last, one can inject multiple different env vars from the same secret reference.
2.x:
```yaml
secrets: [my_token]
```
3.x:
```yaml
environment:
MY_TOKEN:
from_secret: my_token
```
- The `environment` filter option has been removed in favor of `when.evaluate`
#### API changes
- Removed deprecated `registry/` endpoint. Use `registries`, `/authorize/token`
#### CLI changes
The following restructuring was done to achieve a more consistent grouping:
| Old Command | New Command |
| ------------------------------------------- | ------------------------------------------- |
| `woodpecker-cli registry` | `woodpecker-cli repo registry` |
| `woodpecker-cli secret --global` | `woodpecker-cli admin secret` |
| `woodpecker-cli user` | `woodpecker-cli admin user` |
| `woodpecker-cli log-level` | `woodpecker-cli admin log-level` |
| `woodpecker-cli secret --organization` | `woodpecker-cli org secret` |
| `woodpecker-cli deploy` | `woodpecker-cli pipeline deploy` |
| `woodpecker-cli log` | `woodpecker-cli pipeline log` |
| `woodpecker-cli cron` | `woodpecker-cli repo cron` |
| `woodpecker-cli secret --repository` | `woodpecker-cli repo secret` |
| `woodpecker-cli pipeline logs` | `woodpecker-cli pipeline log show` |
| `woodpecker-cli (registry,secret,...) info` | `woodpecker-cli (registry,secret,...) show` |
#### Miscellaneous
- For `woodpecker-cli` containers, `/woodpecker` has been set as the default `workdir`
- Plugin filters for secrets (in the "secrets" repo settings) can now validate against tags.
Additionally, the description has been updated to reflect that these filters only apply to plugins ([#4069](https://github.com/woodpecker-ci/woodpecker/pull/4069)).
- SDK changes:
- The SDK fields `start_time`, `end_time`, `created_at`, `started_at`, `finished_at` and `reviewed_at` have been renamed to `started`, `finished`, `created`, `started`, `finished`, `reviewed` ([#3968](https://github.com/woodpecker-ci/woodpecker/pull/3968))
- The `trusted` field of the repo model was changed from `boolean` to `object`
- CRON definitions now use standard Linux syntax without seconds.
All custom CRON definitions which do not use keywords such as `@daily` or `@weekly` must be updated.
Example definition for a CRON job running at 8 am daily:
2.x:
```sh
0 0 8 * * *
```
3.x:
```sh
0 8 * * *
```
- Native Let's Encrypt certificate support has been dropped as it was almost unused and causing frequent issues.
Let's Encrypt needs to be set up standalone now. The SSL key pair can still be used in `WOODPECKER_SERVER_CERT` and `WOODPECKER_SERVER_KEY` as an alternative to using a reverse proxy for TLS termination.
### Admin-facing migrations
- Previously, some (official) plugins were granted the `privileged` option by default to allow simplified usage.
To streamline this process and enhance security transparency, no plugin is granted the `privileged` options by default anymore.
To allow the use of these plugins in >= 3.0, they must be set explicitly through `WOODPECKER_PLUGINS_PRIVILEGED` on the admin side.
This change mainly impacts the use of the `woodpeckerci/plugin-docker-buildx` plugin, which now will not work anymore unless explicitly listed through this env var ([#4053](https://github.com/woodpecker-ci/woodpecker/pull/4053))
- Environment variable deprecations:
| Deprecated Variable | New Variable |
| -------------------------------- | ------------------------------------ |
| `WOODPECKER_LOG_XORM` | `WOODPECKER_DATABASE_LOG` |
| `WOODPECKER_LOG_XORM_SQL` | `WOODPECKER_DATABASE_LOG_SQL` |
| `WOODPECKER_FILTER_LABELS` | `WOODPECKER_AGENT_LABELS` |
| `WOODPECKER_ESCALATE` | `WOODPECKER_PLUGINS_PRIVILEGED` |
| `WOODPECKER_DEFAULT_CLONE_IMAGE` | `WOODPECKER_DEFAULT_CLONE_PLUGIN` |
| `WOODPECKER_DEV_OAUTH_HOST` | `WOODPECKER_EXPERT_FORGE_OAUTH_HOST` |
| `WOODPECKER_DEV_GITEA_OAUTH_URL` | `WOODPECKER_EXPERT_FORGE_OAUTH_HOST` |
| `WOODPECKER_ROOT_PATH` | `WOODPECKER_HOST` |
| `WOODPECKER_ROOT_URL` | `WOODPECKER_HOST` |
- The resource limit settings for the "docker" backend were moved from the server into agent configuration.
This allows setting limits on an agent-level which allows greater resource definition granularity ([#3174](https://github.com/woodpecker-ci/woodpecker/pull/3174))
- "Kubernetes" backend: previously the image pull secret name was hard-coded to `regcred`.
To allow more flexibility and specifying multiple pull secrets, the default has been removed.
Image pull secrets must now be set explicitly via env var `WOODPECKER_BACKEND_K8S_PULL_SECRET_NAMES` ([#4005](https://github.com/woodpecker-ci/woodpecker/pull/4005))
- Webhook signatures now use the `rfc9421` protocol
- 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
- Upgrading from 1.x versions to 3.x is disallowed, upgrading to 2.x first is required to ensure proper DB migrations
## 2.7.2

View file

@ -13,6 +13,12 @@ Woodpecker provides three different levels to add secrets to your pipeline. The
### Use secrets in commands
:::warning
The use of secrets is deprecated as of version 2.8 and planned to be removed with version 3.
Instead, you can use the *secrets in settings and environment* approach outlined below.
You can already migrate to this strategy with version 2.8.
:::
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:
@ -30,17 +36,27 @@ The case of the environment variables is not changed, but secret matching is don
### 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 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`.
The example below passes a secret called `secret_token` as an environment variable that will be called `TOKEN_ENV`:
```diff
steps:
- name: docker
image: my-plugin
env-secret-example:
image: alpine
commands:
+ - echo "The secret is $TOKEN_ENV"
+ environment:
+ TOKEN_ENV:
+ from_secret: secret_token
```
You can use the same syntax to pass secrets to settings. For example, you can pass a secret named `secret_token` to the settings called `token`, which will then be available in the plugin as environment variable named `PLUGIN_TOKEN` (See [plugins](./51-plugins/20-creating-plugins.md#settings) for details).
```diff
steps:
- name: settings-secret-example
image: my-plugin
+ settings:
+ token:
+ from_secret: secret_token

78
go.mod
View file

@ -1,8 +1,6 @@
module go.woodpecker-ci.org/woodpecker/v2
go 1.22.7
toolchain go1.23.3
go 1.23.4
require (
al.essio.dev/pkg/shellescape v1.5.1
@ -13,13 +11,12 @@ require (
github.com/6543/logfile-open v1.2.1
github.com/adrg/xdg v0.5.3
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.6.0
github.com/charmbracelet/huh/spinner v0.0.0-20240327025511-ec643317aa10
github.com/distribution/reference v0.6.0
github.com/docker/cli v27.3.1+incompatible
github.com/docker/docker v27.3.1+incompatible
github.com/docker/cli v27.4.0+incompatible
github.com/docker/docker v27.4.0+incompatible
github.com/docker/go-connections v0.5.0
github.com/docker/go-units v0.5.0
github.com/drone/envsubst v1.0.3
@ -27,10 +24,11 @@ require (
github.com/franela/goblin v0.0.0-20211003143422-0a4f594942bf
github.com/fsnotify/fsnotify v1.8.0
github.com/gdgvda/cron v0.3.0
github.com/getkin/kin-openapi v0.127.0
github.com/getkin/kin-openapi v0.128.1-0.20241211220347-325cecc5e4e1
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/go-viper/mapstructure/v2 v2.2.1
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/google/go-github/v67 v67.0.0
github.com/google/tink/go v1.7.0
@ -42,10 +40,9 @@ require (
github.com/kinbiko/jsonassert v1.2.0
github.com/lib/pq v1.10.9
github.com/mattn/go-sqlite3 v1.14.24
github.com/mitchellh/mapstructure v1.5.0
github.com/moby/moby v27.3.1+incompatible
github.com/moby/moby v27.4.0+incompatible
github.com/moby/term v0.5.0
github.com/muesli/termenv v0.15.3-0.20240912151726-82936c5ea257
github.com/muesli/termenv v0.15.3-0.20241212154518-8c990cd6cf4b
github.com/neticdk/go-bitbucket v1.0.0
github.com/oklog/ulid/v2 v2.1.0
github.com/pkg/errors v0.9.1
@ -56,24 +53,24 @@ require (
github.com/swaggo/gin-swagger v1.6.0
github.com/swaggo/swag v1.16.4
github.com/urfave/cli-docs/v3 v3.0.0-alpha6
github.com/urfave/cli/v3 v3.0.0-alpha9.10
github.com/xanzy/go-gitlab v0.114.0
github.com/urfave/cli/v3 v3.0.0-beta1
github.com/xeipuuv/gojsonschema v1.2.0
github.com/yaronf/httpsign v0.3.1
github.com/zalando/go-keyring v0.2.6
gitlab.com/gitlab-org/api/client-go v0.117.0
go.uber.org/multierr v1.11.0
golang.org/x/crypto v0.29.0
golang.org/x/net v0.31.0
golang.org/x/crypto v0.31.0
golang.org/x/net v0.32.0
golang.org/x/oauth2 v0.24.0
golang.org/x/sync v0.9.0
golang.org/x/term v0.26.0
golang.org/x/text v0.20.0
google.golang.org/grpc v1.68.0
google.golang.org/protobuf v1.35.2
golang.org/x/sync v0.10.0
golang.org/x/term v0.27.0
golang.org/x/text v0.21.0
google.golang.org/grpc v1.69.0
google.golang.org/protobuf v1.36.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.31.3
k8s.io/apimachinery v0.31.3
k8s.io/client-go v0.31.3
k8s.io/api v0.32.0
k8s.io/apimachinery v0.32.0
k8s.io/client-go v0.32.0
src.techknowlogick.com/xormigrate v1.7.1
xorm.io/builder v0.3.13
xorm.io/xorm v1.3.9
@ -90,7 +87,6 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
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.20.0 // indirect
@ -141,8 +137,6 @@ require (
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/invopop/yaml v0.3.1 // indirect
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
@ -155,15 +149,12 @@ require (
github.com/lestrrat-go/iter v1.0.2 // indirect
github.com/lestrrat-go/jwx/v2 v2.1.0 // indirect
github.com/lestrrat-go/option v1.0.1 // indirect
github.com/libdns/libdns v0.2.2 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
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.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
@ -173,10 +164,10 @@ require (
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/oasdiff/yaml v0.0.0-20241210131133-6b86fb107d80 // indirect
github.com/oasdiff/yaml3 v0.0.0-20241210130736-a94c01f36349 // indirect
github.com/oklog/run v1.0.0 // indirect
github.com/onsi/ginkgo v1.16.4 // indirect
github.com/onsi/ginkgo/v2 v2.20.2 // indirect
github.com/onsi/gomega v1.34.2 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
@ -199,28 +190,25 @@ require (
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/zeebo/blake3 v0.2.4 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
go.opentelemetry.io/otel v1.29.0 // indirect
go.opentelemetry.io/otel v1.31.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 // indirect
go.opentelemetry.io/otel/metric v1.29.0 // indirect
go.opentelemetry.io/otel/sdk v1.28.0 // indirect
go.opentelemetry.io/otel/trace v1.29.0 // indirect
go.uber.org/zap v1.27.0 // indirect
go.opentelemetry.io/otel/metric v1.31.0 // indirect
go.opentelemetry.io/otel/trace v1.31.0 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/time v0.6.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/time v0.7.0 // indirect
golang.org/x/tools v0.27.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // 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.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // 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
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)

163
go.sum
View file

@ -48,10 +48,6 @@ github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc
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.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=
github.com/catppuccin/go v0.2.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
@ -108,10 +104,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.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/cli v27.4.0+incompatible h1:/nJzWkcI1MDMN+U+px/YXnQWJqnu4J+QKGTfD6ptiTc=
github.com/docker/cli v27.4.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/docker v27.4.0+incompatible h1:I9z7sQ5qyzO0BfAb9IMOawRkAGxhYsidKiTMcm0DU+A=
github.com/docker/docker v27.4.0+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=
@ -148,8 +144,8 @@ github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uq
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
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/getkin/kin-openapi v0.128.1-0.20241211220347-325cecc5e4e1 h1:jIUT6NT0F50dhHXlFWsGfdJI/5OnnzO6HZHSiSh5DfM=
github.com/getkin/kin-openapi v0.128.1-0.20241211220347-325cecc5e4e1/go.mod h1:gmWI+b/J45xqpyK5wJmRRZse5wefA5H0RDMK46kLUtI=
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=
@ -193,6 +189,8 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v
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/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
@ -243,8 +241,8 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
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/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 h1:5iH8iuqE5apketRbSFBy+X1V0o+l+8NF1avt4HWl7cA=
github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
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=
@ -271,10 +269,6 @@ github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso=
github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
@ -372,8 +366,6 @@ github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s=
github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
@ -400,18 +392,12 @@ github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
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.3.1+incompatible h1:KQbXBjo7PavKpzIl7UkHT31y9lw/e71Uvrqhr4X+zMA=
github.com/moby/moby v27.3.1+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
github.com/moby/moby v27.4.0+incompatible h1:jGXXZCMAmFZS9pKsQqUt9yAPHOC450PM9lbQYPSQnuc=
github.com/moby/moby v27.4.0+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=
@ -428,8 +414,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.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/muesli/termenv v0.15.3-0.20241212154518-8c990cd6cf4b h1:gmVbquSG+bANneniKyO7R2DkOlCat7XDaSfXxHKKQBY=
github.com/muesli/termenv v0.15.3-0.20241212154518-8c990cd6cf4b/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=
@ -437,6 +423,10 @@ github.com/neticdk/go-bitbucket v1.0.0/go.mod h1:IrHeWO1CrNi0DlOvfhAA9bGRSeNSUB6
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oasdiff/yaml v0.0.0-20241210131133-6b86fb107d80 h1:nZspmSkneBbtxU9TopEAE0CY+SBJLxO8LPUlw2vG4pU=
github.com/oasdiff/yaml v0.0.0-20241210131133-6b86fb107d80/go.mod h1:7tFDb+Y51LcDpn26GccuUgQXUk6t0CXZsivKjyimYX8=
github.com/oasdiff/yaml3 v0.0.0-20241210130736-a94c01f36349 h1:t05Ww3DxZutOqbMN+7OIuqDwXbhl32HiZGpLy26BAPc=
github.com/oasdiff/yaml3 v0.0.0-20241210130736-a94c01f36349/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o=
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU=
@ -446,13 +436,13 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8=
github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc=
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
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=
@ -545,12 +535,10 @@ github.com/urfave/cli-docs/v3 v3.0.0-alpha6 h1:w/l/N0xw1rO/aHRIGXJ0lDwwYFOzilup1
github.com/urfave/cli-docs/v3 v3.0.0-alpha6/go.mod h1:p7Z4lg8FSTrPB9GTaNyTrK3ygffHZcK3w0cU2VE+mzU=
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/urfave/cli/v3 v3.0.0-alpha9.10 h1:whPwidq9cUh18NBqzSR8N3tts8NiQDsTmt9s7AyX85c=
github.com/urfave/cli/v3 v3.0.0-alpha9.10/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg=
github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
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.114.0 h1:0wQr/KBckwrZPfEMjRqpUz0HmsKKON9UhCYv9KDy19M=
github.com/xanzy/go-gitlab v0.114.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=
@ -565,28 +553,26 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
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.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=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
gitlab.com/gitlab-org/api/client-go v0.117.0 h1:HsbKxlTjVgfYmyCU+NRQk2G42RlMOKs6gF+/o0DL+TI=
gitlab.com/gitlab-org/api/client-go v0.117.0/go.mod h1:E+X2dndIYDuUfKVP0C3jhkWvTSE00BkLbCsXTY3edDo=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY=
go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 h1:j9+03ymgYhPKmeXGk5Zu+cIZOlVzd9Zv7QIiyItjFBU=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0/go.mod h1:Y5+XiUG4Emn1hTfciPzGPJaSI+RpDts6BnCIir0SLqk=
go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE=
go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg=
go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4=
go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE=
go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY=
go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk=
go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0=
go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc=
go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys=
go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
@ -604,8 +590,6 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
@ -623,8 +607,8 @@ 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.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
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=
@ -647,8 +631,8 @@ 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.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -656,8 +640,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
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.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.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=
@ -692,14 +676,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.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.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.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
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=
@ -707,10 +691,10 @@ 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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
@ -734,25 +718,27 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
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-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc=
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0=
google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA=
google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 h1:fVoAXEKA4+yufmbdVYv+SE73+cPZbbbe8paLsHfkK+U=
google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
google.golang.org/grpc v1.69.0 h1:quSiOM1GJPmPH5XtU+BCoVXcDVJJAzNcoyfC2cCjGkI=
google.golang.org/grpc v1.69.0/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ=
google.golang.org/protobuf v1.36.0/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=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
@ -765,7 +751,6 @@ gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@ -774,18 +759,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.31.3 h1:umzm5o8lFbdN/hIXbrK9oRpOproJO62CV1zqxXrLgk8=
k8s.io/api v0.31.3/go.mod h1:UJrkIp9pnMOI9K2nlL6vwpxRzzEX5sWgn8kGQe92kCE=
k8s.io/apimachinery v0.31.3 h1:6l0WhcYgasZ/wk9ktLq5vLaoXJJr5ts6lkaQzgeYPq4=
k8s.io/apimachinery v0.31.3/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
k8s.io/client-go v0.31.3 h1:CAlZuM+PH2cm+86LOBemaJI/lQ5linJ6UFxKX/SoG+4=
k8s.io/client-go v0.31.3/go.mod h1:2CgjPUTpv3fE5dNygAr2NcM8nhHzXvxB8KL5gYc3kJs=
k8s.io/api v0.32.0 h1:OL9JpbvAU5ny9ga2fb24X8H6xQlVp+aJMFlgtQjR9CE=
k8s.io/api v0.32.0/go.mod h1:4LEwHZEf6Q/cG96F3dqR965sYOfmPM7rq81BLgsE0p0=
k8s.io/apimachinery v0.32.0 h1:cFSE7N3rmEEtv4ei5X6DaJPHHX0C+upp+v5lVPiEwpg=
k8s.io/apimachinery v0.32.0/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
k8s.io/client-go v0.32.0 h1:DimtMcnN/JIKZcrSrstiwvvZvLjG0aSxy8PxN8IChp8=
k8s.io/client-go v0.32.0/go.mod h1:boDWvdM1Drk4NJj/VddSLnx59X3OPgwrOo0vGbtq9+8=
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-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y=
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4=
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/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=
@ -825,10 +810,10 @@ modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.7.0/go.mod h1:hVdgNMh8ggTuRG1rGU8x+xGRFfiQUIAw0ZqlPy8+HyQ=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA=
sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
src.techknowlogick.com/xormigrate v1.7.1 h1:RKGLLUAqJ+zO8iZ7eOc7oLH7f0cs2gfXSZSvBRBHnlY=

View file

@ -0,0 +1,21 @@
package docker
import (
"github.com/go-viper/mapstructure/v2"
backend "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
)
// BackendOptions defines all the advanced options for the docker backend.
type BackendOptions struct {
User string `mapstructure:"user"`
}
func parseBackendOptions(step *backend.Step) (BackendOptions, error) {
var result BackendOptions
if step == nil || step.BackendOptions == nil {
return result, nil
}
err := mapstructure.WeakDecode(step.BackendOptions[EngineName], &result)
return result, err
}

View file

@ -0,0 +1,56 @@
package docker
import (
"testing"
"github.com/stretchr/testify/assert"
backend "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
)
func Test_parseBackendOptions(t *testing.T) {
tests := []struct {
name string
step *backend.Step
want BackendOptions
wantErr bool
}{
{
name: "nil options",
step: &backend.Step{BackendOptions: nil},
want: BackendOptions{},
},
{
name: "empty options",
step: &backend.Step{BackendOptions: map[string]any{}},
want: BackendOptions{},
},
{
name: "with user option",
step: &backend.Step{BackendOptions: map[string]any{
"docker": map[string]any{
"user": "1000:1000",
},
}},
want: BackendOptions{User: "1000:1000"},
},
{
name: "invalid backend options",
step: &backend.Step{BackendOptions: map[string]any{"docker": "invalid"}},
want: BackendOptions{},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseBackendOptions(tt.step)
if tt.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
assert.Equal(t, tt.want, got)
})
}
}

View file

@ -31,7 +31,7 @@ import (
const minVolumeComponents = 2
// returns a container configuration.
func (e *docker) toConfig(step *types.Step) *container.Config {
func (e *docker) toConfig(step *types.Step, options BackendOptions) *container.Config {
e.windowsPathPatch(step)
config := &container.Config{
@ -44,6 +44,7 @@ func (e *docker) toConfig(step *types.Step) *container.Config {
AttachStdout: true,
AttachStderr: true,
Volumes: toVol(step.Volumes),
User: options.User,
}
configEnv := make(map[string]string)
maps.Copy(configEnv, step.Environment)

View file

@ -131,7 +131,7 @@ func TestToContainerName(t *testing.T) {
func TestStepToConfig(t *testing.T) {
// StepTypeCommands
conf := testEngine.toConfig(testCmdStep)
conf := testEngine.toConfig(testCmdStep, BackendOptions{})
if assert.NotNil(t, conf) {
assert.EqualValues(t, []string{"/bin/sh", "-c", "echo $CI_SCRIPT | base64 -d | /bin/sh -e"}, conf.Entrypoint)
assert.Nil(t, conf.Cmd)
@ -139,7 +139,7 @@ func TestStepToConfig(t *testing.T) {
}
// StepTypePlugin
conf = testEngine.toConfig(testPluginStep)
conf = testEngine.toConfig(testPluginStep, BackendOptions{})
if assert.NotNil(t, conf) {
assert.Nil(t, conf.Cmd)
assert.EqualValues(t, testPluginStep.UUID, conf.Labels["wp_uuid"])
@ -174,7 +174,7 @@ func TestToConfigSmall(t *testing.T) {
Name: "test",
UUID: "09238932",
Commands: []string{"go test"},
})
}, BackendOptions{})
assert.NotNil(t, conf)
sort.Strings(conf.Env)
@ -233,7 +233,7 @@ func TestToConfigFull(t *testing.T) {
AuthConfig: backend.Auth{Username: "user", Password: "123456"},
NetworkMode: "bridge",
Ports: []backend.Port{{Number: 21}, {Number: 22}},
})
}, BackendOptions{})
assert.NotNil(t, conf)
sort.Strings(conf.Env)
@ -286,7 +286,7 @@ func TestToWindowsConfig(t *testing.T) {
AuthConfig: backend.Auth{Username: "user", Password: "123456"},
NetworkMode: "nat",
Ports: []backend.Port{{Number: 21}, {Number: 22}},
})
}, BackendOptions{})
assert.NotNil(t, conf)
sort.Strings(conf.Env)

View file

@ -46,6 +46,7 @@ type docker struct {
}
const (
EngineName = "docker"
networkDriverNAT = "nat"
networkDriverBridge = "bridge"
volumeDriver = "local"
@ -59,7 +60,7 @@ func New() backend.Backend {
}
func (e *docker) Name() string {
return "docker"
return EngineName
}
func (e *docker) IsAvailable(ctx context.Context) bool {
@ -170,9 +171,14 @@ func (e *docker) SetupWorkflow(ctx context.Context, conf *backend.Config, taskUU
}
func (e *docker) StartStep(ctx context.Context, step *backend.Step, taskUUID string) error {
options, err := parseBackendOptions(step)
if err != nil {
log.Error().Err(err).Msg("could not parse backend options")
}
log.Trace().Str("taskUUID", taskUUID).Msgf("start step %s", step.Name)
config := e.toConfig(step)
config := e.toConfig(step, options)
hostConfig := toHostConfig(step, &e.config)
containerName := toContainerName(step)
@ -204,7 +210,7 @@ func (e *docker) StartStep(ctx context.Context, step *backend.Step, taskUUID str
// add default volumes to the host configuration
hostConfig.Binds = utils.DeduplicateStrings(append(hostConfig.Binds, e.config.volumes...))
_, err := e.client.ContainerCreate(ctx, config, hostConfig, nil, nil, containerName)
_, err = e.client.ContainerCreate(ctx, config, hostConfig, nil, nil, containerName)
if client.IsErrNotFound(err) {
// automatically pull and try to re-create the image if the
// failure is caused because the image does not exist.

View file

@ -1,7 +1,7 @@
package kubernetes
import (
"github.com/mitchellh/mapstructure"
"github.com/go-viper/mapstructure/v2"
backend "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
)
@ -86,9 +86,9 @@ const (
func parseBackendOptions(step *backend.Step) (BackendOptions, error) {
var result BackendOptions
if step.BackendOptions == nil {
if step == nil || step.BackendOptions == nil {
return result, nil
}
err := mapstructure.Decode(step.BackendOptions[EngineName], &result)
err := mapstructure.WeakDecode(step.BackendOptions[EngineName], &result)
return result, err
}

View file

@ -9,97 +9,139 @@ import (
)
func Test_parseBackendOptions(t *testing.T) {
got, err := parseBackendOptions(&backend.Step{BackendOptions: nil})
assert.NoError(t, err)
assert.Equal(t, BackendOptions{}, got)
got, err = parseBackendOptions(&backend.Step{BackendOptions: map[string]any{}})
assert.NoError(t, err)
assert.Equal(t, BackendOptions{}, got)
got, err = parseBackendOptions(&backend.Step{
BackendOptions: map[string]any{
"kubernetes": map[string]any{
"nodeSelector": map[string]string{"storage": "ssd"},
"serviceAccountName": "wp-svc-acc",
"labels": map[string]string{"app": "test"},
"annotations": map[string]string{"apps.kubernetes.io/pod-index": "0"},
"tolerations": []map[string]any{
{"key": "net-port", "value": "100Mbit", "effect": TaintEffectNoSchedule},
},
"resources": map[string]any{
"requests": map[string]string{"memory": "128Mi", "cpu": "1000m"},
"limits": map[string]string{"memory": "256Mi", "cpu": "2"},
},
"securityContext": map[string]any{
"privileged": newBool(true),
"runAsNonRoot": newBool(true),
"runAsUser": newInt64(101),
"runAsGroup": newInt64(101),
"fsGroup": newInt64(101),
"seccompProfile": map[string]any{
"type": "Localhost",
"localhostProfile": "profiles/audit.json",
},
"apparmorProfile": map[string]any{
"type": "Localhost",
"localhostProfile": "k8s-apparmor-example-deny-write",
},
},
"secrets": []map[string]any{
{
"name": "aws",
"key": "access-key",
"target": map[string]any{
"env": "AWS_SECRET_ACCESS_KEY",
tests := []struct {
name string
step *backend.Step
want BackendOptions
wantErr bool
}{
{
name: "nil options",
step: &backend.Step{BackendOptions: nil},
want: BackendOptions{},
},
{
name: "empty options",
step: &backend.Step{BackendOptions: map[string]any{}},
want: BackendOptions{},
},
{
name: "full k8s options",
step: &backend.Step{
BackendOptions: map[string]any{
"kubernetes": map[string]any{
"nodeSelector": map[string]string{"storage": "ssd"},
"serviceAccountName": "wp-svc-acc",
"labels": map[string]string{"app": "test"},
"annotations": map[string]string{"apps.kubernetes.io/pod-index": "0"},
"tolerations": []map[string]any{
{"key": "net-port", "value": "100Mbit", "effect": TaintEffectNoSchedule},
},
},
{
"name": "reg-cred",
"key": ".dockerconfigjson",
"target": map[string]any{
"file": "~/.docker/config.json",
"resources": map[string]any{
"requests": map[string]string{"memory": "128Mi", "cpu": "1000m"},
"limits": map[string]string{"memory": "256Mi", "cpu": "2"},
},
"securityContext": map[string]any{
"privileged": newBool(true),
"runAsNonRoot": newBool(true),
"runAsUser": newInt64(101),
"runAsGroup": newInt64(101),
"fsGroup": newInt64(101),
"seccompProfile": map[string]any{
"type": "Localhost",
"localhostProfile": "profiles/audit.json",
},
"apparmorProfile": map[string]any{
"type": "Localhost",
"localhostProfile": "k8s-apparmor-example-deny-write",
},
},
"secrets": []map[string]any{
{
"name": "aws",
"key": "access-key",
"target": map[string]any{
"env": "AWS_SECRET_ACCESS_KEY",
},
},
{
"name": "reg-cred",
"key": ".dockerconfigjson",
"target": map[string]any{
"file": "~/.docker/config.json",
},
},
},
},
},
},
},
})
assert.NoError(t, err)
assert.Equal(t, BackendOptions{
NodeSelector: map[string]string{"storage": "ssd"},
ServiceAccountName: "wp-svc-acc",
Labels: map[string]string{"app": "test"},
Annotations: map[string]string{"apps.kubernetes.io/pod-index": "0"},
Tolerations: []Toleration{{Key: "net-port", Value: "100Mbit", Effect: TaintEffectNoSchedule}},
Resources: Resources{
Requests: map[string]string{"memory": "128Mi", "cpu": "1000m"},
Limits: map[string]string{"memory": "256Mi", "cpu": "2"},
},
SecurityContext: &SecurityContext{
Privileged: newBool(true),
RunAsNonRoot: newBool(true),
RunAsUser: newInt64(101),
RunAsGroup: newInt64(101),
FSGroup: newInt64(101),
SeccompProfile: &SecProfile{
Type: "Localhost",
LocalhostProfile: "profiles/audit.json",
},
ApparmorProfile: &SecProfile{
Type: "Localhost",
LocalhostProfile: "k8s-apparmor-example-deny-write",
want: BackendOptions{
NodeSelector: map[string]string{"storage": "ssd"},
ServiceAccountName: "wp-svc-acc",
Labels: map[string]string{"app": "test"},
Annotations: map[string]string{"apps.kubernetes.io/pod-index": "0"},
Tolerations: []Toleration{{Key: "net-port", Value: "100Mbit", Effect: TaintEffectNoSchedule}},
Resources: Resources{
Requests: map[string]string{"memory": "128Mi", "cpu": "1000m"},
Limits: map[string]string{"memory": "256Mi", "cpu": "2"},
},
SecurityContext: &SecurityContext{
Privileged: newBool(true),
RunAsNonRoot: newBool(true),
RunAsUser: newInt64(101),
RunAsGroup: newInt64(101),
FSGroup: newInt64(101),
SeccompProfile: &SecProfile{
Type: "Localhost",
LocalhostProfile: "profiles/audit.json",
},
ApparmorProfile: &SecProfile{
Type: "Localhost",
LocalhostProfile: "k8s-apparmor-example-deny-write",
},
},
Secrets: []SecretRef{
{
Name: "aws",
Key: "access-key",
Target: SecretTarget{Env: "AWS_SECRET_ACCESS_KEY"},
},
{
Name: "reg-cred",
Key: ".dockerconfigjson",
Target: SecretTarget{File: "~/.docker/config.json"},
},
},
},
},
Secrets: []SecretRef{
{
Name: "aws",
Key: "access-key",
Target: SecretTarget{Env: "AWS_SECRET_ACCESS_KEY"},
},
{
Name: "reg-cred",
Key: ".dockerconfigjson",
Target: SecretTarget{File: "~/.docker/config.json"},
{
name: "number options",
step: &backend.Step{BackendOptions: map[string]any{
"kubernetes": map[string]any{
"resources": map[string]any{
"requests": map[string]int{"memory": 128, "cpu": 1000},
"limits": map[string]int{"memory": 256, "cpu": 2},
},
},
}},
want: BackendOptions{
Resources: Resources{
Requests: map[string]string{"memory": "128", "cpu": "1000"},
Limits: map[string]string{"memory": "256", "cpu": "2"},
},
},
},
}, got)
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseBackendOptions(tt.step)
if tt.wantErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.Equal(t, tt.want, got)
})
}
}

View file

@ -437,7 +437,7 @@ func podSecurityContext(sc *SecurityContext, secCtxConf SecurityContextConfig, s
apparmor = apparmorProfile(sc.ApparmorProfile)
}
if nonRoot == nil && user == nil && group == nil && fsGroup == nil && seccomp == nil {
if nonRoot == nil && user == nil && group == nil && fsGroup == nil && seccomp == nil && apparmor == nil {
return nil
}

View file

@ -25,11 +25,143 @@ import (
"github.com/rs/zerolog/log"
)
var (
pullRegexp = regexp.MustCompile(`\d+`)
maxChangedFiles = 500
const (
initialEnvMapSize = 100
maxChangedFiles = 500
)
var pullRegexp = regexp.MustCompile(`\d+`)
// Environ returns the metadata as a map of environment variables.
func (m *Metadata) Environ() map[string]string {
params := make(map[string]string, initialEnvMapSize)
system := m.Sys
setNonEmptyEnvVar(params, "CI", system.Name)
setNonEmptyEnvVar(params, "CI_SYSTEM_NAME", system.Name)
setNonEmptyEnvVar(params, "CI_SYSTEM_URL", system.URL)
setNonEmptyEnvVar(params, "CI_SYSTEM_HOST", system.Host)
setNonEmptyEnvVar(params, "CI_SYSTEM_PLATFORM", system.Platform) // will be set by pipeline platform option or by agent
setNonEmptyEnvVar(params, "CI_SYSTEM_VERSION", system.Version)
forge := m.Forge
setNonEmptyEnvVar(params, "CI_FORGE_TYPE", forge.Type)
setNonEmptyEnvVar(params, "CI_FORGE_URL", forge.URL)
repo := m.Repo
setNonEmptyEnvVar(params, "CI_REPO", path.Join(repo.Owner, repo.Name))
setNonEmptyEnvVar(params, "CI_REPO_NAME", repo.Name)
setNonEmptyEnvVar(params, "CI_REPO_OWNER", repo.Owner)
setNonEmptyEnvVar(params, "CI_REPO_REMOTE_ID", repo.RemoteID)
setNonEmptyEnvVar(params, "CI_REPO_SCM", repo.SCM)
setNonEmptyEnvVar(params, "CI_REPO_URL", repo.ForgeURL)
setNonEmptyEnvVar(params, "CI_REPO_CLONE_URL", repo.CloneURL)
setNonEmptyEnvVar(params, "CI_REPO_CLONE_SSH_URL", repo.CloneSSHURL)
setNonEmptyEnvVar(params, "CI_REPO_DEFAULT_BRANCH", repo.Branch)
setNonEmptyEnvVar(params, "CI_REPO_PRIVATE", strconv.FormatBool(repo.Private))
setNonEmptyEnvVar(params, "CI_REPO_TRUSTED_NETWORK", strconv.FormatBool(repo.Trusted.Network))
setNonEmptyEnvVar(params, "CI_REPO_TRUSTED_VOLUMES", strconv.FormatBool(repo.Trusted.Volumes))
setNonEmptyEnvVar(params, "CI_REPO_TRUSTED_SECURITY", strconv.FormatBool(repo.Trusted.Security))
// Deprecated remove in 4.x
setNonEmptyEnvVar(params, "CI_REPO_TRUSTED", strconv.FormatBool(m.Repo.Trusted.Security && m.Repo.Trusted.Network && m.Repo.Trusted.Volumes))
pipeline := m.Curr
setNonEmptyEnvVar(params, "CI_PIPELINE_NUMBER", strconv.FormatInt(pipeline.Number, 10))
setNonEmptyEnvVar(params, "CI_PIPELINE_PARENT", strconv.FormatInt(pipeline.Parent, 10))
setNonEmptyEnvVar(params, "CI_PIPELINE_EVENT", pipeline.Event)
setNonEmptyEnvVar(params, "CI_PIPELINE_URL", m.getPipelineWebURL(pipeline, 0))
setNonEmptyEnvVar(params, "CI_PIPELINE_FORGE_URL", pipeline.ForgeURL)
setNonEmptyEnvVar(params, "CI_PIPELINE_DEPLOY_TARGET", pipeline.DeployTo)
setNonEmptyEnvVar(params, "CI_PIPELINE_DEPLOY_TASK", pipeline.DeployTask)
setNonEmptyEnvVar(params, "CI_PIPELINE_CREATED", strconv.FormatInt(pipeline.Created, 10))
setNonEmptyEnvVar(params, "CI_PIPELINE_STARTED", strconv.FormatInt(pipeline.Started, 10))
workflow := m.Workflow
setNonEmptyEnvVar(params, "CI_WORKFLOW_NAME", workflow.Name)
setNonEmptyEnvVar(params, "CI_WORKFLOW_NUMBER", strconv.Itoa(workflow.Number))
step := m.Step
setNonEmptyEnvVar(params, "CI_STEP_NAME", step.Name)
setNonEmptyEnvVar(params, "CI_STEP_NUMBER", strconv.Itoa(step.Number))
setNonEmptyEnvVar(params, "CI_STEP_URL", m.getPipelineWebURL(pipeline, step.Number))
// CI_STEP_STARTED will be set by agent
commit := pipeline.Commit
setNonEmptyEnvVar(params, "CI_COMMIT_SHA", commit.Sha)
setNonEmptyEnvVar(params, "CI_COMMIT_REF", commit.Ref)
setNonEmptyEnvVar(params, "CI_COMMIT_REFSPEC", commit.Refspec)
setNonEmptyEnvVar(params, "CI_COMMIT_MESSAGE", commit.Message)
setNonEmptyEnvVar(params, "CI_COMMIT_BRANCH", commit.Branch)
setNonEmptyEnvVar(params, "CI_COMMIT_AUTHOR", commit.Author.Name)
setNonEmptyEnvVar(params, "CI_COMMIT_AUTHOR_EMAIL", commit.Author.Email)
setNonEmptyEnvVar(params, "CI_COMMIT_AUTHOR_AVATAR", commit.Author.Avatar)
if pipeline.Event == EventTag || pipeline.Event == EventRelease || strings.HasPrefix(pipeline.Commit.Ref, "refs/tags/") {
setNonEmptyEnvVar(params, "CI_COMMIT_TAG", strings.TrimPrefix(pipeline.Commit.Ref, "refs/tags/"))
}
if pipeline.Event == EventRelease {
setNonEmptyEnvVar(params, "CI_COMMIT_PRERELEASE", strconv.FormatBool(pipeline.Commit.IsPrerelease))
}
if pipeline.Event == EventPull || pipeline.Event == EventPullClosed {
sourceBranch, targetBranch := getSourceTargetBranches(commit.Refspec)
setNonEmptyEnvVar(params, "CI_COMMIT_SOURCE_BRANCH", sourceBranch)
setNonEmptyEnvVar(params, "CI_COMMIT_TARGET_BRANCH", targetBranch)
setNonEmptyEnvVar(params, "CI_COMMIT_PULL_REQUEST", pullRegexp.FindString(pipeline.Commit.Ref))
setNonEmptyEnvVar(params, "CI_COMMIT_PULL_REQUEST_LABELS", strings.Join(pipeline.Commit.PullRequestLabels, ","))
}
// Only export changed files if maxChangedFiles is not exceeded
changedFiles := commit.ChangedFiles
if len(changedFiles) == 0 {
params["CI_PIPELINE_FILES"] = "[]"
} else if len(changedFiles) <= maxChangedFiles {
// we have to use json, as other separators like ;, or space are valid filename chars
changedFiles, err := json.Marshal(changedFiles)
if err != nil {
log.Error().Err(err).Msg("marshal changed files")
}
params["CI_PIPELINE_FILES"] = string(changedFiles)
}
prevPipeline := m.Prev
setNonEmptyEnvVar(params, "CI_PREV_PIPELINE_NUMBER", strconv.FormatInt(prevPipeline.Number, 10))
setNonEmptyEnvVar(params, "CI_PREV_PIPELINE_PARENT", strconv.FormatInt(prevPipeline.Parent, 10))
setNonEmptyEnvVar(params, "CI_PREV_PIPELINE_EVENT", prevPipeline.Event)
setNonEmptyEnvVar(params, "CI_PREV_PIPELINE_URL", m.getPipelineWebURL(prevPipeline, 0))
setNonEmptyEnvVar(params, "CI_PREV_PIPELINE_FORGE_URL", prevPipeline.ForgeURL)
setNonEmptyEnvVar(params, "CI_PREV_COMMIT_URL", prevPipeline.ForgeURL) // why commit url?
setNonEmptyEnvVar(params, "CI_PREV_PIPELINE_DEPLOY_TARGET", prevPipeline.DeployTo)
setNonEmptyEnvVar(params, "CI_PREV_PIPELINE_DEPLOY_TASK", prevPipeline.DeployTask)
setNonEmptyEnvVar(params, "CI_PREV_PIPELINE_STATUS", prevPipeline.Status)
setNonEmptyEnvVar(params, "CI_PREV_PIPELINE_CREATED", strconv.FormatInt(prevPipeline.Created, 10))
setNonEmptyEnvVar(params, "CI_PREV_PIPELINE_STARTED", strconv.FormatInt(prevPipeline.Started, 10))
setNonEmptyEnvVar(params, "CI_PREV_PIPELINE_FINISHED", strconv.FormatInt(prevPipeline.Finished, 10))
prevCommit := prevPipeline.Commit
setNonEmptyEnvVar(params, "CI_PREV_COMMIT_SHA", prevCommit.Sha)
setNonEmptyEnvVar(params, "CI_PREV_COMMIT_REF", prevCommit.Ref)
setNonEmptyEnvVar(params, "CI_PREV_COMMIT_REFSPEC", prevCommit.Refspec)
setNonEmptyEnvVar(params, "CI_PREV_COMMIT_MESSAGE", prevCommit.Message)
setNonEmptyEnvVar(params, "CI_PREV_COMMIT_BRANCH", prevCommit.Branch)
setNonEmptyEnvVar(params, "CI_PREV_COMMIT_AUTHOR", prevCommit.Author.Name)
setNonEmptyEnvVar(params, "CI_PREV_COMMIT_AUTHOR_EMAIL", prevCommit.Author.Email)
setNonEmptyEnvVar(params, "CI_PREV_COMMIT_AUTHOR_AVATAR", prevCommit.Author.Avatar)
if prevPipeline.Event == EventPull || prevPipeline.Event == EventPullClosed {
prevSourceBranch, prevTargetBranch := getSourceTargetBranches(prevCommit.Refspec)
setNonEmptyEnvVar(params, "CI_PREV_COMMIT_SOURCE_BRANCH", prevSourceBranch)
setNonEmptyEnvVar(params, "CI_PREV_COMMIT_TARGET_BRANCH", prevTargetBranch)
}
return params
}
func (m *Metadata) getPipelineWebURL(pipeline Pipeline, stepNumber int) string {
if stepNumber == 0 {
return fmt.Sprintf("%s/repos/%d/pipeline/%d", m.Sys.URL, m.Repo.ID, pipeline.Number)
}
return fmt.Sprintf("%s/repos/%d/pipeline/%d/%d", m.Sys.URL, m.Repo.ID, pipeline.Number, stepNumber)
}
func getSourceTargetBranches(refspec string) (string, string) {
var (
sourceBranch string
@ -45,124 +177,10 @@ func getSourceTargetBranches(refspec string) (string, string) {
return sourceBranch, targetBranch
}
// Environ returns the metadata as a map of environment variables.
func (m *Metadata) Environ() map[string]string {
sourceBranch, targetBranch := getSourceTargetBranches(m.Curr.Commit.Refspec)
prevSourceBranch, prevTargetBranch := getSourceTargetBranches(m.Prev.Commit.Refspec)
params := map[string]string{
"CI": m.Sys.Name,
"CI_REPO": path.Join(m.Repo.Owner, m.Repo.Name),
"CI_REPO_NAME": m.Repo.Name,
"CI_REPO_OWNER": m.Repo.Owner,
"CI_REPO_REMOTE_ID": m.Repo.RemoteID,
"CI_REPO_SCM": m.Repo.SCM,
"CI_REPO_URL": m.Repo.ForgeURL,
"CI_REPO_CLONE_URL": m.Repo.CloneURL,
"CI_REPO_CLONE_SSH_URL": m.Repo.CloneSSHURL,
"CI_REPO_DEFAULT_BRANCH": m.Repo.Branch,
"CI_REPO_PRIVATE": strconv.FormatBool(m.Repo.Private),
"CI_REPO_TRUSTED_NETWORK": strconv.FormatBool(m.Repo.Trusted.Network),
"CI_REPO_TRUSTED_VOLUMES": strconv.FormatBool(m.Repo.Trusted.Volumes),
"CI_REPO_TRUSTED_SECURITY": strconv.FormatBool(m.Repo.Trusted.Security),
// Deprecated remove in 4.x
"CI_REPO_TRUSTED": strconv.FormatBool(m.Repo.Trusted.Security && m.Repo.Trusted.Network && m.Repo.Trusted.Volumes),
"CI_COMMIT_SHA": m.Curr.Commit.Sha,
"CI_COMMIT_REF": m.Curr.Commit.Ref,
"CI_COMMIT_REFSPEC": m.Curr.Commit.Refspec,
"CI_COMMIT_BRANCH": m.Curr.Commit.Branch,
"CI_COMMIT_SOURCE_BRANCH": sourceBranch,
"CI_COMMIT_TARGET_BRANCH": targetBranch,
"CI_COMMIT_MESSAGE": m.Curr.Commit.Message,
"CI_COMMIT_AUTHOR": m.Curr.Commit.Author.Name,
"CI_COMMIT_AUTHOR_EMAIL": m.Curr.Commit.Author.Email,
"CI_COMMIT_AUTHOR_AVATAR": m.Curr.Commit.Author.Avatar,
"CI_COMMIT_TAG": "", // will be set if event is tag
"CI_COMMIT_PULL_REQUEST": "", // will be set if event is pull_request or pull_request_closed
"CI_COMMIT_PULL_REQUEST_LABELS": "", // will be set if event is pull_request or pull_request_closed
"CI_PIPELINE_NUMBER": strconv.FormatInt(m.Curr.Number, 10),
"CI_PIPELINE_PARENT": strconv.FormatInt(m.Curr.Parent, 10),
"CI_PIPELINE_EVENT": m.Curr.Event,
"CI_PIPELINE_URL": m.getPipelineWebURL(m.Curr, 0),
"CI_PIPELINE_FORGE_URL": m.Curr.ForgeURL,
"CI_PIPELINE_DEPLOY_TARGET": m.Curr.DeployTo,
"CI_PIPELINE_DEPLOY_TASK": m.Curr.DeployTask,
"CI_PIPELINE_CREATED": strconv.FormatInt(m.Curr.Created, 10),
"CI_PIPELINE_STARTED": strconv.FormatInt(m.Curr.Started, 10),
"CI_WORKFLOW_NAME": m.Workflow.Name,
"CI_WORKFLOW_NUMBER": strconv.Itoa(m.Workflow.Number),
"CI_STEP_NAME": m.Step.Name,
"CI_STEP_NUMBER": strconv.Itoa(m.Step.Number),
"CI_STEP_STARTED": "", // will be set by agent
"CI_STEP_URL": m.getPipelineWebURL(m.Curr, m.Step.Number),
"CI_PREV_COMMIT_SHA": m.Prev.Commit.Sha,
"CI_PREV_COMMIT_REF": m.Prev.Commit.Ref,
"CI_PREV_COMMIT_REFSPEC": m.Prev.Commit.Refspec,
"CI_PREV_COMMIT_BRANCH": m.Prev.Commit.Branch,
"CI_PREV_COMMIT_URL": m.Prev.ForgeURL,
"CI_PREV_COMMIT_MESSAGE": m.Prev.Commit.Message,
"CI_PREV_COMMIT_AUTHOR": m.Prev.Commit.Author.Name,
"CI_PREV_COMMIT_AUTHOR_EMAIL": m.Prev.Commit.Author.Email,
"CI_PREV_COMMIT_AUTHOR_AVATAR": m.Prev.Commit.Author.Avatar,
"CI_PREV_COMMIT_SOURCE_BRANCH": prevSourceBranch,
"CI_PREV_COMMIT_TARGET_BRANCH": prevTargetBranch,
"CI_PREV_PIPELINE_NUMBER": strconv.FormatInt(m.Prev.Number, 10),
"CI_PREV_PIPELINE_PARENT": strconv.FormatInt(m.Prev.Parent, 10),
"CI_PREV_PIPELINE_EVENT": m.Prev.Event,
"CI_PREV_PIPELINE_URL": m.getPipelineWebURL(m.Prev, 0),
"CI_PREV_PIPELINE_FORGE_URL": m.Prev.ForgeURL,
"CI_PREV_PIPELINE_DEPLOY_TARGET": m.Prev.DeployTo,
"CI_PREV_PIPELINE_DEPLOY_TASK": m.Prev.DeployTask,
"CI_PREV_PIPELINE_STATUS": m.Prev.Status,
"CI_PREV_PIPELINE_CREATED": strconv.FormatInt(m.Prev.Created, 10),
"CI_PREV_PIPELINE_STARTED": strconv.FormatInt(m.Prev.Started, 10),
"CI_PREV_PIPELINE_FINISHED": strconv.FormatInt(m.Prev.Finished, 10),
"CI_SYSTEM_NAME": m.Sys.Name,
"CI_SYSTEM_URL": m.Sys.URL,
"CI_SYSTEM_HOST": m.Sys.Host,
"CI_SYSTEM_PLATFORM": m.Sys.Platform, // will be set by pipeline platform option or by agent
"CI_SYSTEM_VERSION": m.Sys.Version,
"CI_FORGE_TYPE": m.Forge.Type,
"CI_FORGE_URL": m.Forge.URL,
func setNonEmptyEnvVar(env map[string]string, key, value string) {
if len(value) > 0 {
env[key] = value
} else {
log.Trace().Str("variable", key).Msg("env var is filtered as it's empty")
}
if m.Curr.Event == EventTag || m.Curr.Event == EventRelease || strings.HasPrefix(m.Curr.Commit.Ref, "refs/tags/") {
params["CI_COMMIT_TAG"] = strings.TrimPrefix(m.Curr.Commit.Ref, "refs/tags/")
}
if m.Curr.Event == EventRelease {
params["CI_COMMIT_PRERELEASE"] = strconv.FormatBool(m.Curr.Commit.IsPrerelease)
}
if m.Curr.Event == EventPull || m.Curr.Event == EventPullClosed {
params["CI_COMMIT_PULL_REQUEST"] = pullRegexp.FindString(m.Curr.Commit.Ref)
params["CI_COMMIT_PULL_REQUEST_LABELS"] = strings.Join(m.Curr.Commit.PullRequestLabels, ",")
}
// Only export changed files if maxChangedFiles is not exceeded
if len(m.Curr.Commit.ChangedFiles) == 0 {
params["CI_PIPELINE_FILES"] = "[]"
} else if len(m.Curr.Commit.ChangedFiles) <= maxChangedFiles {
// we have to use json, as other separators like ;, or space are valid filename chars
changedFiles, err := json.Marshal(m.Curr.Commit.ChangedFiles)
if err != nil {
log.Error().Err(err).Msg("marshal changed files")
}
params["CI_PIPELINE_FILES"] = string(changedFiles)
}
return params
}
func (m *Metadata) getPipelineWebURL(pipeline Pipeline, stepNumber int) string {
if stepNumber == 0 {
return fmt.Sprintf("%s/repos/%d/pipeline/%d", m.Sys.URL, m.Repo.ID, pipeline.Number)
}
return fmt.Sprintf("%s/repos/%d/pipeline/%d/%d", m.Sys.URL, m.Repo.ID, pipeline.Number, stepNumber)
}

View file

@ -314,8 +314,8 @@ func TestCompilerCompile(t *testing.T) {
for _, st := range backConf.Stages {
for _, s := range st.Steps {
s.UUID = ""
assert.Truef(t, s.Environment["VERBOSE"] == "true", "expect to get value of global set environment")
assert.Truef(t, len(s.Environment) > 50, "expect to have a lot of build in variables")
assert.Truef(t, s.Environment["VERBOSE"] == "true", "expected to get value of global set environment")
assert.Truef(t, len(s.Environment) > 10, "expected to have a lot of built-in variables")
s.Environment = nil
}
}

View file

@ -15,7 +15,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.35.2
// protoc-gen-go v1.36.0
// protoc v4.24.4
// source: woodpecker.proto
@ -36,16 +36,15 @@ const (
)
type StepState struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
StepUuid string `protobuf:"bytes,1,opt,name=step_uuid,json=stepUuid,proto3" json:"step_uuid,omitempty"`
Started int64 `protobuf:"varint,2,opt,name=started,proto3" json:"started,omitempty"`
Finished int64 `protobuf:"varint,3,opt,name=finished,proto3" json:"finished,omitempty"`
Exited bool `protobuf:"varint,4,opt,name=exited,proto3" json:"exited,omitempty"`
ExitCode int32 `protobuf:"varint,5,opt,name=exit_code,json=exitCode,proto3" json:"exit_code,omitempty"`
Error string `protobuf:"bytes,6,opt,name=error,proto3" json:"error,omitempty"`
unknownFields protoimpl.UnknownFields
StepUuid string `protobuf:"bytes,1,opt,name=step_uuid,json=stepUuid,proto3" json:"step_uuid,omitempty"`
Started int64 `protobuf:"varint,2,opt,name=started,proto3" json:"started,omitempty"`
Finished int64 `protobuf:"varint,3,opt,name=finished,proto3" json:"finished,omitempty"`
Exited bool `protobuf:"varint,4,opt,name=exited,proto3" json:"exited,omitempty"`
ExitCode int32 `protobuf:"varint,5,opt,name=exit_code,json=exitCode,proto3" json:"exit_code,omitempty"`
Error string `protobuf:"bytes,6,opt,name=error,proto3" json:"error,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *StepState) Reset() {
@ -121,13 +120,12 @@ func (x *StepState) GetError() string {
}
type WorkflowState struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Started int64 `protobuf:"varint,4,opt,name=started,proto3" json:"started,omitempty"`
Finished int64 `protobuf:"varint,5,opt,name=finished,proto3" json:"finished,omitempty"`
Error string `protobuf:"bytes,6,opt,name=error,proto3" json:"error,omitempty"`
unknownFields protoimpl.UnknownFields
Started int64 `protobuf:"varint,4,opt,name=started,proto3" json:"started,omitempty"`
Finished int64 `protobuf:"varint,5,opt,name=finished,proto3" json:"finished,omitempty"`
Error string `protobuf:"bytes,6,opt,name=error,proto3" json:"error,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *WorkflowState) Reset() {
@ -182,15 +180,14 @@ func (x *WorkflowState) GetError() string {
}
type LogEntry struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
StepUuid string `protobuf:"bytes,1,opt,name=step_uuid,json=stepUuid,proto3" json:"step_uuid,omitempty"`
Time int64 `protobuf:"varint,2,opt,name=time,proto3" json:"time,omitempty"`
Line int32 `protobuf:"varint,3,opt,name=line,proto3" json:"line,omitempty"`
Type int32 `protobuf:"varint,4,opt,name=type,proto3" json:"type,omitempty"` // 0 = stdout, 1 = stderr, 2 = exit-code, 3 = metadata, 4 = progress
Data []byte `protobuf:"bytes,5,opt,name=data,proto3" json:"data,omitempty"`
unknownFields protoimpl.UnknownFields
StepUuid string `protobuf:"bytes,1,opt,name=step_uuid,json=stepUuid,proto3" json:"step_uuid,omitempty"`
Time int64 `protobuf:"varint,2,opt,name=time,proto3" json:"time,omitempty"`
Line int32 `protobuf:"varint,3,opt,name=line,proto3" json:"line,omitempty"`
Type int32 `protobuf:"varint,4,opt,name=type,proto3" json:"type,omitempty"` // 0 = stdout, 1 = stderr, 2 = exit-code, 3 = metadata, 4 = progress
Data []byte `protobuf:"bytes,5,opt,name=data,proto3" json:"data,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *LogEntry) Reset() {
@ -259,11 +256,10 @@ func (x *LogEntry) GetData() []byte {
}
type Filter struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Labels map[string]string `protobuf:"bytes,1,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
unknownFields protoimpl.UnknownFields
Labels map[string]string `protobuf:"bytes,1,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
sizeCache protoimpl.SizeCache
}
func (x *Filter) Reset() {
@ -304,13 +300,12 @@ func (x *Filter) GetLabels() map[string]string {
}
type Workflow struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Timeout int64 `protobuf:"varint,2,opt,name=timeout,proto3" json:"timeout,omitempty"`
Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"`
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Timeout int64 `protobuf:"varint,2,opt,name=timeout,proto3" json:"timeout,omitempty"`
Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *Workflow) Reset() {
@ -365,11 +360,10 @@ func (x *Workflow) GetPayload() []byte {
}
type NextRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Filter *Filter `protobuf:"bytes,1,opt,name=filter,proto3" json:"filter,omitempty"`
unknownFields protoimpl.UnknownFields
Filter *Filter `protobuf:"bytes,1,opt,name=filter,proto3" json:"filter,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *NextRequest) Reset() {
@ -410,12 +404,11 @@ func (x *NextRequest) GetFilter() *Filter {
}
type InitRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
State *WorkflowState `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"`
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
State *WorkflowState `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *InitRequest) Reset() {
@ -463,11 +456,10 @@ func (x *InitRequest) GetState() *WorkflowState {
}
type WaitRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *WaitRequest) Reset() {
@ -508,12 +500,11 @@ func (x *WaitRequest) GetId() string {
}
type DoneRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
State *WorkflowState `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"`
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
State *WorkflowState `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *DoneRequest) Reset() {
@ -561,11 +552,10 @@ func (x *DoneRequest) GetState() *WorkflowState {
}
type ExtendRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *ExtendRequest) Reset() {
@ -606,12 +596,11 @@ func (x *ExtendRequest) GetId() string {
}
type UpdateRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
State *StepState `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"`
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
State *StepState `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *UpdateRequest) Reset() {
@ -659,11 +648,10 @@ func (x *UpdateRequest) GetState() *StepState {
}
type LogRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
LogEntries []*LogEntry `protobuf:"bytes,1,rep,name=logEntries,proto3" json:"logEntries,omitempty"`
unknownFields protoimpl.UnknownFields
LogEntries []*LogEntry `protobuf:"bytes,1,rep,name=logEntries,proto3" json:"logEntries,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *LogRequest) Reset() {
@ -704,9 +692,9 @@ func (x *LogRequest) GetLogEntries() []*LogEntry {
}
type Empty struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Empty) Reset() {
@ -740,11 +728,10 @@ func (*Empty) Descriptor() ([]byte, []int) {
}
type ReportHealthRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
unknownFields protoimpl.UnknownFields
Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *ReportHealthRequest) Reset() {
@ -785,15 +772,14 @@ func (x *ReportHealthRequest) GetStatus() string {
}
type AgentInfo struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Platform string `protobuf:"bytes,1,opt,name=platform,proto3" json:"platform,omitempty"`
Capacity int32 `protobuf:"varint,2,opt,name=capacity,proto3" json:"capacity,omitempty"`
Backend string `protobuf:"bytes,3,opt,name=backend,proto3" json:"backend,omitempty"`
Version string `protobuf:"bytes,4,opt,name=version,proto3" json:"version,omitempty"`
CustomLabels map[string]string `protobuf:"bytes,5,rep,name=customLabels,proto3" json:"customLabels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
unknownFields protoimpl.UnknownFields
Platform string `protobuf:"bytes,1,opt,name=platform,proto3" json:"platform,omitempty"`
Capacity int32 `protobuf:"varint,2,opt,name=capacity,proto3" json:"capacity,omitempty"`
Backend string `protobuf:"bytes,3,opt,name=backend,proto3" json:"backend,omitempty"`
Version string `protobuf:"bytes,4,opt,name=version,proto3" json:"version,omitempty"`
CustomLabels map[string]string `protobuf:"bytes,5,rep,name=customLabels,proto3" json:"customLabels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
sizeCache protoimpl.SizeCache
}
func (x *AgentInfo) Reset() {
@ -862,11 +848,10 @@ func (x *AgentInfo) GetCustomLabels() map[string]string {
}
type RegisterAgentRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Info *AgentInfo `protobuf:"bytes,1,opt,name=info,proto3" json:"info,omitempty"`
unknownFields protoimpl.UnknownFields
Info *AgentInfo `protobuf:"bytes,1,opt,name=info,proto3" json:"info,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *RegisterAgentRequest) Reset() {
@ -907,12 +892,11 @@ func (x *RegisterAgentRequest) GetInfo() *AgentInfo {
}
type VersionResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
GrpcVersion int32 `protobuf:"varint,1,opt,name=grpc_version,json=grpcVersion,proto3" json:"grpc_version,omitempty"`
ServerVersion string `protobuf:"bytes,2,opt,name=server_version,json=serverVersion,proto3" json:"server_version,omitempty"`
unknownFields protoimpl.UnknownFields
GrpcVersion int32 `protobuf:"varint,1,opt,name=grpc_version,json=grpcVersion,proto3" json:"grpc_version,omitempty"`
ServerVersion string `protobuf:"bytes,2,opt,name=server_version,json=serverVersion,proto3" json:"server_version,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *VersionResponse) Reset() {
@ -960,11 +944,10 @@ func (x *VersionResponse) GetServerVersion() string {
}
type NextResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Workflow *Workflow `protobuf:"bytes,1,opt,name=workflow,proto3" json:"workflow,omitempty"`
unknownFields protoimpl.UnknownFields
Workflow *Workflow `protobuf:"bytes,1,opt,name=workflow,proto3" json:"workflow,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *NextResponse) Reset() {
@ -1005,11 +988,10 @@ func (x *NextResponse) GetWorkflow() *Workflow {
}
type RegisterAgentResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
AgentId int64 `protobuf:"varint,1,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"`
unknownFields protoimpl.UnknownFields
AgentId int64 `protobuf:"varint,1,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *RegisterAgentResponse) Reset() {
@ -1050,12 +1032,11 @@ func (x *RegisterAgentResponse) GetAgentId() int64 {
}
type AuthRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
AgentToken string `protobuf:"bytes,1,opt,name=agent_token,json=agentToken,proto3" json:"agent_token,omitempty"`
AgentId int64 `protobuf:"varint,2,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"`
unknownFields protoimpl.UnknownFields
AgentToken string `protobuf:"bytes,1,opt,name=agent_token,json=agentToken,proto3" json:"agent_token,omitempty"`
AgentId int64 `protobuf:"varint,2,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *AuthRequest) Reset() {
@ -1103,13 +1084,12 @@ func (x *AuthRequest) GetAgentId() int64 {
}
type AuthResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
AgentId int64 `protobuf:"varint,2,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"`
AccessToken string `protobuf:"bytes,3,opt,name=access_token,json=accessToken,proto3" json:"access_token,omitempty"`
unknownFields protoimpl.UnknownFields
Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
AgentId int64 `protobuf:"varint,2,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"`
AccessToken string `protobuf:"bytes,3,opt,name=access_token,json=accessToken,proto3" json:"access_token,omitempty"`
sizeCache protoimpl.SizeCache
}
func (x *AuthResponse) Reset() {

View file

@ -72,7 +72,7 @@ func GetBadge(c *gin.Context) {
branch = repo.Branch
}
pipeline, err := _store.GetPipelineLast(repo, branch)
pipeline, err := _store.GetPipelineBadge(repo, branch)
if err != nil {
if !errors.Is(err, types.RecordNotExist) {
log.Warn().Err(err).Msg("could not get last pipeline for badge")

View file

@ -132,7 +132,7 @@ func GetPipelines(c *gin.Context) {
if events := c.Query("event"); events != "" {
eventList := strings.Split(events, ",")
wel := make(model.WebhookEventList, 0, len(eventList))
for _, event := range events {
for _, event := range eventList {
we := model.WebhookEvent(event)
if err := we.Validate(); err != nil {
_ = c.AbortWithError(http.StatusBadRequest, err)

View file

@ -96,6 +96,24 @@ func TestGetPipelines(t *testing.T) {
assert.Equal(t, http.StatusOK, c.Writer.Status())
})
t.Run("should filter pipelines by events", func(t *testing.T) {
pipelines := []*model.Pipeline{fakePipeline}
mockStore := store_mocks.NewStore(t)
mockStore.On("GetPipelineList", mock.Anything, mock.Anything, mock.Anything).Return(pipelines, nil)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set("store", mockStore)
c.Request, _ = http.NewRequest(http.MethodGet, "/?event=push,pull_request", nil)
GetPipelines(c)
mockStore.AssertCalled(t, "GetPipelineList", mock.Anything, mock.Anything, &model.PipelineFilter{
Events: model.WebhookEventList{model.EventPush, model.EventPull},
})
assert.Equal(t, http.StatusOK, c.Writer.Status())
})
}
func TestDeletePipeline(t *testing.T) {

View file

@ -258,12 +258,9 @@ func PatchRepo(c *gin.Context) {
c.String(http.StatusBadRequest, "Invalid require-approval setting")
return
}
} else if in.IsGated != nil { // TODO: remove isGated in next major release
if *in.IsGated {
repo.RequireApproval = model.RequireApprovalAllEvents
} else {
repo.RequireApproval = model.RequireApprovalForks
}
} else if in.IsGated != nil {
c.String(http.StatusBadRequest, "'gated' option has been removed, use 'require-approval' in >= 3.0")
return
}
if in.Timeout != nil {
repo.Timeout = *in.Timeout

View file

@ -139,8 +139,8 @@ func (g *RPC) Repo(_ context.Context, u *model.User, remoteID model.ForgeRemoteI
return nil, err
}
var resp *modelRepo
err = json.Unmarshal(jsonResp, resp)
var resp modelRepo
err = json.Unmarshal(jsonResp, &resp)
if err != nil {
return nil, err
}

View file

@ -54,8 +54,8 @@ func (s *RPCServer) URL(_ []byte, resp *string) error {
}
func (s *RPCServer) Teams(args []byte, resp *[]byte) error {
var a *modelUser
err := json.Unmarshal(args, a)
var a modelUser
err := json.Unmarshal(args, &a)
if err != nil {
return err
}
@ -82,8 +82,8 @@ func (s *RPCServer) Repo(args []byte, resp *[]byte) error {
}
func (s *RPCServer) Repos(args []byte, resp *[]byte) error {
var a *modelUser
err := json.Unmarshal(args, a)
var a modelUser
err := json.Unmarshal(args, &a)
if err != nil {
return err
}
@ -261,12 +261,12 @@ func (s *RPCServer) Hook(args []byte, resp *[]byte) error {
}
func (s *RPCServer) Login(args []byte, resp *[]byte) error {
var a *types.OAuthRequest
err := json.Unmarshal(args, a)
var a types.OAuthRequest
err := json.Unmarshal(args, &a)
if err != nil {
return err
}
user, red, err := s.Impl.Login(mkCtx(), a)
user, red, err := s.Impl.Login(mkCtx(), &a)
if err != nil {
return err
}

View file

@ -290,11 +290,11 @@ func (c *config) Dir(ctx context.Context, u *model.User, r *model.Repo, p *model
}
// Status creates a pipeline status for the Bitbucket commit.
func (c *config) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, _ *model.Workflow) error {
func (c *config) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, workflow *model.Workflow) error {
status := internal.PipelineStatus{
State: convertStatus(pipeline.Status),
Desc: common.GetPipelineStatusDescription(pipeline.Status),
Key: "Woodpecker",
Key: common.GetPipelineStatusContext(repo, pipeline, workflow),
URL: common.GetPipelineStatusURL(repo, pipeline, nil),
}
return c.newClient(ctx, user).CreateStatus(repo.Owner, repo.Name, pipeline.Commit, &status)

View file

@ -21,7 +21,7 @@ import (
"net/http"
"strings"
"github.com/xanzy/go-gitlab"
"gitlab.com/gitlab-org/api/client-go"
"go.woodpecker-ci.org/woodpecker/v2/server/model"
"go.woodpecker-ci.org/woodpecker/v2/shared/utils"

View file

@ -28,7 +28,7 @@ import (
"time"
"github.com/rs/zerolog/log"
"github.com/xanzy/go-gitlab"
"gitlab.com/gitlab-org/api/client-go"
"golang.org/x/oauth2"
"go.woodpecker-ci.org/woodpecker/v2/server"

View file

@ -19,7 +19,7 @@ import (
"crypto/tls"
"net/http"
"github.com/xanzy/go-gitlab"
"gitlab.com/gitlab-org/api/client-go"
)
const (

View file

@ -15,7 +15,7 @@
package gitlab
import (
"github.com/xanzy/go-gitlab"
"gitlab.com/gitlab-org/api/client-go"
"go.woodpecker-ci.org/woodpecker/v2/server/model"
)

View file

@ -282,7 +282,7 @@ func (_m *Forge) Login(ctx context.Context, r *types.OAuthRequest) (*model.User,
return r0, r1, r2
}
// Name provides a mock function with given fields:
// Name provides a mock function with no fields
func (_m *Forge) Name() string {
ret := _m.Called()
@ -528,7 +528,7 @@ func (_m *Forge) Teams(ctx context.Context, u *model.User) ([]*model.Team, error
return r0, r1
}
// URL provides a mock function with given fields:
// URL provides a mock function with no fields
func (_m *Forge) URL() string {
ret := _m.Called()

View file

@ -31,23 +31,25 @@ func needsApproval(repo *model.Repo, pipeline *model.Pipeline) bool {
return false
}
switch repo.RequireApproval {
// repository allows all events without approval
if repo.RequireApproval == model.RequireApprovalNone {
case model.RequireApprovalNone:
return false
}
// repository requires approval for pull requests from forks
if pipeline.Event == model.EventPull && pipeline.FromFork {
return true
}
case model.RequireApprovalForks:
if pipeline.Event == model.EventPull && pipeline.FromFork {
return true
}
// repository requires approval for pull requests
if pipeline.Event == model.EventPull && repo.RequireApproval == model.RequireApprovalPullRequests {
return true
}
case model.RequireApprovalPullRequests:
if pipeline.Event == model.EventPull {
return true
}
// repository requires approval for all events
if repo.RequireApproval == model.RequireApprovalAllEvents {
// repository requires approval for all events
case model.RequireApprovalAllEvents:
return true
}

View file

@ -43,20 +43,15 @@ func TestMetadataFromStruct(t *testing.T) {
name: "Test with empty info",
expectedMetadata: metadata.Metadata{Sys: metadata.System{Name: "woodpecker"}},
expectedEnviron: map[string]string{
"CI": "woodpecker",
"CI_COMMIT_AUTHOR": "", "CI_COMMIT_AUTHOR_AVATAR": "", "CI_COMMIT_AUTHOR_EMAIL": "", "CI_COMMIT_BRANCH": "",
"CI_COMMIT_MESSAGE": "", "CI_COMMIT_PULL_REQUEST": "", "CI_COMMIT_PULL_REQUEST_LABELS": "", "CI_COMMIT_REF": "", "CI_COMMIT_REFSPEC": "", "CI_COMMIT_SHA": "", "CI_COMMIT_SOURCE_BRANCH": "",
"CI_COMMIT_TAG": "", "CI_COMMIT_TARGET_BRANCH": "", "CI_FORGE_TYPE": "", "CI_FORGE_URL": "",
"CI_PIPELINE_CREATED": "0", "CI_PIPELINE_DEPLOY_TARGET": "", "CI_PIPELINE_DEPLOY_TASK": "", "CI_PIPELINE_EVENT": "", "CI_PIPELINE_FILES": "[]", "CI_PIPELINE_NUMBER": "0",
"CI_PIPELINE_PARENT": "0", "CI_PIPELINE_STARTED": "0", "CI_PIPELINE_URL": "/repos/0/pipeline/0", "CI_PIPELINE_FORGE_URL": "",
"CI_PREV_COMMIT_AUTHOR": "", "CI_PREV_COMMIT_AUTHOR_AVATAR": "", "CI_PREV_COMMIT_AUTHOR_EMAIL": "", "CI_PREV_COMMIT_BRANCH": "", "CI_PREV_COMMIT_SOURCE_BRANCH": "", "CI_PREV_COMMIT_TARGET_BRANCH": "",
"CI_PREV_COMMIT_MESSAGE": "", "CI_PREV_COMMIT_REF": "", "CI_PREV_COMMIT_REFSPEC": "", "CI_PREV_COMMIT_SHA": "", "CI_PREV_COMMIT_URL": "", "CI_PREV_PIPELINE_CREATED": "0",
"CI_PREV_PIPELINE_DEPLOY_TARGET": "", "CI_PREV_PIPELINE_DEPLOY_TASK": "", "CI_PREV_PIPELINE_EVENT": "", "CI_PREV_PIPELINE_FINISHED": "0", "CI_PREV_PIPELINE_NUMBER": "0", "CI_PREV_PIPELINE_PARENT": "0",
"CI_PREV_PIPELINE_STARTED": "0", "CI_PREV_PIPELINE_STATUS": "", "CI_PREV_PIPELINE_URL": "/repos/0/pipeline/0", "CI_PREV_PIPELINE_FORGE_URL": "", "CI_REPO": "", "CI_REPO_CLONE_URL": "", "CI_REPO_CLONE_SSH_URL": "", "CI_REPO_DEFAULT_BRANCH": "", "CI_REPO_REMOTE_ID": "",
"CI_REPO_NAME": "", "CI_REPO_OWNER": "", "CI_REPO_PRIVATE": "false", "CI_REPO_SCM": "", "CI_REPO_TRUSTED": "false", "CI_REPO_TRUSTED_NETWORK": "false",
"CI_REPO_TRUSTED_VOLUMES": "false", "CI_REPO_TRUSTED_SECURITY": "false", "CI_REPO_URL": "",
"CI_STEP_NAME": "", "CI_STEP_NUMBER": "0", "CI_STEP_STARTED": "", "CI_STEP_URL": "/repos/0/pipeline/0", "CI_SYSTEM_HOST": "", "CI_SYSTEM_NAME": "woodpecker",
"CI_SYSTEM_PLATFORM": "", "CI_SYSTEM_URL": "", "CI_SYSTEM_VERSION": "", "CI_WORKFLOW_NAME": "", "CI_WORKFLOW_NUMBER": "0",
"CI": "woodpecker",
"CI_PIPELINE_CREATED": "0", "CI_PIPELINE_FILES": "[]", "CI_PIPELINE_NUMBER": "0",
"CI_PIPELINE_PARENT": "0", "CI_PIPELINE_STARTED": "0", "CI_PIPELINE_URL": "/repos/0/pipeline/0",
"CI_PREV_PIPELINE_CREATED": "0",
"CI_PREV_PIPELINE_FINISHED": "0", "CI_PREV_PIPELINE_NUMBER": "0", "CI_PREV_PIPELINE_PARENT": "0",
"CI_PREV_PIPELINE_STARTED": "0", "CI_PREV_PIPELINE_URL": "/repos/0/pipeline/0",
"CI_REPO_PRIVATE": "false", "CI_REPO_TRUSTED": "false", "CI_REPO_TRUSTED_NETWORK": "false", "CI_REPO_TRUSTED_SECURITY": "false", "CI_REPO_TRUSTED_VOLUMES": "false",
"CI_STEP_NUMBER": "0", "CI_STEP_URL": "/repos/0/pipeline/0", "CI_SYSTEM_NAME": "woodpecker",
"CI_WORKFLOW_NUMBER": "0",
},
},
{
@ -79,22 +74,17 @@ func TestMetadataFromStruct(t *testing.T) {
Workflow: metadata.Workflow{Name: "hello"},
},
expectedEnviron: map[string]string{
"CI": "woodpecker",
"CI_COMMIT_AUTHOR": "", "CI_COMMIT_AUTHOR_AVATAR": "", "CI_COMMIT_AUTHOR_EMAIL": "", "CI_COMMIT_BRANCH": "",
"CI_COMMIT_MESSAGE": "", "CI_COMMIT_PULL_REQUEST": "", "CI_COMMIT_PULL_REQUEST_LABELS": "", "CI_COMMIT_REF": "", "CI_COMMIT_REFSPEC": "", "CI_COMMIT_SHA": "", "CI_COMMIT_SOURCE_BRANCH": "",
"CI_COMMIT_TAG": "", "CI_COMMIT_TARGET_BRANCH": "", "CI_FORGE_TYPE": "gitea", "CI_FORGE_URL": "https://gitea.com",
"CI_PIPELINE_CREATED": "0", "CI_PIPELINE_DEPLOY_TARGET": "", "CI_PIPELINE_DEPLOY_TASK": "", "CI_PIPELINE_EVENT": "", "CI_PIPELINE_FILES": `["test.go","markdown file.md"]`,
"CI_PIPELINE_NUMBER": "3", "CI_PIPELINE_PARENT": "0", "CI_PIPELINE_STARTED": "0", "CI_PIPELINE_URL": "https://example.com/repos/0/pipeline/3", "CI_PIPELINE_FORGE_URL": "",
"CI_PREV_COMMIT_AUTHOR": "", "CI_PREV_COMMIT_AUTHOR_AVATAR": "", "CI_PREV_COMMIT_AUTHOR_EMAIL": "", "CI_PREV_COMMIT_BRANCH": "", "CI_PREV_COMMIT_SOURCE_BRANCH": "", "CI_PREV_COMMIT_TARGET_BRANCH": "",
"CI_PREV_COMMIT_MESSAGE": "", "CI_PREV_COMMIT_REF": "", "CI_PREV_COMMIT_REFSPEC": "", "CI_PREV_COMMIT_SHA": "", "CI_PREV_COMMIT_URL": "", "CI_PREV_PIPELINE_CREATED": "0",
"CI_PREV_PIPELINE_DEPLOY_TARGET": "", "CI_PREV_PIPELINE_DEPLOY_TASK": "", "CI_PREV_PIPELINE_EVENT": "", "CI_PREV_PIPELINE_FINISHED": "0", "CI_PREV_PIPELINE_NUMBER": "2", "CI_PREV_PIPELINE_PARENT": "0",
"CI_PREV_PIPELINE_STARTED": "0", "CI_PREV_PIPELINE_STATUS": "", "CI_PREV_PIPELINE_URL": "https://example.com/repos/0/pipeline/2", "CI_PREV_PIPELINE_FORGE_URL": "", "CI_REPO": "testUser/testRepo", "CI_REPO_CLONE_URL": "https://gitea.com/testUser/testRepo.git", "CI_REPO_CLONE_SSH_URL": "git@gitea.com:testUser/testRepo.git",
"CI_REPO_DEFAULT_BRANCH": "main", "CI_REPO_NAME": "testRepo", "CI_REPO_OWNER": "testUser", "CI_REPO_PRIVATE": "true", "CI_REPO_REMOTE_ID": "",
"CI_REPO_SCM": "git", "CI_REPO_TRUSTED": "false", "CI_REPO_TRUSTED_NETWORK": "false",
"CI_REPO_TRUSTED_VOLUMES": "false", "CI_REPO_TRUSTED_SECURITY": "false",
"CI_REPO_URL": "https://gitea.com/testUser/testRepo",
"CI_STEP_NAME": "", "CI_STEP_NUMBER": "0", "CI_STEP_STARTED": "", "CI_STEP_URL": "https://example.com/repos/0/pipeline/3", "CI_SYSTEM_HOST": "example.com",
"CI_SYSTEM_NAME": "woodpecker", "CI_SYSTEM_PLATFORM": "", "CI_SYSTEM_URL": "https://example.com", "CI_SYSTEM_VERSION": "", "CI_WORKFLOW_NAME": "hello", "CI_WORKFLOW_NUMBER": "0",
"CI": "woodpecker",
"CI_FORGE_TYPE": "gitea", "CI_FORGE_URL": "https://gitea.com",
"CI_PIPELINE_CREATED": "0", "CI_PIPELINE_FILES": `["test.go","markdown file.md"]`,
"CI_PIPELINE_NUMBER": "3", "CI_PIPELINE_PARENT": "0", "CI_PIPELINE_STARTED": "0", "CI_PIPELINE_URL": "https://example.com/repos/0/pipeline/3",
"CI_PREV_PIPELINE_CREATED": "0",
"CI_PREV_PIPELINE_FINISHED": "0", "CI_PREV_PIPELINE_NUMBER": "2", "CI_PREV_PIPELINE_PARENT": "0",
"CI_PREV_PIPELINE_STARTED": "0", "CI_PREV_PIPELINE_URL": "https://example.com/repos/0/pipeline/2", "CI_REPO": "testUser/testRepo", "CI_REPO_CLONE_URL": "https://gitea.com/testUser/testRepo.git", "CI_REPO_CLONE_SSH_URL": "git@gitea.com:testUser/testRepo.git",
"CI_REPO_DEFAULT_BRANCH": "main", "CI_REPO_NAME": "testRepo", "CI_REPO_OWNER": "testUser", "CI_REPO_PRIVATE": "true",
"CI_REPO_SCM": "git", "CI_REPO_TRUSTED": "false", "CI_REPO_TRUSTED_NETWORK": "false", "CI_REPO_TRUSTED_SECURITY": "false", "CI_REPO_TRUSTED_VOLUMES": "false",
"CI_REPO_URL": "https://gitea.com/testUser/testRepo", "CI_STEP_NUMBER": "0", "CI_STEP_URL": "https://example.com/repos/0/pipeline/3", "CI_SYSTEM_HOST": "example.com",
"CI_SYSTEM_NAME": "woodpecker", "CI_SYSTEM_URL": "https://example.com", "CI_WORKFLOW_NAME": "hello", "CI_WORKFLOW_NUMBER": "0",
},
},
}

View file

@ -150,7 +150,7 @@ func (_m *Queue) KickAgentWorkers(agentID int64) {
_m.Called(agentID)
}
// Pause provides a mock function with given fields:
// Pause provides a mock function with no fields
func (_m *Queue) Pause() {
_m.Called()
}
@ -221,7 +221,7 @@ func (_m *Queue) PushAtOnce(c context.Context, tasks []*model.Task) error {
return r0
}
// Resume provides a mock function with given fields:
// Resume provides a mock function with no fields
func (_m *Queue) Resume() {
_m.Called()
}

View file

@ -140,9 +140,9 @@ func (f *forgeFetcherContext) checkPipelineFile(c context.Context, config string
func (f *forgeFetcherContext) getFirstAvailableConfig(c context.Context, configs []string) ([]*types.FileMeta, error) {
var forgeErr []error
for _, fileOrFolder := range configs {
log.Trace().Msgf("fetching %s from forge", fileOrFolder)
if strings.HasSuffix(fileOrFolder, "/") {
// config is a folder
log.Trace().Msgf("fetching %s from forge", fileOrFolder)
files, err := f.forge.Dir(c, f.user, f.repo, f.pipeline, strings.TrimSuffix(fileOrFolder, "/"))
// if folder is not supported we will get a "Not implemented" error and continue
if err != nil {

View file

@ -48,7 +48,7 @@ func (_m *Manager) ConfigServiceFromRepo(repo *model.Repo) config.Service {
return r0
}
// EnvironmentService provides a mock function with given fields:
// EnvironmentService provides a mock function with no fields
func (_m *Manager) EnvironmentService() environment.Service {
ret := _m.Called()
@ -158,7 +158,7 @@ func (_m *Manager) ForgeFromUser(user *model.User) (forge.Forge, error) {
return r0, r1
}
// RegistryService provides a mock function with given fields:
// RegistryService provides a mock function with no fields
func (_m *Manager) RegistryService() registry.Service {
ret := _m.Called()
@ -198,7 +198,7 @@ func (_m *Manager) RegistryServiceFromRepo(repo *model.Repo) registry.Service {
return r0
}
// SecretService provides a mock function with given fields:
// SecretService provides a mock function with no fields
func (_m *Manager) SecretService() secret.Service {
ret := _m.Called()
@ -238,7 +238,7 @@ func (_m *Manager) SecretServiceFromRepo(repo *model.Repo) secret.Service {
return r0
}
// SignaturePublicKey provides a mock function with given fields:
// SignaturePublicKey provides a mock function with no fields
func (_m *Manager) SignaturePublicKey() crypto.PublicKey {
ret := _m.Called()

View file

@ -16,6 +16,7 @@ package datastore
import (
"github.com/rs/zerolog/log"
"xorm.io/xorm"
"go.woodpecker-ci.org/woodpecker/v2/server/model"
)
@ -46,6 +47,12 @@ func (s storage) LogAppend(_ *model.Step, logEntries []*model.LogEntry) error {
}
func (s storage) LogDelete(step *model.Step) error {
_, err := s.engine.Where("step_id = ?", step.ID).Delete(new(model.LogEntry))
sess := s.engine.NewSession()
defer sess.Close()
return logDelete(sess, step.ID)
}
func logDelete(sess *xorm.Session, stepID int64) error {
_, err := sess.Where("step_id = ?", stepID).Delete(new(model.LogEntry))
return err
}

View file

@ -26,10 +26,8 @@ var gatedToRequireApproval = xormigrate.Migration{
ID: "gated-to-require-approval",
MigrateSession: func(sess *xorm.Session) (err error) {
const (
RequireApprovalNone string = "none"
RequireApprovalForks string = "forks"
RequireApprovalPullRequests string = "pull_requests"
RequireApprovalAllEvents string = "all_events"
requireApprovalOldNotGated string = "old_not_gated"
requireApprovalAllEvents string = "all_events"
)
type repos struct {
@ -45,25 +43,17 @@ var gatedToRequireApproval = xormigrate.Migration{
// migrate gated repos
if _, err := sess.Exec(
builder.Update(builder.Eq{"require_approval": RequireApprovalAllEvents}).
builder.Update(builder.Eq{"require_approval": requireApprovalAllEvents}).
From("repos").
Where(builder.Eq{"gated": true})); err != nil {
return err
}
// migrate public repos to new default require approval
// migrate non gated repos to old_not_gated (no approval required)
if _, err := sess.Exec(
builder.Update(builder.Eq{"require_approval": RequireApprovalForks}).
builder.Update(builder.Eq{"require_approval": requireApprovalOldNotGated}).
From("repos").
Where(builder.Eq{"gated": false, "visibility": "public"})); err != nil {
return err
}
// migrate private repos to new default require approval
if _, err := sess.Exec(
builder.Update(builder.Eq{"require_approval": RequireApprovalNone}).
From("repos").
Where(builder.Eq{"gated": false}.And(builder.Neq{"visibility": "public"}))); err != nil {
Where(builder.Eq{"gated": false})); err != nil {
return err
}

View file

@ -0,0 +1,62 @@
// 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 migration
import (
"fmt"
"src.techknowlogick.com/xormigrate"
"xorm.io/builder"
"xorm.io/xorm"
)
var setNewDefaultsForRequireApproval = xormigrate.Migration{
ID: "set-new-defaults-for-require-approval",
MigrateSession: func(sess *xorm.Session) (err error) {
const (
RequireApprovalOldNotGated string = "old_not_gated"
RequireApprovalNone string = "none"
RequireApprovalForks string = "forks"
RequireApprovalAllEvents string = "all_events"
)
type repos struct {
RequireApproval string `xorm:"require_approval"`
Visibility string `xorm:"varchar(10) 'visibility'"`
}
if err := sess.Sync(new(repos)); err != nil {
return fmt.Errorf("sync new models failed: %w", err)
}
// migrate public repos to require approval for forks
if _, err := sess.Exec(
builder.Update(builder.Eq{"require_approval": RequireApprovalForks}).
From("repos").
Where(builder.Eq{"require_approval": RequireApprovalOldNotGated, "visibility": "public"})); err != nil {
return err
}
// migrate private repos to require no approval
if _, err := sess.Exec(
builder.Update(builder.Eq{"require_approval": RequireApprovalNone}).
From("repos").
Where(builder.Eq{"require_approval": RequireApprovalOldNotGated}.And(builder.Neq{"visibility": "public"}))); err != nil {
return err
}
return nil
},
}

View file

@ -50,6 +50,7 @@ var migrationTasks = []*xormigrate.Migration{
&gatedToRequireApproval,
&removeRepoNetrcOnlyTrusted,
&renameTokenFields,
&setNewDefaultsForRequireApproval,
}
var allBeans = []any{

View file

@ -35,6 +35,15 @@ func (s storage) GetPipelineNumber(repo *model.Repo, num int64) (*model.Pipeline
).Get(pipeline))
}
func (s storage) GetPipelineBadge(repo *model.Repo, branch string) (*model.Pipeline, error) {
pipeline := new(model.Pipeline)
return pipeline, wrapGet(s.engine.
Desc("number").
Where(builder.Eq{"repo_id": repo.ID, "branch": branch, "event": model.EventPush}).
Where(builder.Neq{"status": model.StatusBlocked}).
Get(pipeline))
}
func (s storage) GetPipelineLast(repo *model.Repo, branch string) (*model.Pipeline, error) {
pipeline := new(model.Pipeline)
return pipeline, wrapGet(s.engine.

View file

@ -84,7 +84,7 @@ func (s storage) StepUpdate(step *model.Step) error {
}
func deleteStep(sess *xorm.Session, stepID int64) error {
if _, err := sess.Where("id = ?", stepID).Delete(new(model.LogEntry)); err != nil {
if err := logDelete(sess, stepID); err != nil {
return err
}
return wrapDelete(sess.ID(stepID).Delete(new(model.Step)))

View file

@ -191,7 +191,7 @@ func (_m *Store) AgentUpdate(_a0 *model.Agent) error {
return r0
}
// Close provides a mock function with given fields:
// Close provides a mock function with no fields
func (_m *Store) Close() error {
ret := _m.Called()
@ -748,7 +748,37 @@ func (_m *Store) GetPipeline(_a0 int64) (*model.Pipeline, error) {
return r0, r1
}
// GetPipelineCount provides a mock function with given fields:
// GetPipelineBadge provides a mock function with given fields: _a0, _a1
func (_m *Store) GetPipelineBadge(_a0 *model.Repo, _a1 string) (*model.Pipeline, error) {
ret := _m.Called(_a0, _a1)
if len(ret) == 0 {
panic("no return value specified for GetPipelineBadge")
}
var r0 *model.Pipeline
var r1 error
if rf, ok := ret.Get(0).(func(*model.Repo, string) (*model.Pipeline, error)); ok {
return rf(_a0, _a1)
}
if rf, ok := ret.Get(0).(func(*model.Repo, string) *model.Pipeline); ok {
r0 = rf(_a0, _a1)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Pipeline)
}
}
if rf, ok := ret.Get(1).(func(*model.Repo, string) error); ok {
r1 = rf(_a0, _a1)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetPipelineCount provides a mock function with no fields
func (_m *Store) GetPipelineCount() (int64, error) {
ret := _m.Called()
@ -896,7 +926,7 @@ func (_m *Store) GetPipelineNumber(_a0 *model.Repo, _a1 int64) (*model.Pipeline,
return r0, r1
}
// GetPipelineQueue provides a mock function with given fields:
// GetPipelineQueue provides a mock function with no fields
func (_m *Store) GetPipelineQueue() ([]*model.Feed, error) {
ret := _m.Called()
@ -956,7 +986,7 @@ func (_m *Store) GetRepo(_a0 int64) (*model.Repo, error) {
return r0, r1
}
// GetRepoCount provides a mock function with given fields:
// GetRepoCount provides a mock function with no fields
func (_m *Store) GetRepoCount() (int64, error) {
ret := _m.Called()
@ -1104,7 +1134,7 @@ func (_m *Store) GetUser(_a0 int64) (*model.User, error) {
return r0, r1
}
// GetUserCount provides a mock function with given fields:
// GetUserCount provides a mock function with no fields
func (_m *Store) GetUserCount() (int64, error) {
ret := _m.Called()
@ -1796,7 +1826,7 @@ func (_m *Store) PermUpsert(perm *model.Perm) error {
return r0
}
// Ping provides a mock function with given fields:
// Ping provides a mock function with no fields
func (_m *Store) Ping() error {
ret := _m.Called()
@ -1928,7 +1958,7 @@ func (_m *Store) RegistryList(_a0 *model.Repo, _a1 bool, _a2 *model.ListOptions)
return r0, r1
}
// RegistryListAll provides a mock function with given fields:
// RegistryListAll provides a mock function with no fields
func (_m *Store) RegistryListAll() ([]*model.Registry, error) {
ret := _m.Called()
@ -2162,7 +2192,7 @@ func (_m *Store) SecretList(_a0 *model.Repo, _a1 bool, _a2 *model.ListOptions) (
return r0, r1
}
// SecretListAll provides a mock function with given fields:
// SecretListAll provides a mock function with no fields
func (_m *Store) SecretListAll() ([]*model.Secret, error) {
ret := _m.Called()
@ -2508,7 +2538,7 @@ func (_m *Store) TaskInsert(_a0 *model.Task) error {
return r0
}
// TaskList provides a mock function with given fields:
// TaskList provides a mock function with no fields
func (_m *Store) TaskList() ([]*model.Task, error) {
ret := _m.Called()

View file

@ -72,6 +72,8 @@ type Store interface {
GetPipeline(int64) (*model.Pipeline, error)
// GetPipelineNumber gets a pipeline by number.
GetPipelineNumber(*model.Repo, int64) (*model.Pipeline, error)
// GetPipelineBadge gets the last relevant pipeline for the badge.
GetPipelineBadge(*model.Repo, string) (*model.Pipeline, error)
// GetPipelineLast gets the last pipeline for the branch.
GetPipelineLast(*model.Repo, string) (*model.Pipeline, error)
// GetPipelineLastBefore gets the last pipeline before pipeline number N.

View file

@ -58,7 +58,7 @@
"prettier": "^3.3.3",
"tinycolor2": "^1.6.0",
"typescript": "5.6.3",
"vite": "^5.4.1",
"vite": "^6.0.0",
"vite-plugin-prismjs": "^0.0.11",
"vite-plugin-windicss": "^1.9.3",
"vite-svg-loader": "^5.1.0",

File diff suppressed because it is too large Load diff

View file

@ -518,7 +518,8 @@
"not_started": "noch nicht gestartet",
"sec_short": "sek",
"template": "DD.MM.YYYY, HH:mm z",
"weeks_short": "w"
"weeks_short": "w",
"just_now": "gerade eben"
},
"unknown_error": "Ein unbekannter Fehler ist aufgetreten",
"update_woodpecker": "Du solltest deine Woodpecker-Instanz auf {0} aktualisieren",
@ -576,7 +577,7 @@
"cli_and_api": {
"desc": "Persönlicher Zugangsschlüssel, CLI- und API-Nutzung",
"token": "Persönlicher Zugangsschlüssel",
"api_usage": "Beispiel zur Nutzung der API",
"api_usage": "Beispiel zur Nutzung des API",
"download_cli": "CLI herunterladen",
"reset_token": "Schlüssel zurücksetzen",
"swagger_ui": "Swagger-UI",

View file

@ -193,8 +193,8 @@
"add": "Ajouter un dépôt",
"branches": "Branches",
"deploy_pipeline": {
"enter_target": "Environnement de déploiement ciblé",
"title": "Déclenchement d'un événement de déploiement pour le pipeline courant #{pipelineId}",
"enter_target": "Environnement de 'déploiement' ciblé",
"title": "Déclenchement d'un événement de 'déploiement' pour le pipeline courant #{pipelineId}",
"trigger": "Déployer",
"variables": {
"add": "Ajouter une variable",
@ -365,7 +365,7 @@
"general": {
"allow_pr": {
"allow": "Autoriser les demandes de fusions",
"desc": "Les pipelines peuvent se déclencher sur les pull requests."
"desc": "Permettre aux pipelines de se déclencher sur les pull requests."
},
"cancel_prev": {
"cancel": "Annuler les pipelines précédents",
@ -373,8 +373,8 @@
},
"general": "Général",
"netrc_only_trusted": {
"desc": "Injecter les identifiants netrc uniquement dans des conteneurs de confiance (recommandé).",
"netrc_only_trusted": "Injecter les identifiants netrc uniquement dans des conteneurs de confiance"
"desc": "Les plugins listés ici auront accès aux identifiants netrc qui peuvent être utiliser pour cloner des dépôts depuis la forge, ou pour pousser vers celle-ci.",
"netrc_only_trusted": "Plugins de clonage personnalisés de confiance"
},
"pipeline_path": {
"default": "Par défaut: .woodpecker/*.{'{yaml,yml}'} -> .woodpecker.yaml -> .woodpecker.yml",
@ -388,14 +388,23 @@
"protected": "Protégé"
},
"save": "Enregistrer les paramètres",
"success": "Paramètres du dépôt mis à jour",
"success": "Paramètres du projet mis à jour",
"timeout": {
"minutes": "minutes",
"timeout": "Délai dinactivité"
},
"trusted": {
"desc": "Les conteneurs du pipeline ont accès à des capacités privilégiées (comme le montage de volumes).",
"trusted": "Vérifié"
"trusted": "Vérifié",
"network": {
"network": "Réseau"
},
"volumes": {
"volumes": "Volumes"
},
"security": {
"security": "Sécurité"
}
},
"visibility": {
"internal": {
@ -413,8 +422,8 @@
"visibility": "Visibilité du projet"
},
"allow_deploy": {
"allow": "Autoriser les déploiements",
"desc": "Autoriser les déploiements depuis les pipelines ayant réussis. À utiliser que si vous avez confiance dans les utilisateurs ayant un accès en écriture."
"allow": "Autoriser les événements de 'déploiement'.",
"desc": "Permettre les déploiements depuis les pipelines ayant réussis. À utiliser que si vous avez confiance dans les utilisateurs ayant un accès en écriture."
}
},
"not_allowed": "Vous n'êtes pas autorisé à accéder aux paramètres de ce dépôt",
@ -463,7 +472,22 @@
},
"settings": "Paramètres"
},
"user_none": "Cet(te) organisation / utilisateur n'a pas encore de projets."
"user_none": "Cet(te) organisation / utilisateur n'a pas encore de projets.",
"visibility": {
"visibility": "Visibilité du projet",
"public": {
"public": "Publique",
"desc": "Tout le monde peut voir le projet sans être connecté."
},
"private": {
"private": "Privé",
"desc": "Seul vous et les propriétaires de ce dépôt peuvent le voir."
},
"internal": {
"internal": "Interne",
"desc": "Seuls les comptes identifiés sur cet instance de Woodpecker peuvent voir ce projet."
}
}
},
"repos": "Dépôt",
"repositories": "Dépôts",
@ -476,7 +500,8 @@
"not_started": "pas encore démarré",
"sec_short": "sec",
"template": "D MMM, YYYY, HH:mm z",
"weeks_short": "s"
"weeks_short": "s",
"just_now": "il y a peu de temps"
},
"unknown_error": "Une erreur inconnue est survenue",
"update_woodpecker": "Merci de mettre à jour votre instance Woodpecker vers la version {0}",

View file

@ -144,8 +144,8 @@
"add": "Aggiungi repository",
"branches": "Rami",
"deploy_pipeline": {
"enter_target": "Ambiente di destinazione del deploy",
"title": "Avvia evento di deploy per la pipeline corrente #{pipelineId}",
"enter_target": "Ambiente di destinazione della 'distribuzione'",
"title": "Avvia evento di 'distribuzione' per la pipeline corrente #{pipelineId}",
"trigger": "Distribuzione",
"variables": {
"add": "Aggiungi variabile",
@ -196,13 +196,13 @@
},
"no_pipelines": "Non è ancora stata attivata alcuna pipeline.",
"pipelines_for": "Pipeline per ramo \"{branch}\"",
"files": "File modificati ({files})",
"files": "File modificati",
"no_pipeline_steps": "Nessuno step disponibile nella pipeline!",
"step_not_started": "Questo step non è ancora iniziato.",
"config": "Configurazione",
"tasks": "Attività",
"log_delete_confirm": "Vuoi davvero eliminare i registri attività di questo step?",
"errors": "Errori ({count})",
"errors": "Errori",
"protected": {
"awaits": "Questa pipeline è in attesa di approvazione da parte di un manutentore!",
"approve": "Approva",
@ -225,7 +225,7 @@
"declined": "rifiutata",
"error": "errore"
},
"warnings": "Avvertenze ({count})",
"warnings": "Avvertenze",
"show_errors": "Mostra errori",
"we_got_some_errors": "Oh no, si sono verificati degli errori!",
"event": {
@ -321,7 +321,7 @@
"desc": "Ogni pipeline deve essere approvata prima di essere eseguita."
},
"save": "Salva impostazioni",
"success": "Impostazioni della repository aggiornate",
"success": "Impostazioni del progetto aggiornate",
"timeout": {
"minutes": "minuti",
"timeout": "Scadenza"
@ -342,24 +342,36 @@
"visibility": "Visibilità progetto"
},
"cancel_prev": {
"desc": "Consente di annullare le pipeline in sospeso e in esecuzione dello stesso evento e contesto prima di avviare quella appena attivata.",
"desc": "I trigger di evento selezionati annulleranno le pipeline in sospeso e in esecuzione dello stesso evento prima di avviare quello più recente.",
"cancel": "Annulla pipeline precedenti"
},
"trusted": {
"desc": "I container eseguiti dalle pipeline ottengono accesso a funzionalità avanzate (come il montaggio di volumi).",
"trusted": "Attendibile"
"trusted": "Attendibile",
"network": {
"network": "Rete",
"desc": "I container di pipeline ottengono l'accesso ai privilegi di rete, come la modifica del DNS."
},
"volumes": {
"volumes": "Volumi",
"desc": "I container di pipeline possono montare volumi."
},
"security": {
"security": "Sicurezza",
"desc": "I container di pipeline ottengono l'accesso ai privilegi di sicurezza."
}
},
"allow_pr": {
"allow": "Consenti Richieste di Modifica",
"desc": "Le pipeline possono essere eseguite su richieste di modifica."
"desc": "Consenti l'esecuzione di pipeline sulle richieste di modifica."
},
"allow_deploy": {
"allow": "Consenti deployment",
"desc": "Consenti deployment da pipeline completate con successo. Utilizza solo se ti fidi di tutti gli utenti con accesso push."
"allow": "Consenti eventi di 'distribuzione'.",
"desc": "Consenti 'distribuzione' per le pipeline riuscite. Tutti gli utenti con autorizzazioni push possono attivarli, da usare con cautela."
},
"netrc_only_trusted": {
"netrc_only_trusted": "Inietta le credenziali netrc solo nei container attendibili",
"desc": "Inietta le credenziali netrc solo nei contenitori attendibili (consigliato)."
"netrc_only_trusted": "Estensioni personalizzate affidabili per clone",
"desc": "Le estensioni elencate qui avranno accesso alle credenziali netrc che possono essere utilizzate per clonare i repository dal forge o inviarvi il push."
}
},
"not_allowed": "Non ti è consentito accedere alle impostazioni di questa repository",
@ -395,14 +407,30 @@
"branch": "Ramo"
}
},
"user_none": "L'organizzazione / utente non ha ancora alcun progetto."
"user_none": "L'organizzazione / utente non ha ancora alcun progetto.",
"visibility": {
"visibility": "Visibilità progetto",
"public": {
"public": "Pubblico",
"desc": "Ogni utente può vedere il tuo progetto senza aver effettuato l'accesso."
},
"private": {
"private": "Privato",
"desc": "Solo tu e gli altri proprietari del repository possono visualizzare questo progetto."
},
"internal": {
"internal": "Interno",
"desc": "Solo gli utenti autenticati dell'istanza di Woodpecker possono visualizzare questo progetto."
}
}
},
"repos": "Repository",
"repositories": "Repository",
"search": "Cerca…",
"time": {
"not_started": "non ancora iniziato",
"template": "MMM D, YYYY, HH:mm z"
"template": "MMM D, YYYY, HH:mm z",
"just_now": "poco fa"
},
"unknown_error": "Si è verificato un errore sconosciuto",
"url": "URL",
@ -528,5 +556,16 @@
"saved": "Credenziali di registro salvate",
"deleted": "Credenziali di registro eliminate"
},
"login_with": "Accedi con {forge}"
"login_with": "Accedi con {forge}",
"all_repositories": "Tutti i repository",
"no_search_results": "Nessun risultato trovato",
"require_approval": {
"forks": "Richieste di modifica dal repository derivato",
"desc": "Impedisci alle pipeline dannose di esporre segreti o eseguire attività dannose approvandole prima dell'esecuzione.",
"require_approval_for": "Requisiti di approvazione",
"none": "Nessuno",
"pull_requests": "Tutte le richieste di modifica",
"all_events": "Tutti gli eventi del forge",
"none_desc": "Ogni evento attiva le pipeline, incluse le richieste di modifica. Questa impostazione può essere pericolosa ed è consigliata solo per le istanze private."
}
}

View file

@ -194,7 +194,8 @@
"title": "添加流水线变量",
"value": "变量值",
"delete": "删除变量"
}
},
"enter_task": "部署任务"
},
"enable": {
"disabled": "已禁用",
@ -215,7 +216,8 @@
"title": "添加流水线变量",
"value": "变量值",
"delete": "删除变量"
}
},
"show_pipelines": "查看流水线"
},
"not_allowed": "你没有权限访问这个仓库",
"open_in_forge": "在版本控制系统中打开",
@ -436,7 +438,22 @@
},
"settings": "设置"
},
"user_none": "此组织/用户还没有任何仓库。"
"user_none": "此组织/用户还没有任何仓库。",
"visibility": {
"visibility": "项目可见性",
"public": {
"desc": "任何无需登录的用户均可以看到你的项目。",
"public": "公共的"
},
"private": {
"private": "私有的",
"desc": "只有你和其他仓库拥有者才能看到这个项目。"
},
"internal": {
"internal": "内部的",
"desc": "只有Woodpecker的登录用户可以看到这个项目。"
}
}
},
"repos": "仓库",
"repositories": "仓库",
@ -527,5 +544,6 @@
"cli_login_failed": "登录到 CLI 失败",
"cli_login_denied": "登录 CLI 被拒绝",
"login_to_cli_description": "点击继续以登录到 CLI。",
"return_to_cli": "您现在可以关闭此选项卡并返回 CLI。"
"return_to_cli": "您现在可以关闭此选项卡并返回 CLI。",
"login_with": "使用 {forge} 登录"
}

View file

@ -1,14 +1,17 @@
<template>
<span class="text-xs font-medium inline-flex">
<span
class="pl-2 pr-1 py-0.5 bg-wp-state-neutral-100 text-gray-300 border-2 border-wp-state-neutral-100 rounded-l-full"
class="pl-2 pr-1 py-0.5 bg-wp-state-neutral-100 text-gray-300 border-2 border-wp-state-neutral-100 rounded-l-full flex items-center"
:class="{
'rounded-r-full pr-2': value === undefined,
}"
>
{{ label }}
</span>
<span v-if="value !== undefined" class="pl-1 pr-2 py-0.5 border-2 border-wp-state-neutral-100 rounded-r-full">
<span
v-if="value !== undefined"
class="pl-1 pr-2 py-0.5 border-2 border-wp-state-neutral-100 rounded-r-full flex items-center"
>
{{ value }}
</span>
</span>

View file

@ -1,10 +1,13 @@
<template>
<Panel>
<div class="flex flex-col border-b mb-4 pb-4 justify-center dark:border-wp-background-100">
<h1 class="text-xl text-wp-text-100 flex items-center gap-1">
{{ title }}
<DocsLink v-if="docsUrl" :topic="title" :url="docsUrl" />
</h1>
<div class="flex items-center justify-between">
<h1 class="text-xl text-wp-text-100 flex items-center gap-1">
{{ title }}
<DocsLink v-if="docsUrl" :topic="title" :url="docsUrl" />
</h1>
<slot v-if="$slots.titleActions" name="titleActions" />
</div>
<div class="flex flex-wrap gap-x-4 gap-y-2 items-center justify-between">
<p v-if="description" class="text-sm text-wp-text-alt-100">{{ description }}</p>

View file

@ -2,10 +2,10 @@
<Scaffold v-if="org" enable-tabs :go-back="goBack">
<template #title>
<span>
<router-link :to="{ name: 'org' }" class="hover:underline">
{{ org.name }}
<!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text -->
</router-link>
<router-link :to="{ name: 'org' }" class="hover:underline">{{
org.name
/* eslint-disable-next-line @intlify/vue-i18n/no-raw-text */
}}</router-link>
/
{{ $t('settings') }}
</span>

View file

@ -1,6 +1,6 @@
<template>
<Settings :title="$t('repo.settings.badge.badge')">
<template #headerActions>
<template #titleActions>
<a v-if="badgeUrl" :href="badgeUrl" target="_blank">
<img :src="badgeUrl" />
</a>

View file

@ -10,7 +10,7 @@
</InputField>
<InputField :label="$t('user.settings.cli_and_api.token')">
<template #headerActions>
<template #titleActions>
<Button class="ml-auto" :text="$t('user.settings.cli_and_api.reset_token')" @click="resetToken" />
</template>
<pre class="code-box">{{ token }}</pre>

View file

@ -34,6 +34,15 @@ const (
// pathVersion = "%s/version"
)
type ClientError struct {
StatusCode int
Message string
}
func (e *ClientError) Error() string {
return fmt.Sprintf("client error %d: %s", e.StatusCode, e.Message)
}
type client struct {
client *http.Client
addr string
@ -140,7 +149,10 @@ func (c *client) open(rawURL, method string, in any) (io.ReadCloser, error) {
if resp.StatusCode > http.StatusPartialContent {
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("client error %d: %s", resp.StatusCode, string(out))
return nil, &ClientError{
StatusCode: resp.StatusCode,
Message: string(out),
}
}
return resp.Body, nil
}

View file

@ -95,7 +95,7 @@ func (_m *Client) AgentDelete(_a0 int64) error {
return r0
}
// AgentList provides a mock function with given fields:
// AgentList provides a mock function with no fields
func (_m *Client) AgentList() ([]*woodpecker.Agent, error) {
ret := _m.Called()
@ -629,7 +629,7 @@ func (_m *Client) GlobalSecretUpdate(secret *woodpecker.Secret) (*woodpecker.Sec
return r0, r1
}
// LogLevel provides a mock function with given fields:
// LogLevel provides a mock function with no fields
func (_m *Client) LogLevel() (*woodpecker.LogLevel, error) {
ret := _m.Called()
@ -1241,7 +1241,7 @@ func (_m *Client) PipelineMetadata(repoID int64, pipelineNumber int) ([]byte, er
return r0, r1
}
// PipelineQueue provides a mock function with given fields:
// PipelineQueue provides a mock function with no fields
func (_m *Client) PipelineQueue() ([]*woodpecker.Feed, error) {
ret := _m.Called()
@ -1319,7 +1319,7 @@ func (_m *Client) PipelineStop(repoID int64, pipeline int64) error {
return r0
}
// QueueInfo provides a mock function with given fields:
// QueueInfo provides a mock function with no fields
func (_m *Client) QueueInfo() (*woodpecker.Info, error) {
ret := _m.Called()
@ -1859,7 +1859,7 @@ func (_m *Client) SecretUpdate(repoID int64, secret *woodpecker.Secret) (*woodpe
return r0, r1
}
// Self provides a mock function with given fields:
// Self provides a mock function with no fields
func (_m *Client) Self() (*woodpecker.User, error) {
ret := _m.Called()

View file

@ -4,6 +4,7 @@ import (
"fmt"
"net/url"
"strconv"
"strings"
"time"
)
@ -31,8 +32,12 @@ const (
type PipelineListOptions struct {
ListOptions
Before time.Time
After time.Time
Before time.Time
After time.Time
Branch string
Events []string
RefContains string
Status string
}
type CronListOptions struct {
@ -77,6 +82,18 @@ func (opt *PipelineListOptions) QueryEncode() string {
if !opt.After.IsZero() {
query.Add("after", opt.After.Format(time.RFC3339))
}
if opt.Branch != "" {
query.Add("branch", opt.Branch)
}
if len(opt.Events) > 0 {
query.Add("event", strings.Join(opt.Events, ","))
}
if opt.RefContains != "" {
query.Add("ref", opt.RefContains)
}
if opt.Status != "" {
query.Add("status", opt.Status)
}
return query.Encode()
}

View file

@ -80,7 +80,6 @@ type (
RepoPatch struct {
Config *string `json:"config_file,omitempty"`
IsTrusted *bool `json:"trusted,omitempty"`
IsGated *bool `json:"gated,omitempty"` // TODO: remove in next major release
RequireApproval *ApprovalMode `json:"require_approval,omitempty"`
Timeout *int64 `json:"timeout,omitempty"`
Visibility *string `json:"visibility"`