diff --git a/.cspell.json b/.cspell.json
index a16205fd9..1dea08fca 100644
--- a/.cspell.json
+++ b/.cspell.json
@@ -6,27 +6,31 @@
"en_us",
// code
"go",
- "node",
- // package names
- "npm"
+ "node"
],
"words": [
"abool",
"anbraten",
"antfu",
"apimachinery",
+ "Archlinux",
"autoincr",
"autoscaler",
+ "backporting",
+ "backports",
"binutils",
"bitbucketdatacenter",
"Boguslawski",
"bradrydzewski",
"BUILDPLATFORM",
"buildx",
+ "caddyfile",
"ccmenu",
"certmagic",
"charmbracelet",
+ "cicd",
"ciphertext",
+ "Cloudron",
"Codeberg",
"compatiblelicenses",
"corepack",
@@ -38,6 +42,8 @@
"Debugf",
"desaturate",
"devx",
+ "dind",
+ "Dockle",
"doublestar",
"envsubst",
"errgroup",
@@ -46,64 +52,89 @@
"excalidraw",
"favicons",
"Fediverse",
+ "Feishu",
"Fogas",
"forbidigo",
"Forgejo",
"fsnotify",
+ "Geeklab",
"Georgiana",
"gitea",
+ "gitmodules",
"GOARCH",
"GOBIN",
"gocritic",
"GODEBUG",
+ "godoc",
+ "Gogs",
"golangci",
"gomod",
"gonic",
"GOPATH",
+ "Gource",
+ "handlebargh",
"HEALTHCHECK",
"healthz",
"Hetzner",
+ "HETZNERCLOUD",
+ "homelab",
"HTMLURL",
"HTTPFS",
- "httpsig",
+ "httpsign",
"HTTPURL",
"httputil",
"ianvs",
"iconify",
+ "inetutils",
+ "Infima",
"Infof",
"Informatyka",
"intlify",
"Ionescu",
+ "Jetpack",
"Kaniko",
"Keyfunc",
"kyvg",
"LASTEXITCODE",
"Laszlo",
"laszlocph",
+ "letsencrypt",
+ "loadbalancer",
"logfile",
"loglevel",
"LONGBLOB",
"LONGTEXT",
+ "lonix1",
"mapstructure",
"markdownlint",
+ "mdbook",
"memswap",
"Metas",
"mhmxs",
"moby",
"Msgf",
+ "mstruebing",
"multiarch",
"multierr",
"netdns",
"Netrc",
+ "Nextcloud",
"nfpm",
"nixos",
+ "nixpkgs",
"nocolor",
"nolint",
"norunningpipelines",
"nosniff",
+ "ntfy",
"octocat",
+ "opensource",
+ "Pacman",
+ "picus",
"Pinia",
"pkce",
+ "pnpx",
+ "Polyform",
"posix",
"ppid",
"Println",
@@ -123,19 +154,26 @@
"repology",
"reslimit",
"Reviewdog",
+ "Rieter",
"riscv",
"rundll32",
"Rydzewski",
"seccomp",
"secprofile",
"securecookie",
+ "selfhosted",
"sess",
"shellescape",
+ "sigstore",
+ "Sonatype",
"SSHURL",
+ "sslmode",
"stepbuilder",
"stretchr",
+ "structs",
"sublicensable",
"swaggo",
+ "syscalls",
"TARGETARCH",
"TARGETOS",
"techknowlogick",
@@ -143,38 +181,49 @@
"threadcreate",
"tink",
"tinycolor",
+ "tmole",
"tmpfs",
"tmpl",
"tolerations",
+ "Traefik",
"tseslint",
"ttlcache",
+ "TUNEIT",
+ "Tunnelmole",
"typecheck",
"Typeflag",
"unplugin",
"Upsert",
"urfave",
+ "usecase",
"varchar",
"varz",
+ "Vieter",
+ "virtualisation",
+ "visualisation",
+ "vite",
"vueuse",
"waivable",
"Warnf",
+ "webhookd",
"Weblate",
"windi",
"windicss",
"woodpeckerci",
"WORKDIR",
"Wrapf",
+ "x-enum-varnames",
"xlink",
"xlog",
"xorm",
"xormigrate",
"xyaml",
"yamls",
+ "Yuno",
"zerolog",
"zerologger"
],
"ignorePaths": [
- "**/node_modules/**/*",
"*.excalidraw",
"*.svg",
"*_test.go",
@@ -185,19 +234,26 @@
".vscode/extensions.json",
"CHANGELOG.md",
"Makefile",
- "flake.lock",
"flake.nix",
"go.mod",
- "go.sum",
- "pipeline/rpc/proto/woodpecker.pb.go",
- "pnpm-lock.yaml",
+ "**/*.pb.go",
"server/store/datastore/migration/**/*",
"web/components.d.ts",
"web/src/assets/locales/**/*",
"**/fixtures/**",
"**/testdata/**",
+ "docs/versioned_docs/",
+ "package.json",
+ "91-migrations.md",
+ // generated
+ "go.sum",
+ "flake.lock",
+ "pnpm-lock.yaml",
+ "**/node_modules/**/*",
+ "cmd/server/docs/docs.go",
// TODO: remove the following
- "docs/"
+ "docs/**/*.js",
+ "docs/**/*.ts"
],
// Exclude imports, because they are also strings.
"ignoreRegExpList": [
@@ -210,7 +266,9 @@
// ignore nolint directive
"//\\s*nolint:.*",
// ignore docker image names
- "\\s*docker\\.io/.*"
+ "\\s*docker\\.io/.*",
+ // ignore inline svg in css
+ "\\s*url\\(\"data:image/svg\\+xml.*"
],
"enableFiletypes": ["dockercompose"]
}
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 000000000..46dd8d027
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,11 @@
+
diff --git a/.github/renovate.json b/.github/renovate.json
index d3ea2d642..758ff2b22 100644
--- a/.github/renovate.json
+++ b/.github/renovate.json
@@ -1,6 +1,16 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["github>woodpecker-ci/renovate-config"],
+ "customManagers": [
+ {
+ "customType": "regex",
+ "fileMatch": ["shared/constant/constant.go"],
+ "matchStrings": [
+ "//\\s*renovate:\\s*datasource=(?.*?) depName=(?.*?)( versioning=(?.*?))?\\s+DefaultCloneImage = \"docker.io/woodpeckerci/plugin-git:(?.*)\""
+ ],
+ "versioningTemplate": "{{#if versioning}}{{{versioning}}}{{else}}semver{{/if}}"
+ }
+ ],
"packageRules": [
{
"matchCurrentVersion": "<1.0.0",
diff --git a/.golangci.yaml b/.golangci.yaml
index 391282e2c..aaa9d14f0 100644
--- a/.golangci.yaml
+++ b/.golangci.yaml
@@ -184,3 +184,5 @@ issues:
run:
timeout: 15m
+ build-tags:
+ - test
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 62003e514..305726233 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -24,11 +24,11 @@ repos:
- id: checkmake
exclude: '^docker/Dockerfile.make$' # actually a Dockerfile and not a makefile
- repo: https://github.com/hadolint/hadolint
- rev: v2.12.0
+ rev: v2.13.0-beta
hooks:
- id: hadolint
- repo: https://github.com/pre-commit/mirrors-prettier
- rev: v3.1.0
+ rev: v4.0.0-alpha.8
hooks:
- id: prettier
- repo: https://github.com/adrienverge/yamllint.git
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 90fbfbc2b..4eda24143 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -8,11 +8,9 @@
},
"go.lintTool": "golangci-lint",
"go.lintFlags": ["--fast"],
+ "go.buildTags": "test",
"eslint.workingDirectories": ["./web"],
"prettier.ignorePath": "./web/.prettierignore",
- // Enable the ESlint flat config support
- // (remove this if your ESLint extension above v3.0.5)
- "eslint.experimental.useFlatConfig": true,
// Auto fix
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
diff --git a/.woodpecker/binaries.yaml b/.woodpecker/binaries.yaml
index b1f50d80f..509dccbda 100644
--- a/.woodpecker/binaries.yaml
+++ b/.woodpecker/binaries.yaml
@@ -1,12 +1,15 @@
when:
- event: tag
+ - event: tag
+ - event: pull_request
+ branch: ${CI_REPO_DEFAULT_BRANCH}
+ path: Makefile
variables:
- - &golang_image 'docker.io/golang:1.22'
+ - &golang_image 'docker.io/golang:1.23'
- &node_image 'docker.io/node:22-alpine'
- &xgo_image 'docker.io/techknowlogick/xgo:go-1.22.x'
-# cspell:words bindata netgo TARGZ
+# cspell:words bindata netgo
steps:
build-web:
@@ -35,7 +38,7 @@ steps:
environment:
PLATFORMS: linux|arm64/v8;linux|amd64;windows|amd64
TAGS: bindata sqlite sqlite_unlock_notify netgo
- TARGZ: '1'
+ ARCHIVE_IT: '1'
build-tarball:
depends_on:
@@ -50,6 +53,8 @@ steps:
- vendor
image: *golang_image
commands:
+ - apt update
+ - apt install -y zip
- make release-agent
build-cli:
@@ -57,6 +62,8 @@ steps:
- vendor
image: *golang_image
commands:
+ - apt update
+ - apt install -y zip
- make release-cli
build-deb-rpm:
@@ -96,7 +103,10 @@ steps:
from_secret: github_token
files:
- dist/*.tar.gz
+ - dist/*.zip
- dist/*.deb
- dist/*.rpm
- dist/checksums.txt
title: ${CI_COMMIT_TAG##v}
+ when:
+ event: tag
diff --git a/.woodpecker/docker.yaml b/.woodpecker/docker.yaml
index 6d023816c..f9d601753 100644
--- a/.woodpecker/docker.yaml
+++ b/.woodpecker/docker.yaml
@@ -1,15 +1,15 @@
variables:
- - &golang_image 'docker.io/golang:1.22'
+ - &golang_image 'docker.io/golang:1.23'
- &node_image 'docker.io/node:22-alpine'
- &xgo_image 'docker.io/techknowlogick/xgo:go-1.22.x'
- - &buildx_plugin 'docker.io/woodpeckerci/plugin-docker-buildx:4.0.0'
+ - &buildx_plugin 'docker.io/woodpeckerci/plugin-docker-buildx:4.2.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'
- &platforms_alpine 'linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/amd64,linux/ppc64le'
- &build_args 'CI_COMMIT_SHA=${CI_COMMIT_SHA},CI_COMMIT_BRANCH=${CI_COMMIT_BRANCH},CI_COMMIT_TAG=${CI_COMMIT_TAG}'
- # cspell:words woodpeckerbot netgo TARGZ
+ # cspell:words woodpeckerbot netgo
# vars used on push / tag events only
- publish_logins: &publish_logins # Default DockerHub login
diff --git a/.woodpecker/release-helper.yaml b/.woodpecker/release-helper.yaml
index d733ec184..b9c19c553 100644
--- a/.woodpecker/release-helper.yaml
+++ b/.woodpecker/release-helper.yaml
@@ -1,6 +1,6 @@
steps:
release-helper:
- image: woodpeckerci/plugin-ready-release-go:1.1.2
+ image: woodpeckerci/plugin-ready-release-go:1.2.0
pull: true
settings:
release_branch: ${CI_REPO_DEFAULT_BRANCH}
diff --git a/.woodpecker/static.yaml b/.woodpecker/static.yaml
index 8086ddc38..6f630d806 100644
--- a/.woodpecker/static.yaml
+++ b/.woodpecker/static.yaml
@@ -5,7 +5,7 @@ when:
steps:
- name: lint-editorconfig
- image: docker.io/mstruebing/editorconfig-checker:v3.0.1
+ image: docker.io/mstruebing/editorconfig-checker:v3.0.3
depends_on: []
when:
- event: pull_request
@@ -23,15 +23,15 @@ steps:
- tree --gitignore -I 012_columns_rename_procs_to_steps.go -I versioned_docs -I '*opensource.svg'| pnpx cspell lint --no-progress stdin
- name: prettier
- image: docker.io/woodpeckerci/plugin-prettier:0.1.0
+ image: docker.io/woodpeckerci/plugin-prettier:0.2.0
depends_on: []
settings:
- version: 3.2.5
+ version: 3.3.3
- name: links
image: docker.io/lycheeverse/lychee:0.15.1
depends_on: []
commands:
- lychee pipeline/frontend/yaml/linter/schema/schema.json
- - lychee --exclude localhost docs/docs/
- - lychee --exclude localhost docs/src/pages/
+ - lychee --user-agent "curl/8.4.0" --exclude localhost docs/docs/
+ - lychee --user-agent "curl/8.4.0" --exclude localhost docs/src/pages/
diff --git a/.woodpecker/test.yaml b/.woodpecker/test.yaml
index cf0d443fa..0d39cfa2d 100644
--- a/.woodpecker/test.yaml
+++ b/.woodpecker/test.yaml
@@ -40,6 +40,7 @@ steps:
- go run go.woodpecker-ci.org/woodpecker/v2/cmd/cli lint
environment:
WOODPECKER_DISABLE_UPDATE_CHECK: true
+ WOODPECKER_PLUGINS_PRIVILEGED: 'docker.io/woodpeckerci/plugin-docker-buildx:4.2.0'
when:
- event: pull_request
path:
diff --git a/.woodpecker/web.yaml b/.woodpecker/web.yaml
index b64f33f5c..85d01e854 100644
--- a/.woodpecker/web.yaml
+++ b/.woodpecker/web.yaml
@@ -58,6 +58,7 @@ steps:
test:
depends_on:
- install-dependencies
+ - format-check # wait for it else test artifacts are falsely detected as wrong
image: *node_image
directory: web/
commands:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index da9f14e50..c0053be19 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,133 @@
# Changelog
+## [2.7.1](https://github.com/woodpecker-ci/woodpecker/releases/tag/v2.7.1) - 2024-09-07
+
+### ❤️ Thanks to all contributors! ❤️
+
+@6543, @anbraten, @j04n-f, @qwerty287
+
+### 🔒 Security
+
+- Lint privileged plugin match and allow to be set empty [[#4084](https://github.com/woodpecker-ci/woodpecker/pull/4084)]
+- Allow admins to specify privileged plugins by name **and tag** [[#4076](https://github.com/woodpecker-ci/woodpecker/pull/4076)]
+- Warn if using secrets/env with plugin [[#4039](https://github.com/woodpecker-ci/woodpecker/pull/4039)]
+
+### 🐛 Bug Fixes
+
+- Set refspec for gitlab MR [[#4021](https://github.com/woodpecker-ci/woodpecker/pull/4021)]
+- Change Bitbucket PR hook to point the source branch, commit & ref [[#3965](https://github.com/woodpecker-ci/woodpecker/pull/3965)]
+- Add updated, merged and declined events to bb webhook activation [[#3963](https://github.com/woodpecker-ci/woodpecker/pull/3963)]
+- Fix login via navbar [[#3962](https://github.com/woodpecker-ci/woodpecker/pull/3962)]
+- Fix panic if forge is unreachable [[#3944](https://github.com/woodpecker-ci/woodpecker/pull/3944)]
+- Fix org settings page [[#4093](https://github.com/woodpecker-ci/woodpecker/pull/4093)]
+
+### Misc
+
+- Bump github.com/docker/docker from v24.0.9 to v24.0.9+30 [[#4077](https://github.com/woodpecker-ci/woodpecker/pull/4077)]
+
+## [2.7.0](https://github.com/woodpecker-ci/woodpecker/releases/tag/v2.7.0) - 2024-07-18
+
+### ❤️ Thanks to all contributors! ❤️
+
+@6543, @anbraten, @dvjn, @hhamalai, @lafriks, @pat-s, @qwerty287, @smainz, @tongjicoder, @zc-devs
+
+### 🔒 Security
+
+- Add blocklist of environment variables who could alter execution of plugins [[#3934](https://github.com/woodpecker-ci/woodpecker/pull/3934)]
+- Make sure plugins only mount the workspace base in a predefinde location [[#3933](https://github.com/woodpecker-ci/woodpecker/pull/3933)]
+- Disallow to set arbitrary environments for plugins [[#3909](https://github.com/woodpecker-ci/woodpecker/pull/3909)]
+- Use proper oauth state [[#3847](https://github.com/woodpecker-ci/woodpecker/pull/3847)]
+- Enhance token checking [[#3842](https://github.com/woodpecker-ci/woodpecker/pull/3842)]
+- Bump github.com/hashicorp/go-retryablehttp v0.7.5 -> v0.7.7 [[#3834](https://github.com/woodpecker-ci/woodpecker/pull/3834)]
+
+### ✨ Features
+
+- Gracefully shutdown server [[#3896](https://github.com/woodpecker-ci/woodpecker/pull/3896)]
+- Gracefully shutdown agent [[#3895](https://github.com/woodpecker-ci/woodpecker/pull/3895)]
+- Convert urls in logs to links [[#3904](https://github.com/woodpecker-ci/woodpecker/pull/3904)]
+- Allow login using multiple forges [[#3822](https://github.com/woodpecker-ci/woodpecker/pull/3822)]
+- Global and organization registries [[#1672](https://github.com/woodpecker-ci/woodpecker/pull/1672)]
+- Cli get repo from git remote [[#3830](https://github.com/woodpecker-ci/woodpecker/pull/3830)]
+- Add api for forges [[#3733](https://github.com/woodpecker-ci/woodpecker/pull/3733)]
+
+### 📈 Enhancement
+
+- Cli fix pipeline logs [[#3913](https://github.com/woodpecker-ci/woodpecker/pull/3913)]
+- Migrate to github.com/urfave/cli/v3 [[#2951](https://github.com/woodpecker-ci/woodpecker/pull/2951)]
+- Allow to change the working directory also for plugins and services [[#3914](https://github.com/woodpecker-ci/woodpecker/pull/3914)]
+- Remove `unplugin-icons` [[#3809](https://github.com/woodpecker-ci/woodpecker/pull/3809)]
+- Release windows binaries as zip file [[#3906](https://github.com/woodpecker-ci/woodpecker/pull/3906)]
+- Convert to openapi 3.0 [[#3897](https://github.com/woodpecker-ci/woodpecker/pull/3897)]
+- Add user registries UI [[#3888](https://github.com/woodpecker-ci/woodpecker/pull/3888)]
+- Sort users by login [[#3891](https://github.com/woodpecker-ci/woodpecker/pull/3891)]
+- Exclude dummy backend in production [[#3877](https://github.com/woodpecker-ci/woodpecker/pull/3877)]
+- Fix deploy task env [[#3878](https://github.com/woodpecker-ci/woodpecker/pull/3878)]
+- Get default branch and show message in pipeline list [[#3867](https://github.com/woodpecker-ci/woodpecker/pull/3867)]
+- Add timestamp for last work done by agent [[#3844](https://github.com/woodpecker-ci/woodpecker/pull/3844)]
+- Adjust logger types [[#3859](https://github.com/woodpecker-ci/woodpecker/pull/3859)]
+- Cleanup state reporting [[#3850](https://github.com/woodpecker-ci/woodpecker/pull/3850)]
+- Unify DB tables/columns [[#3806](https://github.com/woodpecker-ci/woodpecker/pull/3806)]
+- Let webhook pass on pipeline parsing error [[#3829](https://github.com/woodpecker-ci/woodpecker/pull/3829)]
+- Exclude mocks from release build [[#3831](https://github.com/woodpecker-ci/woodpecker/pull/3831)]
+- K8s secrets reference from step [[#3655](https://github.com/woodpecker-ci/woodpecker/pull/3655)]
+
+### 🐛 Bug Fixes
+
+- Handle empty repositories in gitea when listing PRs [[#3925](https://github.com/woodpecker-ci/woodpecker/pull/3925)]
+- Update alpine package dep for docker images [[#3917](https://github.com/woodpecker-ci/woodpecker/pull/3917)]
+- Don't report error if agent was terminated gracefully [[#3894](https://github.com/woodpecker-ci/woodpecker/pull/3894)]
+- Let agents continuously report their health [[#3893](https://github.com/woodpecker-ci/woodpecker/pull/3893)]
+- Ignore warnings for cli exec [[#3868](https://github.com/woodpecker-ci/woodpecker/pull/3868)]
+- Correct favicon states [[#3832](https://github.com/woodpecker-ci/woodpecker/pull/3832)]
+- Cleanup of the login flow and tests [[#3810](https://github.com/woodpecker-ci/woodpecker/pull/3810)]
+- Fix newlines in logs [[#3808](https://github.com/woodpecker-ci/woodpecker/pull/3808)]
+- Fix authentication error handling [[#3807](https://github.com/woodpecker-ci/woodpecker/pull/3807)]
+
+### 📚 Documentation
+
+- Streamline docs for new users [[#3803](https://github.com/woodpecker-ci/woodpecker/pull/3803)]
+- Add mastodon verification [[#3843](https://github.com/woodpecker-ci/woodpecker/pull/3843)]
+- chore(deps): update docs npm deps non-major [[#3837](https://github.com/woodpecker-ci/woodpecker/pull/3837)]
+- fix(deps): update docs npm deps non-major [[#3824](https://github.com/woodpecker-ci/woodpecker/pull/3824)]
+- Add openSUSE package [[#3800](https://github.com/woodpecker-ci/woodpecker/pull/3800)]
+- chore(deps): update docs npm deps non-major [[#3798](https://github.com/woodpecker-ci/woodpecker/pull/3798)]
+- Add "Docker Tags" Plugin [[#3796](https://github.com/woodpecker-ci/woodpecker/pull/3796)]
+- chore(deps): update dependency marked to v13 [[#3792](https://github.com/woodpecker-ci/woodpecker/pull/3792)]
+- chore: fix some comments [[#3788](https://github.com/woodpecker-ci/woodpecker/pull/3788)]
+
+### Misc
+
+- chore(deps): update web npm deps non-major [[#3930](https://github.com/woodpecker-ci/woodpecker/pull/3930)]
+- chore(deps): update dependency vitest to v2 [[#3905](https://github.com/woodpecker-ci/woodpecker/pull/3905)]
+- fix(deps): update module github.com/google/go-github/v62 to v63 [[#3910](https://github.com/woodpecker-ci/woodpecker/pull/3910)]
+- chore(deps): update docker.io/woodpeckerci/plugin-docker-buildx docker tag to v4.1.0 [[#3908](https://github.com/woodpecker-ci/woodpecker/pull/3908)]
+- Update plugin-git and add renovate trigger [[#3901](https://github.com/woodpecker-ci/woodpecker/pull/3901)]
+- chore(deps): update docker.io/mstruebing/editorconfig-checker docker tag to v3.0.3 [[#3903](https://github.com/woodpecker-ci/woodpecker/pull/3903)]
+- fix(deps): update golang-packages [[#3875](https://github.com/woodpecker-ci/woodpecker/pull/3875)]
+- chore(deps): lock file maintenance [[#3876](https://github.com/woodpecker-ci/woodpecker/pull/3876)]
+- [pre-commit.ci] pre-commit autoupdate [[#3862](https://github.com/woodpecker-ci/woodpecker/pull/3862)]
+- Add dummy backend [[#3820](https://github.com/woodpecker-ci/woodpecker/pull/3820)]
+- chore(deps): update dependency replace-in-file to v8 [[#3852](https://github.com/woodpecker-ci/woodpecker/pull/3852)]
+- Update forgejo sdk [[#3840](https://github.com/woodpecker-ci/woodpecker/pull/3840)]
+- chore(deps): lock file maintenance [[#3838](https://github.com/woodpecker-ci/woodpecker/pull/3838)]
+- Allow to set dist dir using env var [[#3814](https://github.com/woodpecker-ci/woodpecker/pull/3814)]
+- chore(deps): lock file maintenance [[#3805](https://github.com/woodpecker-ci/woodpecker/pull/3805)]
+- chore(deps): update docker.io/lycheeverse/lychee docker tag to v0.15.1 [[#3797](https://github.com/woodpecker-ci/woodpecker/pull/3797)]
+
+## [2.6.1](https://github.com/woodpecker-ci/woodpecker/releases/tag/v2.6.1) - 2024-07-19
+
+### 🔒 Security
+
+- Add blocklist of environment variables who could alter execution of plugins [[#3934](https://github.com/woodpecker-ci/woodpecker/pull/3934)]
+- Make sure plugins only mount the workspace base in a predefinde location [[#3933](https://github.com/woodpecker-ci/woodpecker/pull/3933)]
+- Disalow to set arbitrary environments for plugins [[#3909](https://github.com/woodpecker-ci/woodpecker/pull/3909)]
+- Bump trivy plugin version and remove unused variable [[#3833](https://github.com/woodpecker-ci/woodpecker/pull/3833)]
+
+### 🐛 Bug Fixes
+
+- Let webhook pass on pipeline parsion error [[#3829](https://github.com/woodpecker-ci/woodpecker/pull/3829)]
+- Fix newlines in logs [[#3808](https://github.com/woodpecker-ci/woodpecker/pull/3808)]
+
## [2.6.0](https://github.com/woodpecker-ci/woodpecker/releases/tag/v2.6.0) - 2024-06-13
### ❤️ Thanks to all contributors! ❤️
diff --git a/Makefile b/Makefile
index d5471b0b4..8ab78b0c6 100644
--- a/Makefile
+++ b/Makefile
@@ -8,6 +8,8 @@ ifeq ($(TARGETOS),windows)
BIN_SUFFIX := .exe
endif
+DIST_DIR ?= dist
+
VERSION ?= next
VERSION_NUMBER ?= 0.0.0
CI_COMMIT_SHA ?= $(shell git rev-parse HEAD)
@@ -27,6 +29,7 @@ else
endif
endif
+TAGS ?=
LDFLAGS := -X go.woodpecker-ci.org/woodpecker/v2/version.Version=${VERSION}
STATIC_BUILD ?= true
ifeq ($(STATIC_BUILD),true)
@@ -103,7 +106,7 @@ clean: ## Clean build artifacts
.PHONY: clean-all
clean-all: clean ## Clean all artifacts
- rm -rf dist web/dist docs/build docs/node_modules web/node_modules
+ rm -rf ${DIST_DIR} web/dist docs/build docs/node_modules web/node_modules
# delete generated
rm -rf docs/docs/40-cli.md docs/swagger.json
@@ -160,20 +163,20 @@ lint-ui: ui-dependencies ## Lint UI code
(cd web/; pnpm lint --quiet)
test-agent: ## Test agent code
- go test -race -cover -coverprofile agent-coverage.out -timeout 30s go.woodpecker-ci.org/woodpecker/v2/cmd/agent go.woodpecker-ci.org/woodpecker/v2/agent/...
+ go test -race -cover -coverprofile agent-coverage.out -timeout 60s -tags 'test $(TAGS)' go.woodpecker-ci.org/woodpecker/v2/cmd/agent go.woodpecker-ci.org/woodpecker/v2/agent/...
test-server: ## Test server code
- go test -race -cover -coverprofile server-coverage.out -timeout 30s go.woodpecker-ci.org/woodpecker/v2/cmd/server $(shell go list go.woodpecker-ci.org/woodpecker/v2/server/... | grep -v '/store')
+ go test -race -cover -coverprofile server-coverage.out -timeout 60s -tags 'test $(TAGS)' go.woodpecker-ci.org/woodpecker/v2/cmd/server $(shell go list go.woodpecker-ci.org/woodpecker/v2/server/... | grep -v '/store')
test-cli: ## Test cli code
- go test -race -cover -coverprofile cli-coverage.out -timeout 30s go.woodpecker-ci.org/woodpecker/v2/cmd/cli go.woodpecker-ci.org/woodpecker/v2/cli/...
+ go test -race -cover -coverprofile cli-coverage.out -timeout 60s -tags 'test $(TAGS)' go.woodpecker-ci.org/woodpecker/v2/cmd/cli go.woodpecker-ci.org/woodpecker/v2/cli/...
test-server-datastore: ## Test server datastore
- go test -timeout 120s -run TestMigrate go.woodpecker-ci.org/woodpecker/v2/server/store/...
- go test -race -timeout 30s -skip TestMigrate go.woodpecker-ci.org/woodpecker/v2/server/store/...
+ go test -timeout 300s -tags 'test $(TAGS)' -run TestMigrate go.woodpecker-ci.org/woodpecker/v2/server/store/...
+ go test -race -timeout 100s -tags 'test $(TAGS)' -skip TestMigrate go.woodpecker-ci.org/woodpecker/v2/server/store/...
test-server-datastore-coverage: ## Test server datastore with coverage report
- go test -race -cover -coverprofile datastore-coverage.out -timeout 180s go.woodpecker-ci.org/woodpecker/v2/server/store/...
+ go test -race -cover -coverprofile datastore-coverage.out -timeout 300s -tags 'test $(TAGS)' go.woodpecker-ci.org/woodpecker/v2/server/store/...
test-ui: ui-dependencies ## Test UI code
(cd web/; pnpm run lint)
@@ -182,7 +185,7 @@ test-ui: ui-dependencies ## Test UI code
(cd web/; pnpm run test)
test-lib: ## Test lib code
- go test -race -cover -coverprofile coverage.out -timeout 30s $(shell go list ./... | grep -v '/cmd\|/agent\|/cli\|/server')
+ go test -race -cover -coverprofile coverage.out -timeout 60s -tags 'test $(TAGS)' $(shell go list ./... | grep -v '/cmd\|/agent\|/cli\|/server')
.PHONY: test
test: test-agent test-server test-server-datastore test-cli test-lib ## Run all tests
@@ -193,16 +196,16 @@ build-ui: ## Build UI
(cd web/; pnpm install --frozen-lockfile; pnpm build)
build-server: build-ui generate-swagger ## Build server
- CGO_ENABLED=${CGO_ENABLED} GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -ldflags '${LDFLAGS}' -o dist/woodpecker-server${BIN_SUFFIX} go.woodpecker-ci.org/woodpecker/v2/cmd/server
+ CGO_ENABLED=${CGO_ENABLED} GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -tags '$(TAGS)' -ldflags '${LDFLAGS}' -o ${DIST_DIR}/woodpecker-server${BIN_SUFFIX} go.woodpecker-ci.org/woodpecker/v2/cmd/server
build-agent: ## Build agent
- CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -ldflags '${LDFLAGS}' -o dist/woodpecker-agent${BIN_SUFFIX} go.woodpecker-ci.org/woodpecker/v2/cmd/agent
+ CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -tags '$(TAGS)' -ldflags '${LDFLAGS}' -o ${DIST_DIR}/woodpecker-agent${BIN_SUFFIX} go.woodpecker-ci.org/woodpecker/v2/cmd/agent
build-cli: ## Build cli
- CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -ldflags '${LDFLAGS}' -o dist/woodpecker-cli${BIN_SUFFIX} go.woodpecker-ci.org/woodpecker/v2/cmd/cli
+ CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -tags '$(TAGS)' -ldflags '${LDFLAGS}' -o ${DIST_DIR}/woodpecker-cli${BIN_SUFFIX} go.woodpecker-ci.org/woodpecker/v2/cmd/cli
build-tarball: ## Build tar archive
- mkdir -p dist && tar chzvf dist/woodpecker-src.tar.gz \
+ mkdir -p ${DIST_DIR} && tar chzvf ${DIST_DIR}/woodpecker-src.tar.gz \
--exclude="*.exe" \
--exclude="./.pnpm-store" \
--exclude="node_modules" \
@@ -224,7 +227,7 @@ cross-compile-server: ## Cross compile the server
TARGETARCH_BUILDX=$(subst arm64/v8,arm64,$(subst arm/v7,arm,$(word 2,$(subst |, ,$(platform))))) \
make release-server-xgo || exit 1; \
)
- tree dist
+ tree ${DIST_DIR}
release-server-xgo: check-xgo ## Create server binaries for release using xgo
@echo "Building for:"
@@ -232,58 +235,79 @@ release-server-xgo: check-xgo ## Create server binaries for release using xgo
@echo "arch orgi:$(TARGETARCH)"
@echo "arch (xgo):$(TARGETARCH_XGO)"
@echo "arch (buildx):$(TARGETARCH_BUILDX)"
-
- CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -dest ./dist/server/$(TARGETOS)_$(TARGETARCH_BUILDX) -tags 'netgo osusergo grpcnotrace $(TAGS)' -ldflags '-linkmode external $(LDFLAGS)' -targets '$(TARGETOS)/$(TARGETARCH_XGO)' -out woodpecker-server -pkg cmd/server .
- @if [ "$${XGO_IN_XGO:-0}" -eq "1" ]; then echo "inside xgo image"; \
- mkdir -p ./dist/server/$(TARGETOS)_$(TARGETARCH_BUILDX); \
- mv -vf /build/woodpecker-server* ./dist/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX); \
- else echo "outside xgo image"; \
- [ -f "./dist/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX)" ] && rm -v ./dist/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX); \
- mv -v ./dist/server/$(TARGETOS)_$(TARGETARCH_XGO)/woodpecker-server* ./dist/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX); \
+ # build via xgo
+ CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -dest ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX) -tags 'netgo osusergo grpcnotrace $(TAGS)' -ldflags '-linkmode external $(LDFLAGS)' -targets '$(TARGETOS)/$(TARGETARCH_XGO)' -out woodpecker-server -pkg cmd/server .
+ # move binary into subfolder depending on target os and arch
+ @if [ "$${XGO_IN_XGO:-0}" -eq "1" ]; then \
+ echo "inside xgo image"; \
+ mkdir -p ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX); \
+ mv -vf /build/woodpecker-server* ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX); \
+ else \
+ echo "outside xgo image"; \
+ [ -f "${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX)" ] && rm -v ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX); \
+ mv -v ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_XGO)/woodpecker-server* ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX); \
+ fi
+ # if enabled package it in an archive
+ @if [ "$${ARCHIVE_IT:-0}" -eq "1" ]; then \
+ if [ "$(BIN_SUFFIX)" = ".exe" ]; then \
+ rm -f ${DIST_DIR}/woodpecker-server_$(TARGETOS)_$(TARGETARCH_BUILDX).zip; \
+ zip -j ${DIST_DIR}/woodpecker-server_$(TARGETOS)_$(TARGETARCH_BUILDX).zip ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server.exe; \
+ else \
+ tar -cvzf ${DIST_DIR}/woodpecker-server_$(TARGETOS)_$(TARGETARCH_BUILDX).tar.gz -C ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX) woodpecker-server$(BIN_SUFFIX); \
+ fi; \
+ else \
+ echo "skip creating '${DIST_DIR}/woodpecker-server_$(TARGETOS)_$(TARGETARCH_BUILDX).tar.gz'"; \
fi
- @[ "$${TARGZ:-0}" -eq "1" ] && tar -cvzf dist/woodpecker-server_$(TARGETOS)_$(TARGETARCH_BUILDX).tar.gz -C dist/server/$(TARGETOS)_$(TARGETARCH_BUILDX) woodpecker-server$(BIN_SUFFIX) || echo "skip creating 'dist/woodpecker-server_$(TARGETOS)_$(TARGETARCH_BUILDX).tar.gz'"
release-server: ## Create server binaries for release
# compile
- GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) CGO_ENABLED=${CGO_ENABLED} go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o dist/server/$(TARGETOS)_$(TARGETARCH)/woodpecker-server$(BIN_SUFFIX) go.woodpecker-ci.org/woodpecker/v2/cmd/server
+ GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) CGO_ENABLED=${CGO_ENABLED} go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH)/woodpecker-server$(BIN_SUFFIX) go.woodpecker-ci.org/woodpecker/v2/cmd/server
# tar binary files
- tar -cvzf dist/woodpecker-server_$(TARGETOS)_$(TARGETARCH).tar.gz -C dist/server/$(TARGETOS)_$(TARGETARCH) woodpecker-server$(BIN_SUFFIX)
+ if [ "$(BIN_SUFFIX)" == ".exe" ]; then \
+ zip -j ${DIST_DIR}/woodpecker-server_$(TARGETOS)_$(TARGETARCH).zip ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH)/woodpecker-server.exe; \
+ else \
+ tar -cvzf ${DIST_DIR}/woodpecker-server_$(TARGETOS)_$(TARGETARCH).tar.gz -C ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH) woodpecker-server$(BIN_SUFFIX); \
+ fi
release-agent: ## Create agent binaries for release
# compile
- GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o dist/agent/linux_amd64/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
- GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o dist/agent/linux_arm64/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
- GOOS=linux GOARCH=arm CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o dist/agent/linux_arm/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
- GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o dist/agent/windows_amd64/woodpecker-agent.exe go.woodpecker-ci.org/woodpecker/v2/cmd/agent
- GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o dist/agent/darwin_amd64/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
- GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o dist/agent/darwin_arm64/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
+ GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o ${DIST_DIR}/agent/linux_amd64/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
+ GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o ${DIST_DIR}/agent/linux_arm64/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
+ GOOS=linux GOARCH=arm CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o ${DIST_DIR}/agent/linux_arm/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
+ GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o ${DIST_DIR}/agent/windows_amd64/woodpecker-agent.exe go.woodpecker-ci.org/woodpecker/v2/cmd/agent
+ GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o ${DIST_DIR}/agent/darwin_amd64/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
+ GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o ${DIST_DIR}/agent/darwin_arm64/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
# tar binary files
- tar -cvzf dist/woodpecker-agent_linux_amd64.tar.gz -C dist/agent/linux_amd64 woodpecker-agent
- tar -cvzf dist/woodpecker-agent_linux_arm64.tar.gz -C dist/agent/linux_arm64 woodpecker-agent
- tar -cvzf dist/woodpecker-agent_linux_arm.tar.gz -C dist/agent/linux_arm woodpecker-agent
- tar -cvzf dist/woodpecker-agent_windows_amd64.tar.gz -C dist/agent/windows_amd64 woodpecker-agent.exe
- tar -cvzf dist/woodpecker-agent_darwin_amd64.tar.gz -C dist/agent/darwin_amd64 woodpecker-agent
- tar -cvzf dist/woodpecker-agent_darwin_arm64.tar.gz -C dist/agent/darwin_arm64 woodpecker-agent
+ tar -cvzf ${DIST_DIR}/woodpecker-agent_linux_amd64.tar.gz -C ${DIST_DIR}/agent/linux_amd64 woodpecker-agent
+ tar -cvzf ${DIST_DIR}/woodpecker-agent_linux_arm64.tar.gz -C ${DIST_DIR}/agent/linux_arm64 woodpecker-agent
+ tar -cvzf ${DIST_DIR}/woodpecker-agent_linux_arm.tar.gz -C ${DIST_DIR}/agent/linux_arm woodpecker-agent
+ tar -cvzf ${DIST_DIR}/woodpecker-agent_darwin_amd64.tar.gz -C ${DIST_DIR}/agent/darwin_amd64 woodpecker-agent
+ tar -cvzf ${DIST_DIR}/woodpecker-agent_darwin_arm64.tar.gz -C ${DIST_DIR}/agent/darwin_arm64 woodpecker-agent
+ # zip binary files
+ rm -f ${DIST_DIR}/woodpecker-agent_windows_amd64.zip
+ zip -j ${DIST_DIR}/woodpecker-agent_windows_amd64.zip ${DIST_DIR}/agent/windows_amd64/woodpecker-agent.exe
release-cli: ## Create cli binaries for release
# compile
- GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o dist/cli/linux_amd64/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
- GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o dist/cli/linux_arm64/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
- GOOS=linux GOARCH=arm CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o dist/cli/linux_arm/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
- GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o dist/cli/windows_amd64/woodpecker-cli.exe go.woodpecker-ci.org/woodpecker/v2/cmd/cli
- GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o dist/cli/darwin_amd64/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
- GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o dist/cli/darwin_arm64/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
+ GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o ${DIST_DIR}/cli/linux_amd64/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
+ GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o ${DIST_DIR}/cli/linux_arm64/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
+ GOOS=linux GOARCH=arm CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o ${DIST_DIR}/cli/linux_arm/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
+ GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o ${DIST_DIR}/cli/windows_amd64/woodpecker-cli.exe go.woodpecker-ci.org/woodpecker/v2/cmd/cli
+ GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o ${DIST_DIR}/cli/darwin_amd64/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
+ GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o ${DIST_DIR}/cli/darwin_arm64/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
# tar binary files
- tar -cvzf dist/woodpecker-cli_linux_amd64.tar.gz -C dist/cli/linux_amd64 woodpecker-cli
- tar -cvzf dist/woodpecker-cli_linux_arm64.tar.gz -C dist/cli/linux_arm64 woodpecker-cli
- tar -cvzf dist/woodpecker-cli_linux_arm.tar.gz -C dist/cli/linux_arm woodpecker-cli
- tar -cvzf dist/woodpecker-cli_windows_amd64.tar.gz -C dist/cli/windows_amd64 woodpecker-cli.exe
- tar -cvzf dist/woodpecker-cli_darwin_amd64.tar.gz -C dist/cli/darwin_amd64 woodpecker-cli
- tar -cvzf dist/woodpecker-cli_darwin_arm64.tar.gz -C dist/cli/darwin_arm64 woodpecker-cli
+ tar -cvzf ${DIST_DIR}/woodpecker-cli_linux_amd64.tar.gz -C ${DIST_DIR}/cli/linux_amd64 woodpecker-cli
+ tar -cvzf ${DIST_DIR}/woodpecker-cli_linux_arm64.tar.gz -C ${DIST_DIR}/cli/linux_arm64 woodpecker-cli
+ tar -cvzf ${DIST_DIR}/woodpecker-cli_linux_arm.tar.gz -C ${DIST_DIR}/cli/linux_arm woodpecker-cli
+ tar -cvzf ${DIST_DIR}/woodpecker-cli_darwin_amd64.tar.gz -C ${DIST_DIR}/cli/darwin_amd64 woodpecker-cli
+ tar -cvzf ${DIST_DIR}/woodpecker-cli_darwin_arm64.tar.gz -C ${DIST_DIR}/cli/darwin_arm64 woodpecker-cli
+ # zip binary files
+ rm -f ${DIST_DIR}/woodpecker-cli_windows_amd64.zip
+ zip -j ${DIST_DIR}/woodpecker-cli_windows_amd64.zip ${DIST_DIR}/cli/windows_amd64/woodpecker-cli.exe
release-checksums: ## Create checksums for all release files
# generate shas for tar files
- (cd dist/; sha256sum *.* > checksums.txt)
+ (cd ${DIST_DIR}/; sha256sum *.* > checksums.txt)
.PHONY: release
release: release-frontend release-server release-agent release-cli ## Release all binaries
@@ -292,16 +316,16 @@ bundle-prepare: ## Prepare the bundles
go install github.com/goreleaser/nfpm/v2/cmd/nfpm@v2.6.0
bundle-agent: bundle-prepare ## Create bundles for agent
- VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/agent.yaml --target ./dist --packager deb
- VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/agent.yaml --target ./dist --packager rpm
+ VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/agent.yaml --target ${DIST_DIR} --packager deb
+ VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/agent.yaml --target ${DIST_DIR} --packager rpm
bundle-server: bundle-prepare ## Create bundles for server
- VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/server.yaml --target ./dist --packager deb
- VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/server.yaml --target ./dist --packager rpm
+ VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/server.yaml --target ${DIST_DIR} --packager deb
+ VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/server.yaml --target ${DIST_DIR} --packager rpm
bundle-cli: bundle-prepare ## Create bundles for cli
- VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/cli.yaml --target ./dist --packager deb
- VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/cli.yaml --target ./dist --packager rpm
+ VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/cli.yaml --target ${DIST_DIR} --packager deb
+ VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/cli.yaml --target ${DIST_DIR} --packager rpm
.PHONY: bundle
bundle: bundle-agent bundle-server bundle-cli ## Create all bundles
diff --git a/README.md b/README.md
index dec158360..1386dc7c1 100644
--- a/README.md
+++ b/README.md
@@ -43,55 +43,48 @@
-Woodpecker is a simple yet powerful CI/CD engine with great extensibility.
+Woodpecker is a simple, yet powerful CI/CD engine with great extensibility.
-![woodpecker](docs/docs/woodpecker.png)
+![woodpecker](docs/woodpecker.png)
-## 🫶 Support
+## Installation & Resources
-Please consider donating and become a backer. 🙏 [[Become a backer](https://opencollective.com/woodpecker-ci#category-CONTRIBUTE)]
+Woodpecker can be installed in various ways (see the [Installation Instructions](https://woodpecker-ci.org/docs/administration/getting-started)) and runs with SQLite as database by default.
+It requires around 100 MB of RAM (Server) and 30 MB (Agent) at runtime in idle mode.
+
+## Support
+
+You can support the project by becoming a backer on [Open Collective](https://opencollective.com/woodpecker-ci#category-CONTRIBUTE) or via [GitHub Sponsors](https://github.com/sponsors/woodpecker-ci).
-## 📖 Documentation
+## Documentation
-
+Our documentation can be found at .
-## ✨ Contribute
+## Translation
-See [Contributing Guide](https://github.com/woodpecker-ci/.github/blob/main/CONTRIBUTING.md)
+We have a self-hosted [Weblate](https://weblate.org/en/) instance at [translate.woodpecker-ci.org](https://translate.woodpecker-ci.org).
-[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://woodpecker-ci.org/docs/next/development/getting-started#gitpod)
+An overview of the current translation state is available at .
-## 📣 Translate
+## Public Woodpecker Instances
-We use an own [Weblate](https://weblate.org/en/) instance at [translate.woodpecker-ci.org](https://translate.woodpecker-ci.org).
+Woodpecker is used as the main CI/CD engine at [Codeberg](https://codeberg.org), an alternative Git hosting platform with a focus on privacy and free software development.
-
-
-
+## Plugins
-## 👋 Who uses Woodpecker?
+Woodpecker can be extended via plugins.
+The [plugin overview website](https://woodpecker-ci.org/plugins) helps browsing available plugins.
+It combines both plugins by the Woodpecker core team and community-maintained ones.
-Woodpecker is used by [itself](https://ci.woodpecker-ci.org/woodpecker/woodpecker-ci/), multiple well-known companies, organizations like [Codeberg](https://codeberg.org), hobbyists and many others.
+## Star History
-Leave a [comment](https://github.com/woodpecker-ci/woodpecker/discussions/2149) if you're using it as well.
-
-Also consider using the topic `WoodpeckerCI` in your repository, so others can learn from your config and use the hashtag `#WoodpeckerCI` when talking about the project on social media!
-
-Here are some places where people mention Woodpecker:
-
-- [GitHub](https://github.com/topics/WoodpeckerCI)
-- [Codeberg](https://codeberg.org/explore/repos?q=woodpeckerci&topic=1)
-- [Twitter](https://twitter.com/search?q=%23WoodpeckerCI&src=typed_query)
-- [Fediverse](https://mastodon.social/tags/WoodpeckerCI)
-
-## ✨ Stars over time
-
-[![Stargazers over time](https://starchart.cc/woodpecker-ci/woodpecker.svg)](https://starchart.cc/woodpecker-ci/woodpecker)
+[![Star History Chart](https://api.star-history.com/svg?repos=woodpecker-ci/woodpecker&type=Date)](https://star-history.com/#woodpecker-ci/woodpecker&Date)
## License
-Woodpecker is Apache 2.0 licensed with the source files in this repository having a header indicating which license they are under and what copyrights apply.
+Woodpecker is Apache 2.0 licensed.
+The source files have a header indicating which license they are under and what copyrights apply.
-Files under the `docs/` folder are licensed under Creative Commons Attribution-ShareAlike 4.0 International Public License.
+Everything in `docs/` is licensed under the Creative Commons Attribution-ShareAlike 4.0 International Public License.
diff --git a/agent/logger.go b/agent/logger.go
index 89ccaf3a5..7e3469fd6 100644
--- a/agent/logger.go
+++ b/agent/logger.go
@@ -26,17 +26,12 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
)
-const (
- // Store not more than 1mb in a log-line as 4mb is the limit of a grpc message
- // and log-lines needs to be parsed by the browsers later on.
- maxLogLineLength = 1024 * 1024 // 1mb
-)
-
func (r *Runner) createLogger(_logger zerolog.Logger, uploads *sync.WaitGroup, workflow *rpc.Workflow) pipeline.Logger {
- return func(step *backend.Step, rc io.Reader) error {
+ return func(step *backend.Step, rc io.ReadCloser) error {
+ defer rc.Close()
+
logger := _logger.With().
Str("image", step.Image).
- Str("workflowID", workflow.ID).
Logger()
uploads.Add(1)
@@ -49,7 +44,7 @@ func (r *Runner) createLogger(_logger zerolog.Logger, uploads *sync.WaitGroup, w
logger.Debug().Msg("log stream opened")
logStream := log.NewLineWriter(r.client, step.UUID, secrets...)
- if err := log.CopyLineByLine(logStream, rc, maxLogLineLength); err != nil {
+ if err := log.CopyLineByLine(logStream, rc, pipeline.MaxLogLineLength); err != nil {
logger.Error().Err(err).Msg("copy limited logStream part")
}
diff --git a/agent/rpc/auth_client_grpc.go b/agent/rpc/auth_client_grpc.go
index 9562f47ea..55c89a41a 100644
--- a/agent/rpc/auth_client_grpc.go
+++ b/agent/rpc/auth_client_grpc.go
@@ -23,6 +23,8 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc/proto"
)
+const authClientTimeout = time.Second * 5
+
type AuthClient struct {
client proto.WoodpeckerAuthClient
conn *grpc.ClientConn
@@ -39,8 +41,8 @@ func NewAuthGrpcClient(conn *grpc.ClientConn, agentToken string, agentID int64)
return client
}
-func (c *AuthClient) Auth() (string, int64, error) {
- ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) //nolint:mnd
+func (c *AuthClient) Auth(ctx context.Context) (string, int64, error) {
+ ctx, cancel := context.WithTimeout(ctx, authClientTimeout)
defer cancel()
req := &proto.AuthRequest{
diff --git a/agent/rpc/auth_interceptor.go b/agent/rpc/auth_interceptor.go
index 1283aa970..17aa2a587 100644
--- a/agent/rpc/auth_interceptor.go
+++ b/agent/rpc/auth_interceptor.go
@@ -30,15 +30,12 @@ type AuthInterceptor struct {
}
// NewAuthInterceptor returns a new auth interceptor.
-func NewAuthInterceptor(
- authClient *AuthClient,
- refreshDuration time.Duration,
-) (*AuthInterceptor, error) {
+func NewAuthInterceptor(ctx context.Context, authClient *AuthClient, refreshDuration time.Duration) (*AuthInterceptor, error) {
interceptor := &AuthInterceptor{
authClient: authClient,
}
- err := interceptor.scheduleRefreshToken(refreshDuration)
+ err := interceptor.scheduleRefreshToken(ctx, refreshDuration)
if err != nil {
return nil, err
}
@@ -78,21 +75,26 @@ func (interceptor *AuthInterceptor) attachToken(ctx context.Context) context.Con
return metadata.AppendToOutgoingContext(ctx, "token", interceptor.accessToken)
}
-func (interceptor *AuthInterceptor) scheduleRefreshToken(refreshDuration time.Duration) error {
- err := interceptor.refreshToken()
+func (interceptor *AuthInterceptor) scheduleRefreshToken(ctx context.Context, refreshInterval time.Duration) error {
+ err := interceptor.refreshToken(ctx)
if err != nil {
return err
}
go func() {
- wait := refreshDuration
+ wait := refreshInterval
+
for {
- time.Sleep(wait)
- err := interceptor.refreshToken()
- if err != nil {
- wait = time.Second
- } else {
- wait = refreshDuration
+ select {
+ case <-ctx.Done():
+ return
+ case <-time.After(wait):
+ err := interceptor.refreshToken(ctx)
+ if err != nil {
+ wait = time.Second
+ } else {
+ wait = refreshInterval
+ }
}
}
}()
@@ -100,8 +102,8 @@ func (interceptor *AuthInterceptor) scheduleRefreshToken(refreshDuration time.Du
return nil
}
-func (interceptor *AuthInterceptor) refreshToken() error {
- accessToken, _, err := interceptor.authClient.Auth()
+func (interceptor *AuthInterceptor) refreshToken(ctx context.Context) error {
+ accessToken, _, err := interceptor.authClient.Auth(ctx)
if err != nil {
return err
}
diff --git a/agent/rpc/client_grpc.go b/agent/rpc/client_grpc.go
index 2ee8f322a..ff6d6d0ec 100644
--- a/agent/rpc/client_grpc.go
+++ b/agent/rpc/client_grpc.go
@@ -25,29 +25,44 @@ import (
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
+ grpcproto "google.golang.org/protobuf/proto"
backend "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc/proto"
)
-// Set grpc version on compile time to compare against server version response.
-const ClientGrpcVersion int32 = proto.Version
+const (
+ // Set grpc version on compile time to compare against server version response.
+ ClientGrpcVersion int32 = proto.Version
+
+ // Maximum size of an outgoing log message.
+ // Picked to prevent it from going over GRPC size limit (4 MiB) with a large safety margin.
+ maxLogBatchSize int = 1 * 1024 * 1024
+
+ // Maximum amount of time between sending consecutive batched log messages.
+ // Controls the delay between the CI job generating a log record, and web users receiving it.
+ maxLogFlushPeriod time.Duration = time.Second
+)
type client struct {
client proto.WoodpeckerClient
conn *grpc.ClientConn
+ logs chan *proto.LogEntry
}
// NewGrpcClient returns a new grpc Client.
-func NewGrpcClient(conn *grpc.ClientConn) rpc.Peer {
+func NewGrpcClient(ctx context.Context, conn *grpc.ClientConn) rpc.Peer {
client := new(client)
client.client = proto.NewWoodpeckerClient(conn)
client.conn = conn
+ client.logs = make(chan *proto.LogEntry, 10) // max memory use: 10 lines * 1 MiB
+ go client.processLogs(ctx)
return client
}
func (c *client) Close() error {
+ close(c.logs)
return c.conn.Close()
}
@@ -72,28 +87,28 @@ func (c *client) Version(ctx context.Context) (*rpc.Version, error) {
}
// Next returns the next workflow in the queue.
-func (c *client) Next(ctx context.Context, f rpc.Filter) (*rpc.Workflow, error) {
+func (c *client) Next(ctx context.Context, filter rpc.Filter) (*rpc.Workflow, error) {
var res *proto.NextResponse
var err error
retry := c.newBackOff()
req := new(proto.NextRequest)
req.Filter = new(proto.Filter)
- req.Filter.Labels = f.Labels
+ req.Filter.Labels = filter.Labels
for {
res, err = c.client.Next(ctx, req)
if err == nil {
break
}
- // TODO: remove after adding continuous data exchange by something like #536
- if strings.Contains(err.Error(), "\"too_many_pings\"") {
- // https://github.com/woodpecker-ci/woodpecker/issues/717#issuecomment-1049365104
- log.Trace().Err(err).Msg("grpc: to many keepalive pings without sending data")
- } else {
- log.Error().Err(err).Msgf("grpc error: done(): code: %v", status.Code(err))
- }
-
switch status.Code(err) {
+ case codes.Canceled:
+ if ctx.Err() != nil {
+ // expected as context was canceled
+ log.Debug().Err(err).Msgf("grpc error: next(): context canceled")
+ return nil, nil
+ }
+ log.Error().Err(err).Msgf("grpc error: next(): code: %v", status.Code(err))
+ return nil, err
case
codes.Aborted,
codes.DataLoss,
@@ -101,14 +116,22 @@ func (c *client) Next(ctx context.Context, f rpc.Filter) (*rpc.Workflow, error)
codes.Internal,
codes.Unavailable:
// non-fatal errors
+ // TODO: remove after adding continuous data exchange by something like #536
+ if strings.Contains(err.Error(), "\"too_many_pings\"") {
+ // https://github.com/woodpecker-ci/woodpecker/issues/717#issuecomment-1049365104
+ log.Trace().Err(err).Msg("grpc: to many keepalive pings without sending data")
+ } else {
+ log.Warn().Err(err).Msgf("grpc error: next(): code: %v", status.Code(err))
+ }
default:
+ log.Error().Err(err).Msgf("grpc error: next(): code: %v", status.Code(err))
return nil, err
}
select {
case <-time.After(retry.NextBackOff()):
case <-ctx.Done():
- return nil, ctx.Err()
+ return nil, nil
}
}
@@ -127,19 +150,25 @@ func (c *client) Next(ctx context.Context, f rpc.Filter) (*rpc.Workflow, error)
}
// Wait blocks until the workflow is complete.
-func (c *client) Wait(ctx context.Context, id string) (err error) {
+func (c *client) Wait(ctx context.Context, workflowID string) (err error) {
retry := c.newBackOff()
req := new(proto.WaitRequest)
- req.Id = id
+ req.Id = workflowID
for {
_, err = c.client.Wait(ctx, req)
if err == nil {
break
}
- log.Error().Err(err).Msgf("grpc error: wait(): code: %v", status.Code(err))
-
switch status.Code(err) {
+ case codes.Canceled:
+ if ctx.Err() != nil {
+ // expected as context was canceled
+ log.Debug().Err(err).Msgf("grpc error: wait(): context canceled")
+ return nil
+ }
+ log.Error().Err(err).Msgf("grpc error: wait(): code: %v", status.Code(err))
+ return err
case
codes.Aborted,
codes.DataLoss,
@@ -147,7 +176,9 @@ func (c *client) Wait(ctx context.Context, id string) (err error) {
codes.Internal,
codes.Unavailable:
// non-fatal errors
+ log.Warn().Err(err).Msgf("grpc error: wait(): code: %v", status.Code(err))
default:
+ log.Error().Err(err).Msgf("grpc error: wait(): code: %v", status.Code(err))
return err
}
@@ -161,17 +192,14 @@ func (c *client) Wait(ctx context.Context, id string) (err error) {
}
// Init signals the workflow is initialized.
-func (c *client) Init(ctx context.Context, id string, state rpc.State) (err error) {
+func (c *client) Init(ctx context.Context, workflowID string, state rpc.WorkflowState) (err error) {
retry := c.newBackOff()
req := new(proto.InitRequest)
- req.Id = id
- req.State = new(proto.State)
- req.State.Error = state.Error
- req.State.ExitCode = int32(state.ExitCode)
- req.State.Exited = state.Exited
- req.State.Finished = state.Finished
+ req.Id = workflowID
+ req.State = new(proto.WorkflowState)
req.State.Started = state.Started
- req.State.StepUuid = state.StepUUID
+ req.State.Finished = state.Finished
+ req.State.Error = state.Error
for {
_, err = c.client.Init(ctx, req)
if err == nil {
@@ -181,6 +209,14 @@ func (c *client) Init(ctx context.Context, id string, state rpc.State) (err erro
log.Error().Err(err).Msgf("grpc error: init(): code: %v", status.Code(err))
switch status.Code(err) {
+ case codes.Canceled:
+ if ctx.Err() != nil {
+ // expected as context was canceled
+ log.Debug().Err(err).Msgf("grpc error: init(): context canceled")
+ return nil
+ }
+ log.Error().Err(err).Msgf("grpc error: init(): code: %v", status.Code(err))
+ return err
case
codes.Aborted,
codes.DataLoss,
@@ -188,7 +224,9 @@ func (c *client) Init(ctx context.Context, id string, state rpc.State) (err erro
codes.Internal,
codes.Unavailable:
// non-fatal errors
+ log.Warn().Err(err).Msgf("grpc error: init(): code: %v", status.Code(err))
default:
+ log.Error().Err(err).Msgf("grpc error: init(): code: %v", status.Code(err))
return err
}
@@ -201,18 +239,15 @@ func (c *client) Init(ctx context.Context, id string, state rpc.State) (err erro
return nil
}
-// Done signals the work is complete.
-func (c *client) Done(ctx context.Context, id string, state rpc.State) (err error) {
+// Done signals the workflow is complete.
+func (c *client) Done(ctx context.Context, workflowID string, state rpc.WorkflowState) (err error) {
retry := c.newBackOff()
req := new(proto.DoneRequest)
- req.Id = id
- req.State = new(proto.State)
- req.State.Error = state.Error
- req.State.ExitCode = int32(state.ExitCode)
- req.State.Exited = state.Exited
- req.State.Finished = state.Finished
+ req.Id = workflowID
+ req.State = new(proto.WorkflowState)
req.State.Started = state.Started
- req.State.StepUuid = state.StepUUID
+ req.State.Finished = state.Finished
+ req.State.Error = state.Error
for {
_, err = c.client.Done(ctx, req)
if err == nil {
@@ -222,6 +257,14 @@ func (c *client) Done(ctx context.Context, id string, state rpc.State) (err erro
log.Error().Err(err).Msgf("grpc error: done(): code: %v", status.Code(err))
switch status.Code(err) {
+ case codes.Canceled:
+ if ctx.Err() != nil {
+ // expected as context was canceled
+ log.Debug().Err(err).Msgf("grpc error: done(): context canceled")
+ return nil
+ }
+ log.Error().Err(err).Msgf("grpc error: done(): code: %v", status.Code(err))
+ return err
case
codes.Aborted,
codes.DataLoss,
@@ -229,7 +272,9 @@ func (c *client) Done(ctx context.Context, id string, state rpc.State) (err erro
codes.Internal,
codes.Unavailable:
// non-fatal errors
+ log.Warn().Err(err).Msgf("grpc error: done(): code: %v", status.Code(err))
default:
+ log.Error().Err(err).Msgf("grpc error: done(): code: %v", status.Code(err))
return err
}
@@ -243,10 +288,10 @@ func (c *client) Done(ctx context.Context, id string, state rpc.State) (err erro
}
// Extend extends the workflow deadline.
-func (c *client) Extend(ctx context.Context, id string) (err error) {
+func (c *client) Extend(ctx context.Context, workflowID string) (err error) {
retry := c.newBackOff()
req := new(proto.ExtendRequest)
- req.Id = id
+ req.Id = workflowID
for {
_, err = c.client.Extend(ctx, req)
if err == nil {
@@ -256,6 +301,14 @@ func (c *client) Extend(ctx context.Context, id string) (err error) {
log.Error().Err(err).Msgf("grpc error: extend(): code: %v", status.Code(err))
switch status.Code(err) {
+ case codes.Canceled:
+ if ctx.Err() != nil {
+ // expected as context was canceled
+ log.Debug().Err(err).Msgf("grpc error: extend(): context canceled")
+ return nil
+ }
+ log.Error().Err(err).Msgf("grpc error: extend(): code: %v", status.Code(err))
+ return err
case
codes.Aborted,
codes.DataLoss,
@@ -263,7 +316,9 @@ func (c *client) Extend(ctx context.Context, id string) (err error) {
codes.Internal,
codes.Unavailable:
// non-fatal errors
+ log.Warn().Err(err).Msgf("grpc error: extend(): code: %v", status.Code(err))
default:
+ log.Error().Err(err).Msgf("grpc error: extend(): code: %v", status.Code(err))
return err
}
@@ -277,17 +332,17 @@ func (c *client) Extend(ctx context.Context, id string) (err error) {
}
// Update updates the workflow state.
-func (c *client) Update(ctx context.Context, id string, state rpc.State) (err error) {
+func (c *client) Update(ctx context.Context, workflowID string, state rpc.StepState) (err error) {
retry := c.newBackOff()
req := new(proto.UpdateRequest)
- req.Id = id
- req.State = new(proto.State)
- req.State.Error = state.Error
- req.State.ExitCode = int32(state.ExitCode)
- req.State.Exited = state.Exited
- req.State.Finished = state.Finished
- req.State.Started = state.Started
+ req.Id = workflowID
+ req.State = new(proto.StepState)
req.State.StepUuid = state.StepUUID
+ req.State.Started = state.Started
+ req.State.Finished = state.Finished
+ req.State.Exited = state.Exited
+ req.State.ExitCode = int32(state.ExitCode)
+ req.State.Error = state.Error
for {
_, err = c.client.Update(ctx, req)
if err == nil {
@@ -297,6 +352,14 @@ func (c *client) Update(ctx context.Context, id string, state rpc.State) (err er
log.Error().Err(err).Msgf("grpc error: update(): code: %v", status.Code(err))
switch status.Code(err) {
+ case codes.Canceled:
+ if ctx.Err() != nil {
+ // expected as context was canceled
+ log.Debug().Err(err).Msgf("grpc error: update(): context canceled")
+ return nil
+ }
+ log.Error().Err(err).Msgf("grpc error: update(): code: %v", status.Code(err))
+ return err
case
codes.Aborted,
codes.DataLoss,
@@ -304,7 +367,9 @@ func (c *client) Update(ctx context.Context, id string, state rpc.State) (err er
codes.Internal,
codes.Unavailable:
// non-fatal errors
+ log.Warn().Err(err).Msgf("grpc error: update(): code: %v", status.Code(err))
default:
+ log.Error().Err(err).Msgf("grpc error: update(): code: %v", status.Code(err))
return err
}
@@ -317,25 +382,82 @@ func (c *client) Update(ctx context.Context, id string, state rpc.State) (err er
return nil
}
-// Log writes the workflow log entry.
-func (c *client) Log(ctx context.Context, logEntry *rpc.LogEntry) (err error) {
- retry := c.newBackOff()
- req := new(proto.LogRequest)
- req.LogEntry = new(proto.LogEntry)
- req.LogEntry.StepUuid = logEntry.StepUUID
- req.LogEntry.Data = logEntry.Data
- req.LogEntry.Line = int32(logEntry.Line)
- req.LogEntry.Time = logEntry.Time
- req.LogEntry.Type = int32(logEntry.Type)
+// EnqueueLog queues the log entry to be written in a batch later.
+func (c *client) EnqueueLog(logEntry *rpc.LogEntry) {
+ c.logs <- &proto.LogEntry{
+ StepUuid: logEntry.StepUUID,
+ Data: logEntry.Data,
+ Line: int32(logEntry.Line),
+ Time: logEntry.Time,
+ Type: int32(logEntry.Type),
+ }
+}
+
+func (c *client) processLogs(ctx context.Context) {
+ var entries []*proto.LogEntry
+ var bytes int
+
+ send := func() {
+ if len(entries) == 0 {
+ return
+ }
+
+ log.Debug().
+ Int("entries", len(entries)).
+ Int("bytes", bytes).
+ Msg("log drain: sending queued logs")
+
+ if err := c.sendLogs(ctx, entries); err != nil {
+ log.Error().Err(err).Msg("log drain: could not send logs to server")
+ }
+
+ // even if send failed, we don't have infinite memory; retry has already been used
+ entries = entries[:0]
+ bytes = 0
+ }
+
+ // ctx.Done() is covered by the log channel being closed
for {
- _, err = c.client.Log(ctx, req)
+ select {
+ case entry, ok := <-c.logs:
+ if !ok {
+ log.Info().Msg("log drain: channel closed")
+ send()
+ return
+ }
+
+ entries = append(entries, entry)
+ bytes += grpcproto.Size(entry) // cspell:words grpcproto
+
+ if bytes >= maxLogBatchSize {
+ send()
+ }
+
+ case <-time.After(maxLogFlushPeriod):
+ send()
+ }
+ }
+}
+
+func (c *client) sendLogs(ctx context.Context, entries []*proto.LogEntry) error {
+ req := &proto.LogRequest{LogEntries: entries}
+ retry := c.newBackOff()
+
+ for {
+ _, err := c.client.Log(ctx, req)
if err == nil {
break
}
- log.Error().Err(err).Msgf("grpc error: log(): code: %v", status.Code(err))
-
switch status.Code(err) {
+ case codes.Canceled:
+ if ctx.Err() != nil {
+ // expected as context was canceled
+ log.Debug().Err(err).Msgf("grpc error: log(): context canceled")
+ return nil
+ }
+ log.Error().Err(err).Msgf("grpc error: log(): code: %v", status.Code(err))
+ return err
case
codes.Aborted,
codes.DataLoss,
@@ -343,7 +465,9 @@ func (c *client) Log(ctx context.Context, logEntry *rpc.LogEntry) (err error) {
codes.Internal,
codes.Unavailable:
// non-fatal errors
+ log.Warn().Err(err).Msgf("grpc error: log(): code: %v", status.Code(err))
default:
+ log.Error().Err(err).Msgf("grpc error: log(): code: %v", status.Code(err))
return err
}
@@ -383,6 +507,14 @@ func (c *client) ReportHealth(ctx context.Context) (err error) {
return nil
}
switch status.Code(err) {
+ case codes.Canceled:
+ if ctx.Err() != nil {
+ // expected as context was canceled
+ log.Debug().Err(err).Msgf("grpc error: report_health(): context canceled")
+ return nil
+ }
+ log.Error().Err(err).Msgf("grpc error: report_health(): code: %v", status.Code(err))
+ return err
case
codes.Aborted,
codes.DataLoss,
@@ -390,7 +522,9 @@ func (c *client) ReportHealth(ctx context.Context) (err error) {
codes.Internal,
codes.Unavailable:
// non-fatal errors
+ log.Warn().Err(err).Msgf("grpc error: report_health(): code: %v", status.Code(err))
default:
+ log.Error().Err(err).Msgf("grpc error: report_health(): code: %v", status.Code(err))
return err
}
diff --git a/agent/runner.go b/agent/runner.go
index 2d96ff41b..27363aa66 100644
--- a/agent/runner.go
+++ b/agent/runner.go
@@ -23,12 +23,12 @@ import (
"time"
"github.com/rs/zerolog/log"
- "github.com/tevino/abool/v2"
"google.golang.org/grpc/metadata"
"go.woodpecker-ci.org/woodpecker/v2/pipeline"
backend "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
+ "go.woodpecker-ci.org/woodpecker/v2/shared/constant"
"go.woodpecker-ci.org/woodpecker/v2/shared/utils"
)
@@ -50,41 +50,41 @@ func NewRunner(workEngine rpc.Peer, f rpc.Filter, h string, state *State, backen
}
}
-func (r *Runner) Run(runnerCtx context.Context) error { //nolint:contextcheck
+func (r *Runner) Run(runnerCtx, shutdownCtx context.Context) error { //nolint:contextcheck
log.Debug().Msg("request next execution")
meta, _ := metadata.FromOutgoingContext(runnerCtx)
ctxMeta := metadata.NewOutgoingContext(context.Background(), meta)
// get the next workflow from the queue
- work, err := r.client.Next(runnerCtx, r.filter)
+ workflow, err := r.client.Next(runnerCtx, r.filter)
if err != nil {
return err
}
- if work == nil {
+ if workflow == nil {
return nil
}
timeout := time.Hour
- if minutes := work.Timeout; minutes != 0 {
+ if minutes := workflow.Timeout; minutes != 0 {
timeout = time.Duration(minutes) * time.Minute
}
- repoName := extractRepositoryName(work.Config) // hack
- pipelineNumber := extractPipelineNumber(work.Config) // hack
+ repoName := extractRepositoryName(workflow.Config) // hack
+ pipelineNumber := extractPipelineNumber(workflow.Config) // hack
r.counter.Add(
- work.ID,
+ workflow.ID,
timeout,
repoName,
pipelineNumber,
)
- defer r.counter.Done(work.ID)
+ defer r.counter.Done(workflow.ID)
logger := log.With().
Str("repo", repoName).
Str("pipeline", pipelineNumber).
- Str("id", work.ID).
+ Str("workflow_id", workflow.ID).
Logger()
logger.Debug().Msg("received execution")
@@ -99,17 +99,16 @@ func (r *Runner) Run(runnerCtx context.Context) error { //nolint:contextcheck
logger.Error().Msg("Received sigterm termination signal")
})
- canceled := abool.New()
+ canceled := false
go func() {
logger.Debug().Msg("listen for cancel signal")
- if err := r.client.Wait(workflowCtx, work.ID); err != nil {
- canceled.SetTo(true)
+ if err := r.client.Wait(workflowCtx, workflow.ID); err != nil {
+ canceled = true
logger.Warn().Err(err).Msg("cancel signal received")
-
cancel()
} else {
- logger.Debug().Msg("stop listening for cancel signal")
+ logger.Debug().Msg("done listening for cancel signal")
}
}()
@@ -118,81 +117,74 @@ func (r *Runner) Run(runnerCtx context.Context) error { //nolint:contextcheck
select {
case <-workflowCtx.Done():
logger.Debug().Msg("pipeline done")
-
return
- case <-time.After(time.Minute):
- logger.Debug().Msg("pipeline lease renewed")
- if err := r.client.Extend(workflowCtx, work.ID); err != nil {
+ case <-time.After(constant.TaskTimeout / 3):
+ logger.Debug().Msg("pipeline lease renewed")
+ if err := r.client.Extend(workflowCtx, workflow.ID); err != nil {
log.Error().Err(err).Msg("extending pipeline deadline failed")
}
}
}
}()
- state := rpc.State{}
+ state := rpc.WorkflowState{}
state.Started = time.Now().Unix()
- err = r.client.Init(runnerCtx, work.ID, state)
+ err = r.client.Init(runnerCtx, workflow.ID, state)
if err != nil {
- logger.Error().Err(err).Msg("pipeline initialization failed")
+ logger.Error().Err(err).Msg("workflow initialization failed")
+ // TODO: should we return here?
}
var uploads sync.WaitGroup
//nolint:contextcheck
- err = pipeline.New(work.Config,
+ err = pipeline.New(workflow.Config,
pipeline.WithContext(workflowCtx),
- pipeline.WithTaskUUID(fmt.Sprint(work.ID)),
- pipeline.WithLogger(r.createLogger(logger, &uploads, work)),
- pipeline.WithTracer(r.createTracer(ctxMeta, logger, work)),
+ pipeline.WithTaskUUID(fmt.Sprint(workflow.ID)),
+ pipeline.WithLogger(r.createLogger(logger, &uploads, workflow)),
+ pipeline.WithTracer(r.createTracer(ctxMeta, &uploads, logger, workflow)),
pipeline.WithBackend(*r.backend),
pipeline.WithDescription(map[string]string{
- "ID": work.ID,
- "Repo": repoName,
- "Pipeline": pipelineNumber,
+ "workflow_id": workflow.ID,
+ "repo": repoName,
+ "pipeline_number": pipelineNumber,
}),
).Run(runnerCtx)
state.Finished = time.Now().Unix()
- state.Exited = true
- if canceled.IsSet() {
- state.Error = ""
- state.ExitCode = pipeline.ExitCodeKilled
- } else if err != nil {
- pExitError := &pipeline.ExitError{}
- switch {
- case errors.As(err, &pExitError):
- state.ExitCode = pExitError.Code
- case errors.Is(err, pipeline.ErrCancel):
- state.Error = ""
- state.ExitCode = pipeline.ExitCodeKilled
- canceled.SetTo(true)
- default:
- state.ExitCode = 1
- state.Error = err.Error()
- }
+ if errors.Is(err, pipeline.ErrCancel) {
+ canceled = true
+ } else if canceled {
+ err = errors.Join(err, pipeline.ErrCancel)
+ }
+
+ if err != nil {
+ state.Error = err.Error()
}
logger.Debug().
Str("error", state.Error).
- Int("exit_code", state.ExitCode).
- Bool("canceled", canceled.IsSet()).
- Msg("pipeline complete")
+ Bool("canceled", canceled).
+ Msg("workflow finished")
- logger.Debug().Msg("uploading logs")
+ logger.Debug().Msg("uploading logs and traces / states ...")
uploads.Wait()
- logger.Debug().Msg("uploading logs complete")
+ logger.Debug().Msg("uploaded logs and traces / states")
logger.Debug().
Str("error", state.Error).
- Int("exit_code", state.ExitCode).
- Msg("updating pipeline status")
+ Msg("updating workflow status")
- if err := r.client.Done(runnerCtx, work.ID, state); err != nil {
- logger.Error().Err(err).Msg("updating pipeline status failed")
+ doneCtx := runnerCtx
+ if doneCtx.Err() != nil {
+ doneCtx = shutdownCtx
+ }
+ if err := r.client.Done(doneCtx, workflow.ID, state); err != nil {
+ logger.Error().Err(err).Msg("updating workflow status failed")
} else {
- logger.Debug().Msg("updating pipeline status complete")
+ logger.Debug().Msg("updating workflow status complete")
}
return nil
diff --git a/agent/tracer.go b/agent/tracer.go
index 985c185d0..ff8f23c38 100644
--- a/agent/tracer.go
+++ b/agent/tracer.go
@@ -18,6 +18,7 @@ import (
"context"
"runtime"
"strconv"
+ "sync"
"time"
"github.com/rs/zerolog"
@@ -26,17 +27,19 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
)
-func (r *Runner) createTracer(ctxMeta context.Context, logger zerolog.Logger, workflow *rpc.Workflow) pipeline.TraceFunc {
+func (r *Runner) createTracer(ctxMeta context.Context, uploads *sync.WaitGroup, logger zerolog.Logger, workflow *rpc.Workflow) pipeline.TraceFunc {
return func(state *pipeline.State) error {
+ uploads.Add(1)
+
stepLogger := logger.With().
Str("image", state.Pipeline.Step.Image).
- Str("workflowID", workflow.ID).
+ Str("workflow_id", workflow.ID).
Err(state.Process.Error).
Int("exit_code", state.Process.ExitCode).
Bool("exited", state.Process.Exited).
Logger()
- stepState := rpc.State{
+ stepState := rpc.StepState{
StepUUID: state.Pipeline.Step.UUID,
Exited: state.Process.Exited,
ExitCode: state.Process.ExitCode,
@@ -57,6 +60,7 @@ func (r *Runner) createTracer(ctxMeta context.Context, logger zerolog.Logger, wo
}
stepLogger.Debug().Msg("update step status complete")
+ uploads.Done()
}()
if state.Process.Exited {
return nil
@@ -68,21 +72,12 @@ func (r *Runner) createTracer(ctxMeta context.Context, logger zerolog.Logger, wo
// TODO: find better way to update this state and move it to pipeline to have the same env in cli-exec
state.Pipeline.Step.Environment["CI_MACHINE"] = r.hostname
- state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "success"
- state.Pipeline.Step.Environment["CI_PIPELINE_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10)
- state.Pipeline.Step.Environment["CI_PIPELINE_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
+ state.Pipeline.Step.Environment["CI_PIPELINE_STARTED"] = strconv.FormatInt(state.Pipeline.Started, 10)
- state.Pipeline.Step.Environment["CI_STEP_STATUS"] = "success"
- state.Pipeline.Step.Environment["CI_STEP_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10)
- state.Pipeline.Step.Environment["CI_STEP_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
+ state.Pipeline.Step.Environment["CI_STEP_STARTED"] = strconv.FormatInt(state.Pipeline.Started, 10)
state.Pipeline.Step.Environment["CI_SYSTEM_PLATFORM"] = runtime.GOOS + "/" + runtime.GOARCH
- if state.Pipeline.Error != nil {
- state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "failure"
- state.Pipeline.Step.Environment["CI_STEP_STATUS"] = "failure"
- }
-
return nil
}
}
diff --git a/server/store/datastore/migration/005_repos_drop_repo_counter.go b/cli/admin/admin.go
similarity index 59%
rename from server/store/datastore/migration/005_repos_drop_repo_counter.go
rename to cli/admin/admin.go
index dc1785e0c..351efc0d5 100644
--- a/server/store/datastore/migration/005_repos_drop_repo_counter.go
+++ b/cli/admin/admin.go
@@ -1,10 +1,10 @@
-// Copyright 2021 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.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -12,16 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package migration
+package admin
import (
- "src.techknowlogick.com/xormigrate"
- "xorm.io/xorm"
+ "github.com/urfave/cli/v3"
+
+ "go.woodpecker-ci.org/woodpecker/v2/cli/admin/registry"
)
-var alterTableReposDropCounter = xormigrate.Migration{
- ID: "alter-table-drop-counter",
- MigrateSession: func(sess *xorm.Session) error {
- return dropTableColumns(sess, "repos", "repo_counter")
+// Command exports the admin command set.
+var Command = &cli.Command{
+ Name: "admin",
+ Usage: "administer server settings",
+ Commands: []*cli.Command{
+ registry.Command,
},
}
diff --git a/cli/registry/registry.go b/cli/admin/registry/registry.go
similarity index 86%
rename from cli/registry/registry.go
rename to cli/admin/registry/registry.go
index eb8a7d796..3d9c4de50 100644
--- a/cli/registry/registry.go
+++ b/cli/admin/registry/registry.go
@@ -1,4 +1,4 @@
-// Copyright 2023 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.
@@ -15,14 +15,14 @@
package registry
import (
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
)
// Command exports the registry command set.
var Command = &cli.Command{
Name: "registry",
- Usage: "manage registries",
- Subcommands: []*cli.Command{
+ Usage: "manage global registries",
+ Commands: []*cli.Command{
registryCreateCmd,
registryDeleteCmd,
registryUpdateCmd,
diff --git a/cli/admin/registry/registry_add.go b/cli/admin/registry/registry_add.go
new file mode 100644
index 000000000..a378a8a2f
--- /dev/null
+++ b/cli/admin/registry/registry_add.go
@@ -0,0 +1,76 @@
+// 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 registry
+
+import (
+ "context"
+ "os"
+ "strings"
+
+ "github.com/urfave/cli/v3"
+
+ "go.woodpecker-ci.org/woodpecker/v2/cli/internal"
+ "go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
+)
+
+var registryCreateCmd = &cli.Command{
+ Name: "add",
+ Usage: "adds a registry",
+ Action: registryCreate,
+ Flags: []cli.Flag{
+ &cli.StringFlag{
+ Name: "hostname",
+ Usage: "registry hostname",
+ Value: "docker.io",
+ },
+ &cli.StringFlag{
+ Name: "username",
+ Usage: "registry username",
+ },
+ &cli.StringFlag{
+ Name: "password",
+ Usage: "registry password",
+ },
+ },
+}
+
+func registryCreate(ctx context.Context, c *cli.Command) error {
+ var (
+ hostname = c.String("hostname")
+ username = c.String("username")
+ password = c.String("password")
+ )
+
+ client, err := internal.NewClient(ctx, c)
+ if err != nil {
+ return err
+ }
+ registry := &woodpecker.Registry{
+ Address: hostname,
+ Username: username,
+ Password: password,
+ }
+ if strings.HasPrefix(registry.Password, "@") {
+ path := strings.TrimPrefix(registry.Password, "@")
+ out, err := os.ReadFile(path)
+ if err != nil {
+ return err
+ }
+ registry.Password = string(out)
+ }
+
+ _, err = client.GlobalRegistryCreate(registry)
+ return err
+}
diff --git a/cli/admin/registry/registry_info.go b/cli/admin/registry/registry_info.go
new file mode 100644
index 000000000..80b78546f
--- /dev/null
+++ b/cli/admin/registry/registry_info.go
@@ -0,0 +1,63 @@
+// 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 registry
+
+import (
+ "context"
+ "html/template"
+ "os"
+
+ "github.com/urfave/cli/v3"
+
+ "go.woodpecker-ci.org/woodpecker/v2/cli/common"
+ "go.woodpecker-ci.org/woodpecker/v2/cli/internal"
+)
+
+var registryInfoCmd = &cli.Command{
+ Name: "info",
+ Usage: "display registry info",
+ Action: registryInfo,
+ Flags: []cli.Flag{
+ &cli.StringFlag{
+ Name: "hostname",
+ Usage: "registry hostname",
+ Value: "docker.io",
+ },
+ common.FormatFlag(tmplRegistryList, true),
+ },
+}
+
+func registryInfo(ctx context.Context, c *cli.Command) error {
+ var (
+ hostname = c.String("hostname")
+ format = c.String("format") + "\n"
+ )
+
+ client, err := internal.NewClient(ctx, c)
+ if err != nil {
+ return err
+ }
+
+ registry, err := client.GlobalRegistry(hostname)
+ if err != nil {
+ return err
+ }
+
+ tmpl, err := template.New("_").Parse(format)
+ if err != nil {
+ return err
+ }
+ return tmpl.Execute(os.Stdout, registry)
+}
diff --git a/cli/admin/registry/registry_list.go b/cli/admin/registry/registry_list.go
new file mode 100644
index 000000000..6f5788967
--- /dev/null
+++ b/cli/admin/registry/registry_list.go
@@ -0,0 +1,66 @@
+// 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 registry
+
+import (
+ "context"
+ "html/template"
+ "os"
+
+ "github.com/urfave/cli/v3"
+
+ "go.woodpecker-ci.org/woodpecker/v2/cli/common"
+ "go.woodpecker-ci.org/woodpecker/v2/cli/internal"
+)
+
+var registryListCmd = &cli.Command{
+ Name: "ls",
+ Usage: "list registries",
+ Action: registryList,
+ Flags: []cli.Flag{
+ common.FormatFlag(tmplRegistryList, true),
+ },
+}
+
+func registryList(ctx context.Context, c *cli.Command) error {
+ format := c.String("format") + "\n"
+
+ client, err := internal.NewClient(ctx, c)
+ if err != nil {
+ return err
+ }
+
+ list, err := client.GlobalRegistryList()
+ if err != nil {
+ return err
+ }
+
+ tmpl, err := template.New("_").Parse(format)
+ if err != nil {
+ return err
+ }
+ for _, registry := range list {
+ if err := tmpl.Execute(os.Stdout, registry); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Template for registry list information.
+var tmplRegistryList = "\x1b[33m{{ .Address }} \x1b[0m" + `
+Username: {{ .Username }}
+Email: {{ .Email }}
+`
diff --git a/cli/admin/registry/registry_rm.go b/cli/admin/registry/registry_rm.go
new file mode 100644
index 000000000..3dfb02c1f
--- /dev/null
+++ b/cli/admin/registry/registry_rm.go
@@ -0,0 +1,47 @@
+// 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 registry
+
+import (
+ "context"
+
+ "github.com/urfave/cli/v3"
+
+ "go.woodpecker-ci.org/woodpecker/v2/cli/internal"
+)
+
+var registryDeleteCmd = &cli.Command{
+ Name: "rm",
+ Usage: "remove a registry",
+ Action: registryDelete,
+ Flags: []cli.Flag{
+ &cli.StringFlag{
+ Name: "hostname",
+ Usage: "registry hostname",
+ Value: "docker.io",
+ },
+ },
+}
+
+func registryDelete(ctx context.Context, c *cli.Command) error {
+ hostname := c.String("hostname")
+
+ client, err := internal.NewClient(ctx, c)
+ if err != nil {
+ return err
+ }
+
+ return client.GlobalRegistryDelete(hostname)
+}
diff --git a/cli/admin/registry/registry_set.go b/cli/admin/registry/registry_set.go
new file mode 100644
index 000000000..4196a982d
--- /dev/null
+++ b/cli/admin/registry/registry_set.go
@@ -0,0 +1,79 @@
+// 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 registry
+
+import (
+ "context"
+ "os"
+ "strings"
+
+ "github.com/urfave/cli/v3"
+
+ "go.woodpecker-ci.org/woodpecker/v2/cli/common"
+ "go.woodpecker-ci.org/woodpecker/v2/cli/internal"
+ "go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
+)
+
+var registryUpdateCmd = &cli.Command{
+ Name: "update",
+ Usage: "update a registry",
+ Action: registryUpdate,
+ Flags: []cli.Flag{
+ common.OrgFlag,
+ &cli.StringFlag{
+ Name: "hostname",
+ Usage: "registry hostname",
+ Value: "docker.io",
+ },
+ &cli.StringFlag{
+ Name: "username",
+ Usage: "registry username",
+ },
+ &cli.StringFlag{
+ Name: "password",
+ Usage: "registry password",
+ },
+ },
+}
+
+func registryUpdate(ctx context.Context, c *cli.Command) error {
+ var (
+ hostname = c.String("hostname")
+ username = c.String("username")
+ password = c.String("password")
+ )
+
+ client, err := internal.NewClient(ctx, c)
+ if err != nil {
+ return err
+ }
+
+ registry := &woodpecker.Registry{
+ Address: hostname,
+ Username: username,
+ Password: password,
+ }
+ if strings.HasPrefix(registry.Password, "@") {
+ path := strings.TrimPrefix(registry.Password, "@")
+ out, err := os.ReadFile(path)
+ if err != nil {
+ return err
+ }
+ registry.Password = string(out)
+ }
+
+ _, err = client.GlobalRegistryUpdate(registry)
+ return err
+}
diff --git a/cli/common/flags.go b/cli/common/flags.go
index 6a7431249..4b81505a9 100644
--- a/cli/common/flags.go
+++ b/cli/common/flags.go
@@ -15,49 +15,49 @@
package common
import (
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/shared/logger"
)
var GlobalFlags = append([]cli.Flag{
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_CONFIG"},
+ Sources: cli.EnvVars("WOODPECKER_CONFIG"),
Name: "config",
Aliases: []string{"c"},
Usage: "path to config file",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_SERVER"},
+ Sources: cli.EnvVars("WOODPECKER_SERVER"),
Name: "server",
Aliases: []string{"s"},
Usage: "server address",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_TOKEN"},
+ Sources: cli.EnvVars("WOODPECKER_TOKEN"),
Name: "token",
Aliases: []string{"t"},
Usage: "server auth token",
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_DISABLE_UPDATE_CHECK"},
+ Sources: cli.EnvVars("WOODPECKER_DISABLE_UPDATE_CHECK"),
Name: "disable-update-check",
Usage: "disable update check",
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_SKIP_VERIFY"},
+ Sources: cli.EnvVars("WOODPECKER_SKIP_VERIFY"),
Name: "skip-verify",
Usage: "skip ssl verification",
Hidden: true,
},
&cli.StringFlag{
- EnvVars: []string{"SOCKS_PROXY"},
+ Sources: cli.EnvVars("SOCKS_PROXY"),
Name: "socks-proxy",
Usage: "socks proxy address",
Hidden: true,
},
&cli.BoolFlag{
- EnvVars: []string{"SOCKS_PROXY_OFF"},
+ Sources: cli.EnvVars("SOCKS_PROXY_OFF"),
Name: "socks-proxy-off",
Usage: "socks proxy ignored",
Hidden: true,
diff --git a/cli/common/hooks.go b/cli/common/hooks.go
index 952742cba..7a5443538 100644
--- a/cli/common/hooks.go
+++ b/cli/common/hooks.go
@@ -6,7 +6,7 @@ import (
"time"
"github.com/rs/zerolog/log"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal/config"
"go.woodpecker-ci.org/woodpecker/v2/cli/update"
@@ -17,12 +17,12 @@ var (
cancelWaitForUpdate context.CancelCauseFunc
)
-func Before(c *cli.Context) error {
- if err := setupGlobalLogger(c); err != nil {
+func Before(ctx context.Context, c *cli.Command) error {
+ if err := setupGlobalLogger(ctx, c); err != nil {
return err
}
- go func() {
+ go func(context.Context) {
if c.Bool("disable-update-check") {
return
}
@@ -37,23 +37,23 @@ func Before(c *cli.Context) error {
log.Debug().Msg("Checking for updates ...")
- newVersion, err := update.CheckForUpdate(waitForUpdateCheck, false)
+ newVersion, err := update.CheckForUpdate(waitForUpdateCheck, false) //nolint:contextcheck
if err != nil {
log.Error().Err(err).Msgf("Failed to check for updates")
return
}
if newVersion != nil {
- log.Warn().Msgf("A new version of woodpecker-cli is available: %s. Update by running: %s update", newVersion.Version, c.App.Name)
+ log.Warn().Msgf("A new version of woodpecker-cli is available: %s. Update by running: %s update", newVersion.Version, c.Root().Name)
} else {
log.Debug().Msgf("No update required")
}
- }()
+ }(ctx)
- return config.Load(c)
+ return config.Load(ctx, c)
}
-func After(_ *cli.Context) error {
+func After(_ context.Context, _ *cli.Command) error {
if waitForUpdateCheck != nil {
select {
case <-waitForUpdateCheck.Done():
diff --git a/cli/common/pipeline.go b/cli/common/pipeline.go
index b479e5693..fba8cb54a 100644
--- a/cli/common/pipeline.go
+++ b/cli/common/pipeline.go
@@ -15,11 +15,12 @@
package common
import (
+ "context"
"fmt"
"os"
"strings"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/shared/constant"
)
@@ -37,16 +38,16 @@ func DetectPipelineConfig() (isDir bool, config string, _ error) {
return false, "", fmt.Errorf("could not detect pipeline config")
}
-func RunPipelineFunc(c *cli.Context, fileFunc, dirFunc func(*cli.Context, string) error) error {
+func RunPipelineFunc(ctx context.Context, c *cli.Command, fileFunc, dirFunc func(context.Context, *cli.Command, string) error) error {
if c.Args().Len() == 0 {
isDir, path, err := DetectPipelineConfig()
if err != nil {
return err
}
if isDir {
- return dirFunc(c, path)
+ return dirFunc(ctx, c, path)
}
- return fileFunc(c, path)
+ return fileFunc(ctx, c, path)
}
multiArgs := c.Args().Len() > 1
@@ -59,11 +60,11 @@ func RunPipelineFunc(c *cli.Context, fileFunc, dirFunc func(*cli.Context, string
fmt.Println("#", fi.Name())
}
if fi.IsDir() {
- if err := dirFunc(c, arg); err != nil {
+ if err := dirFunc(ctx, c, arg); err != nil {
return err
}
} else {
- if err := fileFunc(c, arg); err != nil {
+ if err := fileFunc(ctx, c, arg); err != nil {
return err
}
}
diff --git a/cli/common/zerologger.go b/cli/common/zerologger.go
index d3e275898..7c932c83d 100644
--- a/cli/common/zerologger.go
+++ b/cli/common/zerologger.go
@@ -15,11 +15,13 @@
package common
import (
- "github.com/urfave/cli/v2"
+ "context"
+
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/shared/logger"
)
-func setupGlobalLogger(c *cli.Context) error {
- return logger.SetupGlobalLogger(c, false)
+func setupGlobalLogger(ctx context.Context, c *cli.Command) error {
+ return logger.SetupGlobalLogger(ctx, c, false)
}
diff --git a/cli/cron/cron.go b/cli/cron/cron.go
index 97b9ac43c..efcfa2c17 100644
--- a/cli/cron/cron.go
+++ b/cli/cron/cron.go
@@ -15,14 +15,14 @@
package cron
import (
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
)
// Command exports the cron command set.
var Command = &cli.Command{
Name: "cron",
Usage: "manage cron jobs",
- Subcommands: []*cli.Command{
+ Commands: []*cli.Command{
cronCreateCmd,
cronDeleteCmd,
cronUpdateCmd,
diff --git a/cli/cron/cron_add.go b/cli/cron/cron_add.go
index 2eb5eddd4..2ab730e0d 100644
--- a/cli/cron/cron_add.go
+++ b/cli/cron/cron_add.go
@@ -15,10 +15,11 @@
package cron
import (
+ "context"
"html/template"
"os"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -50,9 +51,9 @@ var cronCreateCmd = &cli.Command{
},
}
-func cronCreate(c *cli.Context) error {
+func cronCreate(ctx context.Context, c *cli.Command) error {
var (
- jobName = c.String("name")
+ cronName = c.String("name")
branch = c.String("branch")
schedule = c.String("schedule")
repoIDOrFullName = c.String("repository")
@@ -62,7 +63,7 @@ func cronCreate(c *cli.Context) error {
repoIDOrFullName = c.Args().First()
}
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
@@ -73,7 +74,7 @@ func cronCreate(c *cli.Context) error {
}
cron := &woodpecker.Cron{
- Name: jobName,
+ Name: cronName,
Branch: branch,
Schedule: schedule,
}
diff --git a/cli/cron/cron_info.go b/cli/cron/cron_info.go
index fd6f16bc1..276ed15a9 100644
--- a/cli/cron/cron_info.go
+++ b/cli/cron/cron_info.go
@@ -15,10 +15,11 @@
package cron
import (
+ "context"
"html/template"
"os"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -40,16 +41,16 @@ var cronInfoCmd = &cli.Command{
},
}
-func cronInfo(c *cli.Context) error {
+func cronInfo(ctx context.Context, c *cli.Command) error {
var (
- jobID = c.Int64("id")
+ cronID = c.Int("id")
repoIDOrFullName = c.String("repository")
format = c.String("format") + "\n"
)
if repoIDOrFullName == "" {
repoIDOrFullName = c.Args().First()
}
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
@@ -58,7 +59,7 @@ func cronInfo(c *cli.Context) error {
return err
}
- cron, err := client.CronGet(repoID, jobID)
+ cron, err := client.CronGet(repoID, cronID)
if err != nil {
return err
}
diff --git a/cli/cron/cron_list.go b/cli/cron/cron_list.go
index edd6c88d3..b51a7aaee 100644
--- a/cli/cron/cron_list.go
+++ b/cli/cron/cron_list.go
@@ -15,10 +15,11 @@
package cron
import (
+ "context"
"html/template"
"os"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -35,7 +36,7 @@ var cronListCmd = &cli.Command{
},
}
-func cronList(c *cli.Context) error {
+func cronList(ctx context.Context, c *cli.Command) error {
var (
format = c.String("format") + "\n"
repoIDOrFullName = c.String("repository")
@@ -43,7 +44,7 @@ func cronList(c *cli.Context) error {
if repoIDOrFullName == "" {
repoIDOrFullName = c.Args().First()
}
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/cron/cron_rm.go b/cli/cron/cron_rm.go
index 0e6fbc4c0..048dcd605 100644
--- a/cli/cron/cron_rm.go
+++ b/cli/cron/cron_rm.go
@@ -15,9 +15,10 @@
package cron
import (
+ "context"
"fmt"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -38,15 +39,15 @@ var cronDeleteCmd = &cli.Command{
},
}
-func cronDelete(c *cli.Context) error {
+func cronDelete(ctx context.Context, c *cli.Command) error {
var (
- jobID = c.Int64("id")
+ cronID = c.Int("id")
repoIDOrFullName = c.String("repository")
)
if repoIDOrFullName == "" {
repoIDOrFullName = c.Args().First()
}
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
@@ -54,7 +55,7 @@ func cronDelete(c *cli.Context) error {
if err != nil {
return err
}
- err = client.CronDelete(repoID, jobID)
+ err = client.CronDelete(repoID, cronID)
if err != nil {
return err
}
diff --git a/cli/cron/cron_update.go b/cli/cron/cron_update.go
index 0c25f03f7..de66e9a1f 100644
--- a/cli/cron/cron_update.go
+++ b/cli/cron/cron_update.go
@@ -15,10 +15,11 @@
package cron
import (
+ "context"
"html/template"
"os"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -53,10 +54,10 @@ var cronUpdateCmd = &cli.Command{
},
}
-func cronUpdate(c *cli.Context) error {
+func cronUpdate(ctx context.Context, c *cli.Command) error {
var (
repoIDOrFullName = c.String("repository")
- jobID = c.Int64("id")
+ cronID = c.Int("id")
jobName = c.String("name")
branch = c.String("branch")
schedule = c.String("schedule")
@@ -65,7 +66,7 @@ func cronUpdate(c *cli.Context) error {
if repoIDOrFullName == "" {
repoIDOrFullName = c.Args().First()
}
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
@@ -74,7 +75,7 @@ func cronUpdate(c *cli.Context) error {
return err
}
cron := &woodpecker.Cron{
- ID: jobID,
+ ID: cronID,
Name: jobName,
Branch: branch,
Schedule: schedule,
diff --git a/cli/deploy/deploy.go b/cli/deploy/deploy.go
index 71ba9401f..a037d109d 100644
--- a/cli/deploy/deploy.go
+++ b/cli/deploy/deploy.go
@@ -15,12 +15,13 @@
package deploy
import (
+ "context"
"fmt"
"html/template"
"os"
"strconv"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -30,7 +31,7 @@ import (
// Command exports the deploy command.
var Command = &cli.Command{
Name: "deploy",
- Usage: "deploy code",
+ Usage: "trigger a pipeline with the 'deployment' event",
ArgsUsage: " ",
Action: deploy,
Flags: []cli.Flag{
@@ -38,7 +39,6 @@ var Command = &cli.Command{
&cli.StringFlag{
Name: "branch",
Usage: "branch filter",
- Value: "main",
},
&cli.StringFlag{
Name: "event",
@@ -58,8 +58,8 @@ var Command = &cli.Command{
},
}
-func deploy(c *cli.Context) error {
- client, err := internal.NewClient(c)
+func deploy(ctx context.Context, c *cli.Command) error {
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
@@ -74,6 +74,15 @@ func deploy(c *cli.Context) error {
event := c.String("event")
status := c.String("status")
+ if branch == "" {
+ repo, err := client.Repo(repoID)
+ if err != nil {
+ return err
+ }
+
+ branch = repo.DefaultBranch
+ }
+
pipelineArg := c.Args().Get(1)
var number int64
if pipelineArg == "last" {
diff --git a/server/store/datastore/migration/017_remove_files_table.go b/cli/exec/dummy.go
similarity index 68%
rename from server/store/datastore/migration/017_remove_files_table.go
rename to cli/exec/dummy.go
index 8cc99b806..edb544598 100644
--- a/server/store/datastore/migration/017_remove_files_table.go
+++ b/cli/exec/dummy.go
@@ -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.
@@ -12,16 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package migration
+//go:build test
+// +build test
-import (
- "src.techknowlogick.com/xormigrate"
- "xorm.io/xorm"
-)
+package exec
-var dropFiles = xormigrate.Migration{
- ID: "drop-files",
- MigrateSession: func(sess *xorm.Session) error {
- return sess.DropTable("files")
- },
+import "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/dummy"
+
+func init() { //nolint:gochecknoinits
+ backends = append(backends, dummy.New())
}
diff --git a/cli/exec/exec.go b/cli/exec/exec.go
index 68db9aabe..59bbe47e6 100644
--- a/cli/exec/exec.go
+++ b/cli/exec/exec.go
@@ -26,20 +26,22 @@ import (
"github.com/drone/envsubst"
"github.com/rs/zerolog/log"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
+ "go.woodpecker-ci.org/woodpecker/v2/cli/lint"
"go.woodpecker-ci.org/woodpecker/v2/pipeline"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/docker"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/kubernetes"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/local"
- backendTypes "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
+ backend_types "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/compiler"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/linter"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/matrix"
pipelineLog "go.woodpecker-ci.org/woodpecker/v2/pipeline/log"
+ "go.woodpecker-ci.org/woodpecker/v2/shared/constant"
"go.woodpecker-ci.org/woodpecker/v2/shared/utils"
)
@@ -52,11 +54,17 @@ var Command = &cli.Command{
Flags: utils.MergeSlices(flags, docker.Flags, kubernetes.Flags, local.Flags),
}
-func run(c *cli.Context) error {
- return common.RunPipelineFunc(c, execFile, execDir)
+var backends = []backend_types.Backend{
+ kubernetes.New(),
+ docker.New(),
+ local.New(),
}
-func execDir(c *cli.Context, dir string) error {
+func run(ctx context.Context, c *cli.Command) error {
+ return common.RunPipelineFunc(ctx, c, execFile, execDir)
+}
+
+func execDir(ctx context.Context, c *cli.Command, dir string) error {
// TODO: respect pipeline dependency
repoPath := c.String("repo-path")
if repoPath != "" {
@@ -75,7 +83,7 @@ func execDir(c *cli.Context, dir string) error {
// check if it is a regular file (not dir)
if info.Mode().IsRegular() && (strings.HasSuffix(info.Name(), ".yaml") || strings.HasSuffix(info.Name(), ".yml")) {
fmt.Println("#", info.Name())
- _ = runExec(c, path, repoPath) // TODO: should we drop errors or store them and report back?
+ _ = runExec(ctx, c, path, repoPath) // TODO: should we drop errors or store them and report back?
fmt.Println("")
return nil
}
@@ -84,7 +92,7 @@ func execDir(c *cli.Context, dir string) error {
})
}
-func execFile(c *cli.Context, file string) error {
+func execFile(ctx context.Context, c *cli.Command, file string) error {
repoPath := c.String("repo-path")
if repoPath != "" {
repoPath, _ = filepath.Abs(repoPath)
@@ -94,10 +102,10 @@ func execFile(c *cli.Context, file string) error {
if runtime.GOOS == "windows" {
repoPath = convertPathForWindows(repoPath)
}
- return runExec(c, file, repoPath)
+ return runExec(ctx, c, file, repoPath)
}
-func runExec(c *cli.Context, file, repoPath string) error {
+func runExec(ctx context.Context, c *cli.Command, file, repoPath string) error {
dat, err := os.ReadFile(file)
if err != nil {
return err
@@ -112,7 +120,7 @@ func runExec(c *cli.Context, file, repoPath string) error {
axes = append(axes, matrix.Axis{})
}
for _, axis := range axes {
- err := execWithAxis(c, file, repoPath, axis)
+ err := execWithAxis(ctx, c, file, repoPath, axis)
if err != nil {
return err
}
@@ -120,8 +128,11 @@ func runExec(c *cli.Context, file, repoPath string) error {
return nil
}
-func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error {
- metadata := metadataFromContext(c, axis)
+func execWithAxis(ctx context.Context, c *cli.Command, file, repoPath string, axis matrix.Axis) error {
+ metadata, err := metadataFromContext(ctx, c, axis)
+ if err != nil {
+ return fmt.Errorf("could not create metadata: %w", err)
+ }
environ := metadata.Environ()
var secrets []compiler.Secret
for key, val := range metadata.Workflow.Matrix {
@@ -177,19 +188,30 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
volumes = append(volumes, repoPath+":"+path.Join(workspaceBase, workspacePath))
}
+ privilegedPlugins := c.StringSlice("plugins-privileged")
+
// lint the yaml file
- if err := linter.New(linter.WithTrusted(true)).Lint([]*linter.WorkflowConfig{{
+ err = linter.New(
+ linter.WithTrusted(true),
+ linter.PrivilegedPlugins(privilegedPlugins),
+ linter.WithTrustedClonePlugins(constant.TrustedClonePlugins),
+ ).Lint([]*linter.WorkflowConfig{{
File: path.Base(file),
RawConfig: confStr,
Workflow: conf,
- }}); err != nil {
- return err
+ }})
+ if err != nil {
+ str, err := lint.FormatLintError(file, err)
+ fmt.Print(str)
+ if err != nil {
+ return err
+ }
}
// compiles the yaml file
compiled, err := compiler.New(
compiler.WithEscalated(
- c.StringSlice("privileged")...,
+ privilegedPlugins...,
),
compiler.WithVolumes(volumes...),
compiler.WithWorkspace(
@@ -223,12 +245,7 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
return err
}
- backendCtx := context.WithValue(c.Context, backendTypes.CliContext, c)
- backends := []backendTypes.Backend{
- kubernetes.New(),
- docker.New(),
- local.New(),
- }
+ backendCtx := context.WithValue(ctx, backend_types.CliCommand, c)
backendEngine, err := backend.FindBackend(backendCtx, backends, c.String("backend-engine"))
if err != nil {
return err
@@ -238,21 +255,21 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
return err
}
- ctx, cancel := context.WithTimeout(context.Background(), c.Duration("timeout"))
+ pipelineCtx, cancel := context.WithTimeout(context.Background(), c.Duration("timeout"))
defer cancel()
- ctx = utils.WithContextSigtermCallback(ctx, func() {
- fmt.Println("ctrl+c received, terminating process")
+ pipelineCtx = utils.WithContextSigtermCallback(pipelineCtx, func() {
+ fmt.Printf("ctrl+c received, terminating current pipeline '%s'\n", confStr)
})
return pipeline.New(compiled,
- pipeline.WithContext(ctx),
+ pipeline.WithContext(pipelineCtx), //nolint:contextcheck
pipeline.WithTracer(pipeline.DefaultTracer),
pipeline.WithLogger(defaultLogger),
pipeline.WithBackend(backendEngine),
pipeline.WithDescription(map[string]string{
"CLI": "exec",
}),
- ).Run(c.Context)
+ ).Run(ctx)
}
// convertPathForWindows converts a path to use slash separators
@@ -274,8 +291,7 @@ func convertPathForWindows(path string) string {
return filepath.ToSlash(path)
}
-const maxLogLineLength = 1024 * 1024 // 1mb
-var defaultLogger = pipeline.Logger(func(step *backendTypes.Step, rc io.Reader) error {
+var defaultLogger = pipeline.Logger(func(step *backend_types.Step, rc io.ReadCloser) error {
logWriter := NewLineWriter(step.Name, step.UUID)
- return pipelineLog.CopyLineByLine(logWriter, rc, maxLogLineLength)
+ return pipelineLog.CopyLineByLine(logWriter, rc, pipeline.MaxLogLineLength)
})
diff --git a/cli/exec/flags.go b/cli/exec/flags.go
index eabce0470..1acc44ee3 100644
--- a/cli/exec/flags.go
+++ b/cli/exec/flags.go
@@ -17,53 +17,51 @@ package exec
import (
"time"
- "github.com/urfave/cli/v2"
-
- "go.woodpecker-ci.org/woodpecker/v2/shared/constant"
+ "github.com/urfave/cli/v3"
)
var flags = []cli.Flag{
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_LOCAL"},
+ Sources: cli.EnvVars("WOODPECKER_LOCAL"),
Name: "local",
Usage: "run from local directory",
Value: true,
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_REPO_PATH"},
+ Sources: cli.EnvVars("WOODPECKER_REPO_PATH"),
Name: "repo-path",
Usage: "path to local repository",
},
&cli.DurationFlag{
- EnvVars: []string{"WOODPECKER_TIMEOUT"},
+ Sources: cli.EnvVars("WOODPECKER_TIMEOUT"),
Name: "timeout",
Usage: "pipeline timeout",
Value: time.Hour,
},
&cli.StringSliceFlag{
- EnvVars: []string{"WOODPECKER_VOLUMES"},
+ Sources: cli.EnvVars("WOODPECKER_VOLUMES"),
Name: "volumes",
Usage: "pipeline volumes",
},
&cli.StringSliceFlag{
- EnvVars: []string{"WOODPECKER_NETWORKS"},
+ Sources: cli.EnvVars("WOODPECKER_NETWORKS"),
Name: "network",
Usage: "external networks",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_PREFIX"},
+ Sources: cli.EnvVars("WOODPECKER_PREFIX"),
Name: "prefix",
Value: "woodpecker",
Usage: "prefix used for containers, volumes, networks, ... created by woodpecker",
Hidden: true,
},
&cli.StringSliceFlag{
- Name: "privileged",
- Usage: "privileged plugins",
- Value: cli.NewStringSlice(constant.PrivilegedPlugins...),
+ Sources: cli.EnvVars("WOODPECKER_PLUGINS_PRIVILEGED"),
+ Name: "plugins-privileged",
+ Usage: "Allow plugins to run in privileged mode, if environment variable is defined but empty there will be none",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_BACKEND"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND"),
Name: "backend-engine",
Usage: "backend engine to run pipelines on",
Value: "auto-detect",
@@ -73,17 +71,17 @@ var flags = []cli.Flag{
// backend options for pipeline compiler
//
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_NO_PROXY", "NO_PROXY", "no_proxy"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_NO_PROXY", "NO_PROXY", "no_proxy"),
Usage: "if set, pass the environment variable down as \"NO_PROXY\" to steps",
Name: "backend-no-proxy",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_HTTP_PROXY", "HTTP_PROXY", "http_proxy"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_HTTP_PROXY", "HTTP_PROXY", "http_proxy"),
Usage: "if set, pass the environment variable down as \"HTTP_PROXY\" to steps",
Name: "backend-http-proxy",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_HTTPS_PROXY", "HTTPS_PROXY", "https_proxy"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_HTTPS_PROXY", "HTTPS_PROXY", "https_proxy"),
Usage: "if set, pass the environment variable down as \"HTTPS_PROXY\" to steps",
Name: "backend-https-proxy",
},
@@ -97,12 +95,12 @@ var flags = []cli.Flag{
// workspace default
//
&cli.StringFlag{
- EnvVars: []string{"CI_WORKSPACE_BASE"},
+ Sources: cli.EnvVars("CI_WORKSPACE_BASE"),
Name: "workspace-base",
Value: "/woodpecker",
},
&cli.StringFlag{
- EnvVars: []string{"CI_WORKSPACE_PATH"},
+ Sources: cli.EnvVars("CI_WORKSPACE_PATH"),
Name: "workspace-path",
Value: "src",
},
@@ -110,218 +108,246 @@ var flags = []cli.Flag{
// netrc parameters
//
&cli.StringFlag{
- EnvVars: []string{"CI_NETRC_USERNAME"},
+ Sources: cli.EnvVars("CI_NETRC_USERNAME"),
Name: "netrc-username",
},
&cli.StringFlag{
- EnvVars: []string{"CI_NETRC_PASSWORD"},
+ Sources: cli.EnvVars("CI_NETRC_PASSWORD"),
Name: "netrc-password",
},
&cli.StringFlag{
- EnvVars: []string{"CI_NETRC_MACHINE"},
+ Sources: cli.EnvVars("CI_NETRC_MACHINE"),
Name: "netrc-machine",
},
//
// metadata parameters
//
&cli.StringFlag{
- EnvVars: []string{"CI_SYSTEM_PLATFORM"},
+ Sources: cli.EnvVars("CI_SYSTEM_PLATFORM"),
Name: "system-platform",
},
&cli.StringFlag{
- EnvVars: []string{"CI_SYSTEM_NAME"},
+ Sources: cli.EnvVars("CI_SYSTEM_HOST"),
+ Name: "system-host",
+ },
+ &cli.StringFlag{
+ Sources: cli.EnvVars("CI_SYSTEM_NAME"),
Name: "system-name",
Value: "woodpecker",
},
&cli.StringFlag{
- EnvVars: []string{"CI_SYSTEM_URL"},
+ Sources: cli.EnvVars("CI_SYSTEM_URL"),
Name: "system-url",
Value: "https://github.com/woodpecker-ci/woodpecker",
},
&cli.StringFlag{
- EnvVars: []string{"CI_REPO"},
+ Sources: cli.EnvVars("CI_REPO"),
Name: "repo",
Usage: "full repo name",
},
&cli.StringFlag{
- EnvVars: []string{"CI_REPO_REMOTE_ID"},
+ Sources: cli.EnvVars("CI_REPO_REMOTE_ID"),
Name: "repo-remote-id",
},
&cli.StringFlag{
- EnvVars: []string{"CI_REPO_URL"},
+ Sources: cli.EnvVars("CI_REPO_URL"),
Name: "repo-url",
},
&cli.StringFlag{
- EnvVars: []string{"CI_REPO_CLONE_URL"},
+ Sources: cli.EnvVars("CI_REPO_SCM"),
+ Name: "repo-scm",
+ Value: "git",
+ },
+ &cli.StringFlag{
+ Sources: cli.EnvVars("CI_REPO_DEFAULT_BRANCH"),
+ Name: "repo-default-branch",
+ Value: "main",
+ },
+ &cli.StringFlag{
+ Sources: cli.EnvVars("CI_REPO_CLONE_URL"),
Name: "repo-clone-url",
},
&cli.StringFlag{
- EnvVars: []string{"CI_REPO_CLONE_SSH_URL"},
+ Sources: cli.EnvVars("CI_REPO_CLONE_SSH_URL"),
Name: "repo-clone-ssh-url",
},
&cli.StringFlag{
- EnvVars: []string{"CI_REPO_PRIVATE"},
+ Sources: cli.EnvVars("CI_REPO_PRIVATE"),
Name: "repo-private",
},
&cli.BoolFlag{
- EnvVars: []string{"CI_REPO_TRUSTED"},
+ Sources: cli.EnvVars("CI_REPO_TRUSTED"),
Name: "repo-trusted",
},
&cli.IntFlag{
- EnvVars: []string{"CI_PIPELINE_NUMBER"},
+ Sources: cli.EnvVars("CI_PIPELINE_NUMBER"),
Name: "pipeline-number",
},
&cli.IntFlag{
- EnvVars: []string{"CI_PIPELINE_PARENT"},
+ Sources: cli.EnvVars("CI_PIPELINE_PARENT"),
Name: "pipeline-parent",
},
- &cli.Int64Flag{
- EnvVars: []string{"CI_PIPELINE_CREATED"},
+ &cli.IntFlag{
+ Sources: cli.EnvVars("CI_PIPELINE_CREATED"),
Name: "pipeline-created",
},
- &cli.Int64Flag{
- EnvVars: []string{"CI_PIPELINE_STARTED"},
+ &cli.IntFlag{
+ Sources: cli.EnvVars("CI_PIPELINE_STARTED"),
Name: "pipeline-started",
},
- &cli.Int64Flag{
- EnvVars: []string{"CI_PIPELINE_FINISHED"},
- Name: "pipeline-finished",
- },
&cli.StringFlag{
- EnvVars: []string{"CI_PIPELINE_STATUS"},
- Name: "pipeline-status",
- },
- &cli.StringFlag{
- EnvVars: []string{"CI_PIPELINE_EVENT"},
+ Sources: cli.EnvVars("CI_PIPELINE_EVENT"),
Name: "pipeline-event",
Value: "manual",
},
&cli.StringFlag{
- EnvVars: []string{"CI_PIPELINE_URL"},
+ Sources: cli.EnvVars("CI_PIPELINE_FORGE_URL"),
Name: "pipeline-url",
},
&cli.StringFlag{
- EnvVars: []string{"CI_PIPELINE_TARGET"},
- Name: "pipeline-target",
+ Sources: cli.EnvVars("CI_PIPELINE_DEPLOY_TARGET"),
+ Name: "pipeline-deploy-to",
},
&cli.StringFlag{
- EnvVars: []string{"CI_PIPELINE_TASK"},
- Name: "pipeline-task",
+ Sources: cli.EnvVars("CI_PIPELINE_DEPLOY_TASK"),
+ Name: "pipeline-deploy-task",
},
&cli.StringFlag{
- EnvVars: []string{"CI_COMMIT_SHA"},
+ Sources: cli.EnvVars("CI_PIPELINE_FILES"),
+ Usage: "either json formatted list of strings, or comma separated string list",
+ Name: "pipeline-files",
+ },
+ &cli.StringFlag{
+ Sources: cli.EnvVars("CI_COMMIT_SHA"),
Name: "commit-sha",
},
&cli.StringFlag{
- EnvVars: []string{"CI_COMMIT_REF"},
+ Sources: cli.EnvVars("CI_COMMIT_REF"),
Name: "commit-ref",
},
&cli.StringFlag{
- EnvVars: []string{"CI_COMMIT_REFSPEC"},
+ Sources: cli.EnvVars("CI_COMMIT_REFSPEC"),
Name: "commit-refspec",
},
&cli.StringFlag{
- EnvVars: []string{"CI_COMMIT_BRANCH"},
+ Sources: cli.EnvVars("CI_COMMIT_BRANCH"),
Name: "commit-branch",
+ Value: "main",
},
&cli.StringFlag{
- EnvVars: []string{"CI_COMMIT_MESSAGE"},
+ Sources: cli.EnvVars("CI_COMMIT_MESSAGE"),
Name: "commit-message",
},
&cli.StringFlag{
- EnvVars: []string{"CI_COMMIT_AUTHOR_NAME"},
+ Sources: cli.EnvVars("CI_COMMIT_AUTHOR"),
Name: "commit-author-name",
},
&cli.StringFlag{
- EnvVars: []string{"CI_COMMIT_AUTHOR_AVATAR"},
+ Sources: cli.EnvVars("CI_COMMIT_AUTHOR_AVATAR"),
Name: "commit-author-avatar",
},
&cli.StringFlag{
- EnvVars: []string{"CI_COMMIT_AUTHOR_EMAIL"},
+ Sources: cli.EnvVars("CI_COMMIT_AUTHOR_EMAIL"),
Name: "commit-author-email",
},
+ &cli.StringSliceFlag{
+ Sources: cli.EnvVars("CI_COMMIT_PULL_REQUEST_LABELS"),
+ Name: "commit-pull-labels",
+ },
+ &cli.BoolFlag{
+ Sources: cli.EnvVars("CI_COMMIT_PRERELEASE"),
+ Name: "commit-release-is-pre",
+ },
&cli.IntFlag{
- EnvVars: []string{"CI_PREV_PIPELINE_NUMBER"},
+ Sources: cli.EnvVars("CI_PREV_PIPELINE_NUMBER"),
Name: "prev-pipeline-number",
},
- &cli.Int64Flag{
- EnvVars: []string{"CI_PREV_PIPELINE_CREATED"},
+ &cli.IntFlag{
+ Sources: cli.EnvVars("CI_PREV_PIPELINE_CREATED"),
Name: "prev-pipeline-created",
},
- &cli.Int64Flag{
- EnvVars: []string{"CI_PREV_PIPELINE_STARTED"},
+ &cli.IntFlag{
+ Sources: cli.EnvVars("CI_PREV_PIPELINE_STARTED"),
Name: "prev-pipeline-started",
},
- &cli.Int64Flag{
- EnvVars: []string{"CI_PREV_PIPELINE_FINISHED"},
+ &cli.IntFlag{
+ Sources: cli.EnvVars("CI_PREV_PIPELINE_FINISHED"),
Name: "prev-pipeline-finished",
},
&cli.StringFlag{
- EnvVars: []string{"CI_PREV_PIPELINE_STATUS"},
+ Sources: cli.EnvVars("CI_PREV_PIPELINE_STATUS"),
Name: "prev-pipeline-status",
},
&cli.StringFlag{
- EnvVars: []string{"CI_PREV_PIPELINE_EVENT"},
+ Sources: cli.EnvVars("CI_PREV_PIPELINE_EVENT"),
Name: "prev-pipeline-event",
},
&cli.StringFlag{
- EnvVars: []string{"CI_PREV_PIPELINE_URL"},
+ Sources: cli.EnvVars("CI_PREV_PIPELINE_FORGE_URL"),
Name: "prev-pipeline-url",
},
&cli.StringFlag{
- EnvVars: []string{"CI_PREV_COMMIT_SHA"},
+ Sources: cli.EnvVars("CI_PREV_PIPELINE_DEPLOY_TARGET"),
+ Name: "prev-pipeline-deploy-to",
+ },
+ &cli.StringFlag{
+ Sources: cli.EnvVars("CI_PREV_PIPELINE_DEPLOY_TASK"),
+ Name: "prev-pipeline-deploy-task",
+ },
+ &cli.StringFlag{
+ Sources: cli.EnvVars("CI_PREV_COMMIT_SHA"),
Name: "prev-commit-sha",
},
&cli.StringFlag{
- EnvVars: []string{"CI_PREV_COMMIT_REF"},
+ Sources: cli.EnvVars("CI_PREV_COMMIT_REF"),
Name: "prev-commit-ref",
},
&cli.StringFlag{
- EnvVars: []string{"CI_PREV_COMMIT_REFSPEC"},
+ Sources: cli.EnvVars("CI_PREV_COMMIT_REFSPEC"),
Name: "prev-commit-refspec",
},
&cli.StringFlag{
- EnvVars: []string{"CI_PREV_COMMIT_BRANCH"},
+ Sources: cli.EnvVars("CI_PREV_COMMIT_BRANCH"),
Name: "prev-commit-branch",
},
&cli.StringFlag{
- EnvVars: []string{"CI_PREV_COMMIT_MESSAGE"},
+ Sources: cli.EnvVars("CI_PREV_COMMIT_MESSAGE"),
Name: "prev-commit-message",
},
&cli.StringFlag{
- EnvVars: []string{"CI_PREV_COMMIT_AUTHOR_NAME"},
+ Sources: cli.EnvVars("CI_PREV_COMMIT_AUTHOR"),
Name: "prev-commit-author-name",
},
&cli.StringFlag{
- EnvVars: []string{"CI_PREV_COMMIT_AUTHOR_AVATAR"},
+ Sources: cli.EnvVars("CI_PREV_COMMIT_AUTHOR_AVATAR"),
Name: "prev-commit-author-avatar",
},
&cli.StringFlag{
- EnvVars: []string{"CI_PREV_COMMIT_AUTHOR_EMAIL"},
+ Sources: cli.EnvVars("CI_PREV_COMMIT_AUTHOR_EMAIL"),
Name: "prev-commit-author-email",
},
&cli.IntFlag{
- EnvVars: []string{"CI_WORKFLOW_NAME"},
+ Sources: cli.EnvVars("CI_WORKFLOW_NAME"),
Name: "workflow-name",
},
&cli.IntFlag{
- EnvVars: []string{"CI_WORKFLOW_NUMBER"},
+ Sources: cli.EnvVars("CI_WORKFLOW_NUMBER"),
Name: "workflow-number",
},
&cli.IntFlag{
- EnvVars: []string{"CI_STEP_NAME"},
+ Sources: cli.EnvVars("CI_STEP_NAME"),
Name: "step-name",
},
&cli.StringSliceFlag{
- EnvVars: []string{"CI_ENV"},
+ Sources: cli.EnvVars("CI_ENV"),
Name: "env",
},
&cli.StringFlag{
- EnvVars: []string{"CI_FORGE_TYPE"},
+ Sources: cli.EnvVars("CI_FORGE_TYPE"),
Name: "forge-type",
},
&cli.StringFlag{
- EnvVars: []string{"CI_FORGE_URL"},
+ Sources: cli.EnvVars("CI_FORGE_URL"),
Name: "forge-url",
},
}
diff --git a/cli/exec/metadata.go b/cli/exec/metadata.go
index 0cb471683..db2f9d95f 100644
--- a/cli/exec/metadata.go
+++ b/cli/exec/metadata.go
@@ -15,10 +15,13 @@
package exec
import (
+ "context"
+ "encoding/json"
+ "fmt"
"runtime"
"strings"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/metadata"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/matrix"
@@ -26,7 +29,7 @@ import (
)
// return the metadata from the cli context.
-func metadataFromContext(c *cli.Context, axis matrix.Axis) metadata.Metadata {
+func metadataFromContext(_ context.Context, c *cli.Command, axis matrix.Axis) (metadata.Metadata, error) {
platform := c.String("system-platform")
if platform == "" {
platform = runtime.GOOS + "/" + runtime.GOARCH
@@ -40,28 +43,42 @@ func metadataFromContext(c *cli.Context, axis matrix.Axis) metadata.Metadata {
repoName = fullRepoName[idx+1:]
}
+ var changedFiles []string
+ changedFilesRaw := c.String("pipeline-files")
+ if len(changedFilesRaw) != 0 && changedFilesRaw[0] == '[' {
+ if err := json.Unmarshal([]byte(changedFilesRaw), &changedFiles); err != nil {
+ return metadata.Metadata{}, fmt.Errorf("pipeline-files detected json but could not parse it: %w", err)
+ }
+ } else {
+ for _, file := range strings.Split(changedFilesRaw, ",") {
+ changedFiles = append(changedFiles, strings.TrimSpace(file))
+ }
+ }
+
return metadata.Metadata{
Repo: metadata.Repo{
Name: repoName,
Owner: repoOwner,
RemoteID: c.String("repo-remote-id"),
ForgeURL: c.String("repo-url"),
+ SCM: c.String("repo-scm"),
+ Branch: c.String("repo-default-branch"),
CloneURL: c.String("repo-clone-url"),
CloneSSHURL: c.String("repo-clone-ssh-url"),
Private: c.Bool("repo-private"),
Trusted: c.Bool("repo-trusted"),
},
Curr: metadata.Pipeline{
- Number: c.Int64("pipeline-number"),
- Parent: c.Int64("pipeline-parent"),
- Created: c.Int64("pipeline-created"),
- Started: c.Int64("pipeline-started"),
- Finished: c.Int64("pipeline-finished"),
- Status: c.String("pipeline-status"),
- Event: c.String("pipeline-event"),
- ForgeURL: c.String("pipeline-url"),
- Target: c.String("pipeline-target"),
- Task: c.String("pipeline-task"),
+ Number: c.Int("pipeline-number"),
+ Parent: c.Int("pipeline-parent"),
+ Created: c.Int("pipeline-created"),
+ Started: c.Int("pipeline-started"),
+ Finished: c.Int("pipeline-finished"),
+ Status: c.String("pipeline-status"),
+ Event: c.String("pipeline-event"),
+ ForgeURL: c.String("pipeline-url"),
+ DeployTo: c.String("pipeline-deploy-to"),
+ DeployTask: c.String("pipeline-deploy-task"),
Commit: metadata.Commit{
Sha: c.String("commit-sha"),
Ref: c.String("commit-ref"),
@@ -73,13 +90,16 @@ func metadataFromContext(c *cli.Context, axis matrix.Axis) metadata.Metadata {
Email: c.String("commit-author-email"),
Avatar: c.String("commit-author-avatar"),
},
+ PullRequestLabels: c.StringSlice("commit-pull-labels"),
+ IsPrerelease: c.Bool("commit-release-is-pre"),
+ ChangedFiles: changedFiles,
},
},
Prev: metadata.Pipeline{
- Number: c.Int64("prev-pipeline-number"),
- Created: c.Int64("prev-pipeline-created"),
- Started: c.Int64("prev-pipeline-started"),
- Finished: c.Int64("prev-pipeline-finished"),
+ Number: c.Int("prev-pipeline-number"),
+ Created: c.Int("prev-pipeline-created"),
+ Started: c.Int("prev-pipeline-started"),
+ Finished: c.Int("prev-pipeline-finished"),
Status: c.String("prev-pipeline-status"),
Event: c.String("prev-pipeline-event"),
ForgeURL: c.String("prev-pipeline-url"),
@@ -98,16 +118,17 @@ func metadataFromContext(c *cli.Context, axis matrix.Axis) metadata.Metadata {
},
Workflow: metadata.Workflow{
Name: c.String("workflow-name"),
- Number: c.Int("workflow-number"),
+ Number: int(c.Int("workflow-number")),
Matrix: axis,
},
Step: metadata.Step{
Name: c.String("step-name"),
- Number: c.Int("step-number"),
+ Number: int(c.Int("step-number")),
},
Sys: metadata.System{
Name: c.String("system-name"),
URL: c.String("system-url"),
+ Host: c.String("system-host"),
Platform: platform,
Version: version.Version,
},
@@ -115,5 +136,5 @@ func metadataFromContext(c *cli.Context, axis matrix.Axis) metadata.Metadata {
Type: c.String("forge-type"),
URL: c.String("forge-url"),
},
- }
+ }, nil
}
diff --git a/cli/info/info.go b/cli/info/info.go
index 5963f4425..2d17680d4 100644
--- a/cli/info/info.go
+++ b/cli/info/info.go
@@ -15,10 +15,11 @@
package info
import (
+ "context"
"os"
"text/template"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -33,8 +34,8 @@ var Command = &cli.Command{
Flags: []cli.Flag{common.FormatFlag(tmplInfo, true)},
}
-func info(c *cli.Context) error {
- client, err := internal.NewClient(c)
+func info(ctx context.Context, c *cli.Command) error {
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/internal/config/config.go b/cli/internal/config/config.go
index 29741212e..817a859c3 100644
--- a/cli/internal/config/config.go
+++ b/cli/internal/config/config.go
@@ -1,6 +1,7 @@
package config
import (
+ "context"
"encoding/json"
"errors"
"os"
@@ -8,7 +9,7 @@ import (
"github.com/adrg/xdg"
"github.com/rs/zerolog/log"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"github.com/zalando/go-keyring"
)
@@ -32,12 +33,12 @@ func (c *Config) MergeIfNotSet(c2 *Config) {
var skipSetupForCommands = []string{"setup", "help", "h", "version", "update", "lint", "exec", ""}
-func Load(c *cli.Context) error {
+func Load(ctx context.Context, c *cli.Command) error {
if firstArg := c.Args().First(); slices.Contains(skipSetupForCommands, firstArg) {
return nil
}
- config, err := Get(c, c.String("config"))
+ config, err := Get(ctx, c, c.String("config"))
if err != nil {
return err
}
@@ -80,11 +81,11 @@ func getConfigPath(configPath string) (string, error) {
return configPath, nil
}
-func Get(ctx *cli.Context, _configPath string) (*Config, error) {
- c := &Config{
- LogLevel: ctx.String("log-level"),
- Token: ctx.String("token"),
- ServerURL: ctx.String("server"),
+func Get(_ context.Context, c *cli.Command, _configPath string) (*Config, error) {
+ conf := &Config{
+ LogLevel: c.String("log-level"),
+ Token: c.String("token"),
+ ServerURL: c.String("server"),
}
configPath, err := getConfigPath(_configPath)
@@ -109,33 +110,33 @@ func Get(ctx *cli.Context, _configPath string) (*Config, error) {
if err != nil {
return nil, err
}
- c.MergeIfNotSet(configFromFile)
+ conf.MergeIfNotSet(configFromFile)
log.Debug().Msg("Loaded config from file")
}
// if server or token are explicitly set, use them
- if ctx.IsSet("server") || ctx.IsSet("token") {
- return c, nil
+ if c.IsSet("server") || c.IsSet("token") {
+ return conf, nil
}
// load token from keyring
- service := ctx.App.Name
- secret, err := keyring.Get(service, c.ServerURL)
+ service := c.Root().Name
+ secret, err := keyring.Get(service, conf.ServerURL)
if errors.Is(err, keyring.ErrUnsupportedPlatform) {
log.Warn().Msg("Keyring is not supported on this platform")
- return c, nil
+ return conf, nil
}
if errors.Is(err, keyring.ErrNotFound) {
log.Warn().Msg("Token not found in keyring")
- return c, nil
+ return conf, nil
}
- c.Token = secret
+ conf.Token = secret
- return c, nil
+ return conf, nil
}
-func Save(ctx *cli.Context, _configPath string, c *Config) error {
- config, err := json.Marshal(c)
+func Save(_ context.Context, c *cli.Command, _configPath string, conf *Config) error {
+ config, err := json.Marshal(conf)
if err != nil {
return err
}
@@ -146,8 +147,8 @@ func Save(ctx *cli.Context, _configPath string, c *Config) error {
}
// save token to keyring
- service := ctx.App.Name
- err = keyring.Set(service, c.ServerURL, c.Token)
+ service := c.Root().Name
+ err = keyring.Set(service, conf.ServerURL, conf.Token)
if err != nil {
return err
}
diff --git a/cli/internal/util.go b/cli/internal/util.go
index 5532c62e8..e705dc9f9 100644
--- a/cli/internal/util.go
+++ b/cli/internal/util.go
@@ -15,15 +15,18 @@
package internal
import (
+ "context"
"crypto/tls"
"crypto/x509"
"fmt"
"net/http"
+ "os/exec"
"strconv"
"strings"
+ vsc_url "github.com/gitsight/go-vcsurl"
"github.com/rs/zerolog/log"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"golang.org/x/net/proxy"
"golang.org/x/oauth2"
@@ -31,7 +34,7 @@ import (
)
// NewClient returns a new client from the CLI context.
-func NewClient(c *cli.Context) (woodpecker.Client, error) {
+func NewClient(ctx context.Context, c *cli.Command) (woodpecker.Client, error) {
var (
skip = c.Bool("skip-verify")
socks = c.String("socks-proxy")
@@ -61,8 +64,7 @@ func NewClient(c *cli.Context) (woodpecker.Client, error) {
}
config := new(oauth2.Config)
- client := config.Client(
- c.Context,
+ client := config.Client(ctx,
&oauth2.Token{
AccessToken: token,
},
@@ -90,8 +92,52 @@ func NewClient(c *cli.Context) (woodpecker.Client, error) {
return woodpecker.NewClient(server, client), nil
}
+func getRepoFromGit(remoteName string) (string, error) {
+ cmd := exec.Command("git", "remote", "get-url", remoteName)
+ stdout, err := cmd.Output()
+ if err != nil {
+ return "", fmt.Errorf("could not get remote url: %w", err)
+ }
+
+ gitRemote := strings.TrimSpace(string(stdout))
+
+ log.Debug().Str("git-remote", gitRemote).Msg("extracted remote url from git")
+
+ if len(gitRemote) == 0 {
+ return "", fmt.Errorf("no repository provided")
+ }
+
+ u, err := vsc_url.Parse(gitRemote)
+ if err != nil {
+ return "", fmt.Errorf("could not parse git remote url: %w", err)
+ }
+
+ repoFullName := u.FullName
+ log.Debug().Str("repo", repoFullName).Msg("extracted repository from remote url")
+
+ return repoFullName, nil
+}
+
// ParseRepo parses the repository owner and name from a string.
func ParseRepo(client woodpecker.Client, str string) (repoID int64, err error) {
+ if str == "" {
+ str, err = getRepoFromGit("upstream")
+ if err != nil {
+ log.Debug().Err(err).Msg("could not get repository from git upstream remote")
+ }
+ }
+
+ if str == "" {
+ str, err = getRepoFromGit("origin")
+ if err != nil {
+ log.Debug().Err(err).Msg("could not get repository from git origin remote")
+ }
+ }
+
+ if str == "" {
+ return 0, fmt.Errorf("no repository provided")
+ }
+
if strings.Contains(str, "/") {
repo, err := client.RepoLookup(str)
if err != nil {
@@ -115,3 +161,40 @@ func ParseKeyPair(p []string) map[string]string {
}
return params
}
+
+/*
+ParseStep parses the step id form a string which may either be the step PID (step number) or a step name.
+These rules apply:
+
+- Step PID take precedence over step name when searching for a match.
+- First match is used, when there are multiple steps with the same name.
+
+Strictly speaking, this is not parsing, but a lookup.
+*/
+func ParseStep(client woodpecker.Client, repoID, number int64, stepArg string) (stepID int64, err error) {
+ pipeline, err := client.Pipeline(repoID, number)
+ if err != nil {
+ return 0, err
+ }
+
+ stepPID, err := strconv.ParseInt(stepArg, 10, 64)
+ if err == nil {
+ for _, wf := range pipeline.Workflows {
+ for _, step := range wf.Children {
+ if int64(step.PID) == stepPID {
+ return step.ID, nil
+ }
+ }
+ }
+ }
+
+ for _, wf := range pipeline.Workflows {
+ for _, step := range wf.Children {
+ if step.Name == stepArg {
+ return step.ID, nil
+ }
+ }
+ }
+
+ return 0, fmt.Errorf("no step with number or name '%s' found", stepArg)
+}
diff --git a/cli/lint/lint.go b/cli/lint/lint.go
index e82ebf050..973e9ec89 100644
--- a/cli/lint/lint.go
+++ b/cli/lint/lint.go
@@ -15,20 +15,19 @@
package lint
import (
- "errors"
+ "context"
"fmt"
"os"
"path"
"path/filepath"
"strings"
- term_env "github.com/muesli/termenv"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
- pipeline_errors "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/linter"
+ "go.woodpecker-ci.org/woodpecker/v2/shared/constant"
)
// Command exports the info command.
@@ -37,13 +36,26 @@ var Command = &cli.Command{
Usage: "lint a pipeline configuration file",
ArgsUsage: "[path/to/.woodpecker.yaml]",
Action: lint,
+ Flags: []cli.Flag{
+ &cli.StringSliceFlag{
+ Sources: cli.EnvVars("WOODPECKER_PLUGINS_PRIVILEGED"),
+ Name: "plugins-privileged",
+ Usage: "Allow plugins to run in privileged mode, if environment variable is defined but empty there will be none",
+ },
+ &cli.StringSliceFlag{
+ Sources: cli.EnvVars("WOODPECKER_PLUGINS_TRUSTED_CLONE"),
+ Name: "plugins-trusted-clone",
+ Usage: "Plugins witch are trusted to handle the netrc info in clone steps",
+ Value: constant.TrustedClonePlugins,
+ },
+ },
}
-func lint(c *cli.Context) error {
- return common.RunPipelineFunc(c, lintFile, lintDir)
+func lint(ctx context.Context, c *cli.Command) error {
+ return common.RunPipelineFunc(ctx, c, lintFile, lintDir)
}
-func lintDir(c *cli.Context, dir string) error {
+func lintDir(ctx context.Context, c *cli.Command, dir string) error {
var errorStrings []string
if err := filepath.Walk(dir, func(path string, info os.FileInfo, e error) error {
if e != nil {
@@ -53,7 +65,7 @@ func lintDir(c *cli.Context, dir string) error {
// check if it is a regular file (not dir)
if info.Mode().IsRegular() && (strings.HasSuffix(info.Name(), ".yaml") || strings.HasSuffix(info.Name(), ".yml")) {
fmt.Println("#", info.Name())
- if err := lintFile(c, path); err != nil {
+ if err := lintFile(ctx, c, path); err != nil {
errorStrings = append(errorStrings, err.Error())
}
fmt.Println("")
@@ -71,9 +83,7 @@ func lintDir(c *cli.Context, dir string) error {
return nil
}
-func lintFile(_ *cli.Context, file string) error {
- output := term_env.NewOutput(os.Stdout)
-
+func lintFile(_ context.Context, c *cli.Command, file string) error {
fi, err := os.Open(file)
if err != nil {
return err
@@ -87,7 +97,7 @@ func lintFile(_ *cli.Context, file string) error {
rawConfig := string(buf)
- c, err := yaml.ParseString(rawConfig)
+ parsedConfig, err := yaml.ParseString(rawConfig)
if err != nil {
return err
}
@@ -95,40 +105,23 @@ func lintFile(_ *cli.Context, file string) error {
config := &linter.WorkflowConfig{
File: path.Base(file),
RawConfig: rawConfig,
- Workflow: c,
+ Workflow: parsedConfig,
}
// TODO: lint multiple files at once to allow checks for sth like "depends_on" to work
- err = linter.New(linter.WithTrusted(true)).Lint([]*linter.WorkflowConfig{config})
+ err = linter.New(
+ linter.WithTrusted(true),
+ linter.PrivilegedPlugins(c.StringSlice("plugins-privileged")),
+ linter.WithTrustedClonePlugins(c.StringSlice("plugins-trusted-clone")),
+ ).Lint([]*linter.WorkflowConfig{config})
if err != nil {
- fmt.Printf("🔥 %s has warnings / errors:\n", output.String(config.File).Underline())
+ str, err := FormatLintError(config.File, err)
- hasErrors := false
- for _, err := range pipeline_errors.GetPipelineErrors(err) {
- line := " "
-
- if err.IsWarning {
- line = fmt.Sprintf("%s ⚠️ ", line)
- } else {
- line = fmt.Sprintf("%s ❌", line)
- hasErrors = true
- }
-
- if data := pipeline_errors.GetLinterData(err); data != nil {
- line = fmt.Sprintf("%s %s\t%s", line, output.String(data.Field).Bold(), err.Message)
- } else {
- line = fmt.Sprintf("%s %s", line, err.Message)
- }
-
- // TODO: use table output
- fmt.Printf("%s\n", line)
+ if str != "" {
+ fmt.Print(str)
}
- if hasErrors {
- return errors.New("config has errors")
- }
-
- return nil
+ return err
}
fmt.Println("✅ Config is valid")
diff --git a/cli/lint/utils.go b/cli/lint/utils.go
new file mode 100644
index 000000000..5a062ae3e
--- /dev/null
+++ b/cli/lint/utils.go
@@ -0,0 +1,56 @@
+package lint
+
+import (
+ "errors"
+ "fmt"
+ "os"
+
+ term_env "github.com/muesli/termenv"
+
+ pipeline_errors "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors"
+)
+
+func FormatLintError(file string, err error) (string, error) {
+ if err == nil {
+ return "", nil
+ }
+
+ output := term_env.NewOutput(os.Stdout)
+ str := ""
+
+ amountErrors := 0
+ amountWarnings := 0
+ linterErrors := pipeline_errors.GetPipelineErrors(err)
+ for _, err := range linterErrors {
+ line := " "
+
+ if err.IsWarning {
+ line = fmt.Sprintf("%s ⚠️ ", line)
+ amountWarnings++
+ } else {
+ line = fmt.Sprintf("%s ❌", line)
+ amountErrors++
+ }
+
+ if data := pipeline_errors.GetLinterData(err); data != nil {
+ line = fmt.Sprintf("%s %s\t%s", line, output.String(data.Field).Bold(), err.Message)
+ } else {
+ line = fmt.Sprintf("%s %s", line, err.Message)
+ }
+
+ // TODO: use table output
+ str = fmt.Sprintf("%s%s\n", str, line)
+ }
+
+ if amountErrors > 0 {
+ if amountWarnings > 0 {
+ str = fmt.Sprintf("🔥 %s has %d errors and warnings:\n%s", output.String(file).Underline(), len(linterErrors), str)
+ } else {
+ str = fmt.Sprintf("🔥 %s has %d errors:\n%s", output.String(file).Underline(), len(linterErrors), str)
+ }
+ return str, errors.New("config has errors")
+ }
+
+ str = fmt.Sprintf("⚠️ %s has %d warnings:\n%s", output.String(file).Underline(), len(linterErrors), str)
+ return str, nil
+}
diff --git a/cli/log/log.go b/cli/log/log.go
index b9436c534..2ca1e1c90 100644
--- a/cli/log/log.go
+++ b/cli/log/log.go
@@ -15,14 +15,14 @@
package log
import (
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
)
// Command exports the log command set.
var Command = &cli.Command{
Name: "log",
Usage: "manage logs",
- Subcommands: []*cli.Command{
+ Commands: []*cli.Command{
logPurgeCmd,
},
}
diff --git a/cli/log/log_purge.go b/cli/log/log_purge.go
index 8a62ac79d..44070289b 100644
--- a/cli/log/log_purge.go
+++ b/cli/log/log_purge.go
@@ -15,10 +15,11 @@
package log
import (
+ "context"
"fmt"
"strconv"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
)
@@ -26,44 +27,52 @@ import (
var logPurgeCmd = &cli.Command{
Name: "purge",
Usage: "purge a log",
- ArgsUsage: " [step]",
+ ArgsUsage: " [step-number|step-name]",
Action: logPurge,
}
-func logPurge(c *cli.Context) (err error) {
- client, err := internal.NewClient(c)
+func logPurge(ctx context.Context, c *cli.Command) (err error) {
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
repoIDOrFullName := c.Args().First()
+ if len(repoIDOrFullName) == 0 {
+ return fmt.Errorf("missing required argument repo-id / repo-full-name")
+ }
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
if err != nil {
- return err
+ return fmt.Errorf("invalid repo '%s': %w", repoIDOrFullName, err)
}
- number, err := strconv.ParseInt(c.Args().Get(1), 10, 64)
+
+ pipelineArg := c.Args().Get(1)
+ if len(pipelineArg) == 0 {
+ return fmt.Errorf("missing required argument pipeline")
+ }
+ number, err := strconv.ParseInt(pipelineArg, 10, 64)
if err != nil {
return err
}
stepArg := c.Args().Get(2) //nolint:mnd
- // TODO: Add lookup by name: stepID, err := internal.ParseStep(client, repoID, stepIDOrName)
var stepID int64
if len(stepArg) != 0 {
- stepID, err = strconv.ParseInt(stepArg, 10, 64)
+ stepID, err = internal.ParseStep(client, repoID, number, stepArg)
if err != nil {
return err
}
}
if stepID > 0 {
+ fmt.Printf("Purging logs for pipeline %s#%d step %d\n", repoIDOrFullName, number, stepID)
err = client.StepLogsPurge(repoID, number, stepID)
} else {
+ fmt.Printf("Purging logs for pipeline %s#%d\n", repoIDOrFullName, number)
err = client.LogsPurge(repoID, number)
}
if err != nil {
return err
}
- fmt.Printf("Purging logs for pipeline %s#%d\n", repoIDOrFullName, number)
return nil
}
diff --git a/cli/loglevel/loglevel.go b/cli/loglevel/loglevel.go
index 1908260e0..947e99eaf 100644
--- a/cli/loglevel/loglevel.go
+++ b/cli/loglevel/loglevel.go
@@ -15,9 +15,11 @@
package loglevel
import (
+ "context"
+
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
@@ -31,8 +33,8 @@ var Command = &cli.Command{
Action: logLevel,
}
-func logLevel(c *cli.Context) error {
- client, err := internal.NewClient(c)
+func logLevel(ctx context.Context, c *cli.Command) error {
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/server/store/datastore/migration/015_remove_active_from_users.go b/cli/org/org.go
similarity index 60%
rename from server/store/datastore/migration/015_remove_active_from_users.go
rename to cli/org/org.go
index d0eb785d1..c7b9cd840 100644
--- a/server/store/datastore/migration/015_remove_active_from_users.go
+++ b/cli/org/org.go
@@ -1,10 +1,10 @@
-// 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.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -12,16 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package migration
+package org
import (
- "src.techknowlogick.com/xormigrate"
- "xorm.io/xorm"
+ "github.com/urfave/cli/v3"
+
+ "go.woodpecker-ci.org/woodpecker/v2/cli/org/registry"
)
-var removeActiveFromUsers = xormigrate.Migration{
- ID: "remove-active-from-users",
- MigrateSession: func(sess *xorm.Session) error {
- return dropTableColumns(sess, "users", "user_active")
+// Command exports the org command set.
+var Command = &cli.Command{
+ Name: "org",
+ Usage: "manage organizations",
+ Commands: []*cli.Command{
+ registry.Command,
},
}
diff --git a/cli/org/registry/registry.go b/cli/org/registry/registry.go
new file mode 100644
index 000000000..aa4f9f23b
--- /dev/null
+++ b/cli/org/registry/registry.go
@@ -0,0 +1,60 @@
+// 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 registry
+
+import (
+ "strconv"
+
+ "github.com/urfave/cli/v3"
+
+ "go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
+)
+
+// Command exports the registry command set.
+var Command = &cli.Command{
+ Name: "registry",
+ Usage: "manage organization registries",
+ Commands: []*cli.Command{
+ registryCreateCmd,
+ registryDeleteCmd,
+ registryUpdateCmd,
+ registryInfoCmd,
+ registryListCmd,
+ },
+}
+
+func parseTargetArgs(client woodpecker.Client, c *cli.Command) (orgID int64, err error) {
+ orgIDOrName := c.String("organization")
+ if orgIDOrName == "" {
+ orgIDOrName = c.Args().First()
+ }
+
+ if orgIDOrName == "" {
+ if err := cli.ShowSubcommandHelp(c); err != nil {
+ return -1, err
+ }
+ }
+
+ if orgID, err := strconv.ParseInt(orgIDOrName, 10, 64); err == nil {
+ return orgID, nil
+ }
+
+ org, err := client.OrgLookup(orgIDOrName)
+ if err != nil {
+ return -1, err
+ }
+
+ return org.ID, nil
+}
diff --git a/cli/org/registry/registry_add.go b/cli/org/registry/registry_add.go
new file mode 100644
index 000000000..d82859f00
--- /dev/null
+++ b/cli/org/registry/registry_add.go
@@ -0,0 +1,84 @@
+// 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 registry
+
+import (
+ "context"
+ "os"
+ "strings"
+
+ "github.com/urfave/cli/v3"
+
+ "go.woodpecker-ci.org/woodpecker/v2/cli/common"
+ "go.woodpecker-ci.org/woodpecker/v2/cli/internal"
+ "go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
+)
+
+var registryCreateCmd = &cli.Command{
+ Name: "add",
+ Usage: "adds a registry",
+ ArgsUsage: "[org-id|org-full-name]",
+ Action: registryCreate,
+ Flags: []cli.Flag{
+ common.OrgFlag,
+ &cli.StringFlag{
+ Name: "hostname",
+ Usage: "registry hostname",
+ Value: "docker.io",
+ },
+ &cli.StringFlag{
+ Name: "username",
+ Usage: "registry username",
+ },
+ &cli.StringFlag{
+ Name: "password",
+ Usage: "registry password",
+ },
+ },
+}
+
+func registryCreate(ctx context.Context, c *cli.Command) error {
+ var (
+ hostname = c.String("hostname")
+ username = c.String("username")
+ password = c.String("password")
+ )
+
+ client, err := internal.NewClient(ctx, c)
+ if err != nil {
+ return err
+ }
+ registry := &woodpecker.Registry{
+ Address: hostname,
+ Username: username,
+ Password: password,
+ }
+ if strings.HasPrefix(registry.Password, "@") {
+ path := strings.TrimPrefix(registry.Password, "@")
+ out, err := os.ReadFile(path)
+ if err != nil {
+ return err
+ }
+ registry.Password = string(out)
+ }
+
+ orgID, err := parseTargetArgs(client, c)
+ if err != nil {
+ return err
+ }
+
+ _, err = client.OrgRegistryCreate(orgID, registry)
+ return err
+}
diff --git a/cli/org/registry/registry_info.go b/cli/org/registry/registry_info.go
new file mode 100644
index 000000000..752c54c18
--- /dev/null
+++ b/cli/org/registry/registry_info.go
@@ -0,0 +1,70 @@
+// 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 registry
+
+import (
+ "context"
+ "html/template"
+ "os"
+
+ "github.com/urfave/cli/v3"
+
+ "go.woodpecker-ci.org/woodpecker/v2/cli/common"
+ "go.woodpecker-ci.org/woodpecker/v2/cli/internal"
+)
+
+var registryInfoCmd = &cli.Command{
+ Name: "info",
+ Usage: "display registry info",
+ ArgsUsage: "[org-id|org-full-name]",
+ Action: registryInfo,
+ Flags: []cli.Flag{
+ common.OrgFlag,
+ &cli.StringFlag{
+ Name: "hostname",
+ Usage: "registry hostname",
+ Value: "docker.io",
+ },
+ common.FormatFlag(tmplRegistryList, true),
+ },
+}
+
+func registryInfo(ctx context.Context, c *cli.Command) error {
+ var (
+ hostname = c.String("hostname")
+ format = c.String("format") + "\n"
+ )
+
+ client, err := internal.NewClient(ctx, c)
+ if err != nil {
+ return err
+ }
+
+ orgID, err := parseTargetArgs(client, c)
+ if err != nil {
+ return err
+ }
+
+ registry, err := client.OrgRegistry(orgID, hostname)
+ if err != nil {
+ return err
+ }
+
+ tmpl, err := template.New("_").Parse(format)
+ if err != nil {
+ return err
+ }
+ return tmpl.Execute(os.Stdout, registry)
+}
diff --git a/cli/org/registry/registry_list.go b/cli/org/registry/registry_list.go
new file mode 100644
index 000000000..1829d0401
--- /dev/null
+++ b/cli/org/registry/registry_list.go
@@ -0,0 +1,73 @@
+// 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 registry
+
+import (
+ "context"
+ "html/template"
+ "os"
+
+ "github.com/urfave/cli/v3"
+
+ "go.woodpecker-ci.org/woodpecker/v2/cli/common"
+ "go.woodpecker-ci.org/woodpecker/v2/cli/internal"
+)
+
+var registryListCmd = &cli.Command{
+ Name: "ls",
+ Usage: "list registries",
+ ArgsUsage: "[org-id|org-full-name]",
+ Action: registryList,
+ Flags: []cli.Flag{
+ common.OrgFlag,
+ common.FormatFlag(tmplRegistryList, true),
+ },
+}
+
+func registryList(ctx context.Context, c *cli.Command) error {
+ format := c.String("format") + "\n"
+
+ client, err := internal.NewClient(ctx, c)
+ if err != nil {
+ return err
+ }
+
+ orgID, err := parseTargetArgs(client, c)
+ if err != nil {
+ return err
+ }
+
+ list, err := client.OrgRegistryList(orgID)
+ if err != nil {
+ return err
+ }
+
+ tmpl, err := template.New("_").Parse(format)
+ if err != nil {
+ return err
+ }
+ for _, registry := range list {
+ if err := tmpl.Execute(os.Stdout, registry); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Template for registry list information.
+var tmplRegistryList = "\x1b[33m{{ .Address }} \x1b[0m" + `
+Username: {{ .Username }}
+Email: {{ .Email }}
+`
diff --git a/cli/org/registry/registry_rm.go b/cli/org/registry/registry_rm.go
new file mode 100644
index 000000000..8157e1626
--- /dev/null
+++ b/cli/org/registry/registry_rm.go
@@ -0,0 +1,55 @@
+// 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 registry
+
+import (
+ "context"
+
+ "github.com/urfave/cli/v3"
+
+ "go.woodpecker-ci.org/woodpecker/v2/cli/common"
+ "go.woodpecker-ci.org/woodpecker/v2/cli/internal"
+)
+
+var registryDeleteCmd = &cli.Command{
+ Name: "rm",
+ Usage: "remove a registry",
+ ArgsUsage: "[org-id|org-full-name]",
+ Action: registryDelete,
+ Flags: []cli.Flag{
+ common.OrgFlag,
+ &cli.StringFlag{
+ Name: "hostname",
+ Usage: "registry hostname",
+ Value: "docker.io",
+ },
+ },
+}
+
+func registryDelete(ctx context.Context, c *cli.Command) error {
+ hostname := c.String("hostname")
+
+ client, err := internal.NewClient(ctx, c)
+ if err != nil {
+ return err
+ }
+
+ orgID, err := parseTargetArgs(client, c)
+ if err != nil {
+ return err
+ }
+
+ return client.OrgRegistryDelete(orgID, hostname)
+}
diff --git a/cli/org/registry/registry_set.go b/cli/org/registry/registry_set.go
new file mode 100644
index 000000000..e08e2af4f
--- /dev/null
+++ b/cli/org/registry/registry_set.go
@@ -0,0 +1,85 @@
+// 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 registry
+
+import (
+ "context"
+ "os"
+ "strings"
+
+ "github.com/urfave/cli/v3"
+
+ "go.woodpecker-ci.org/woodpecker/v2/cli/common"
+ "go.woodpecker-ci.org/woodpecker/v2/cli/internal"
+ "go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
+)
+
+var registryUpdateCmd = &cli.Command{
+ Name: "update",
+ Usage: "update a registry",
+ ArgsUsage: "[org-id|org-full-name]",
+ Action: registryUpdate,
+ Flags: []cli.Flag{
+ common.OrgFlag,
+ &cli.StringFlag{
+ Name: "hostname",
+ Usage: "registry hostname",
+ Value: "docker.io",
+ },
+ &cli.StringFlag{
+ Name: "username",
+ Usage: "registry username",
+ },
+ &cli.StringFlag{
+ Name: "password",
+ Usage: "registry password",
+ },
+ },
+}
+
+func registryUpdate(ctx context.Context, c *cli.Command) error {
+ var (
+ hostname = c.String("hostname")
+ username = c.String("username")
+ password = c.String("password")
+ )
+
+ client, err := internal.NewClient(ctx, c)
+ if err != nil {
+ return err
+ }
+
+ registry := &woodpecker.Registry{
+ Address: hostname,
+ Username: username,
+ Password: password,
+ }
+ if strings.HasPrefix(registry.Password, "@") {
+ path := strings.TrimPrefix(registry.Password, "@")
+ out, err := os.ReadFile(path)
+ if err != nil {
+ return err
+ }
+ registry.Password = string(out)
+ }
+
+ orgID, err := parseTargetArgs(client, c)
+ if err != nil {
+ return err
+ }
+
+ _, err = client.OrgRegistryUpdate(orgID, registry)
+ return err
+}
diff --git a/cli/pipeline/approve.go b/cli/pipeline/approve.go
index 4e2185b27..ae99324f5 100644
--- a/cli/pipeline/approve.go
+++ b/cli/pipeline/approve.go
@@ -15,10 +15,11 @@
package pipeline
import (
+ "context"
"fmt"
"strconv"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
)
@@ -30,9 +31,9 @@ var pipelineApproveCmd = &cli.Command{
Action: pipelineApprove,
}
-func pipelineApprove(c *cli.Context) (err error) {
+func pipelineApprove(ctx context.Context, c *cli.Command) (err error) {
repoIDOrFullName := c.Args().First()
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/pipeline/create.go b/cli/pipeline/create.go
index 008a27f3e..e343c24a0 100644
--- a/cli/pipeline/create.go
+++ b/cli/pipeline/create.go
@@ -15,9 +15,10 @@
package pipeline
import (
+ "context"
"strings"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -42,9 +43,9 @@ var pipelineCreateCmd = &cli.Command{
}...),
}
-func pipelineCreate(c *cli.Context) error {
+func pipelineCreate(ctx context.Context, c *cli.Command) error {
repoIDOrFullName := c.Args().First()
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/pipeline/decline.go b/cli/pipeline/decline.go
index b99b13452..f44179ba8 100644
--- a/cli/pipeline/decline.go
+++ b/cli/pipeline/decline.go
@@ -15,10 +15,11 @@
package pipeline
import (
+ "context"
"fmt"
"strconv"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
)
@@ -30,9 +31,9 @@ var pipelineDeclineCmd = &cli.Command{
Action: pipelineDecline,
}
-func pipelineDecline(c *cli.Context) (err error) {
+func pipelineDecline(ctx context.Context, c *cli.Command) (err error) {
repoIDOrFullName := c.Args().First()
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/pipeline/info.go b/cli/pipeline/info.go
index 91cae4743..660c1c72b 100644
--- a/cli/pipeline/info.go
+++ b/cli/pipeline/info.go
@@ -15,9 +15,10 @@
package pipeline
import (
+ "context"
"strconv"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -32,9 +33,9 @@ var pipelineInfoCmd = &cli.Command{
Flags: common.OutputFlags("table"),
}
-func pipelineInfo(c *cli.Context) error {
+func pipelineInfo(ctx context.Context, c *cli.Command) error {
repoIDOrFullName := c.Args().First()
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/pipeline/kill.go b/cli/pipeline/kill.go
index 3c8fa3fb9..872719765 100644
--- a/cli/pipeline/kill.go
+++ b/cli/pipeline/kill.go
@@ -15,10 +15,11 @@
package pipeline
import (
+ "context"
"fmt"
"strconv"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
)
@@ -31,14 +32,14 @@ var pipelineKillCmd = &cli.Command{
Hidden: true,
}
-func pipelineKill(c *cli.Context) (err error) {
+func pipelineKill(ctx context.Context, c *cli.Command) (err error) {
number, err := strconv.ParseInt(c.Args().Get(1), 10, 64)
if err != nil {
return err
}
repoIDOrFullName := c.Args().First()
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/pipeline/last.go b/cli/pipeline/last.go
index e0af7d17f..3d911d0fa 100644
--- a/cli/pipeline/last.go
+++ b/cli/pipeline/last.go
@@ -15,7 +15,9 @@
package pipeline
import (
- "github.com/urfave/cli/v2"
+ "context"
+
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -36,9 +38,9 @@ var pipelineLastCmd = &cli.Command{
}...),
}
-func pipelineLast(c *cli.Context) error {
+func pipelineLast(ctx context.Context, c *cli.Command) error {
repoIDOrFullName := c.Args().First()
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/pipeline/list.go b/cli/pipeline/list.go
index 6a3576323..f8b798674 100644
--- a/cli/pipeline/list.go
+++ b/cli/pipeline/list.go
@@ -15,7 +15,9 @@
package pipeline
import (
- "github.com/urfave/cli/v2"
+ "context"
+
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -49,19 +51,19 @@ var pipelineListCmd = &cli.Command{
}...),
}
-func List(c *cli.Context) error {
- client, err := internal.NewClient(c)
+func List(ctx context.Context, c *cli.Command) error {
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
- resources, err := pipelineList(c, client)
+ resources, err := pipelineList(ctx, c, client)
if err != nil {
return err
}
return pipelineOutput(c, resources)
}
-func pipelineList(c *cli.Context, client woodpecker.Client) ([]woodpecker.Pipeline, error) {
+func pipelineList(_ context.Context, c *cli.Command, client woodpecker.Client) ([]woodpecker.Pipeline, error) {
resources := make([]woodpecker.Pipeline, 0)
repoIDOrFullName := c.Args().First()
@@ -78,7 +80,7 @@ func pipelineList(c *cli.Context, client woodpecker.Client) ([]woodpecker.Pipeli
branch := c.String("branch")
event := c.String("event")
status := c.String("status")
- limit := c.Int("limit")
+ limit := int(c.Int("limit"))
var count int
for _, pipeline := range pipelines {
diff --git a/cli/pipeline/list_test.go b/cli/pipeline/list_test.go
index 0f913bf71..55ce4578c 100644
--- a/cli/pipeline/list_test.go
+++ b/cli/pipeline/list_test.go
@@ -1,13 +1,14 @@
package pipeline
import (
+ "context"
"errors"
"io"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker/mocks"
@@ -109,12 +110,10 @@ func TestPipelineList(t *testing.T) {
mockClient.On("PipelineList", mock.Anything).Return(tt.pipelines, tt.pipelineErr)
mockClient.On("RepoLookup", mock.Anything).Return(&woodpecker.Repo{ID: tt.repoID}, nil)
- app := &cli.App{Writer: io.Discard}
- c := cli.NewContext(app, nil, nil)
-
command := pipelineListCmd
- command.Action = func(c *cli.Context) error {
- pipelines, err := pipelineList(c, mockClient)
+ command.Writer = io.Discard
+ command.Action = func(ctx context.Context, c *cli.Command) error {
+ pipelines, err := pipelineList(ctx, c, mockClient)
if tt.wantErr != nil {
assert.EqualError(t, err, tt.wantErr.Error())
return nil
@@ -126,7 +125,7 @@ func TestPipelineList(t *testing.T) {
return nil
}
- _ = command.Run(c, tt.args...)
+ _ = command.Run(context.Background(), tt.args)
})
}
}
diff --git a/cli/pipeline/logs.go b/cli/pipeline/logs.go
index 116d68a4d..f7725bc46 100644
--- a/cli/pipeline/logs.go
+++ b/cli/pipeline/logs.go
@@ -15,52 +15,98 @@
package pipeline
import (
+ "context"
"fmt"
+ "os"
"strconv"
+ "text/template"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
+ "go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
)
var pipelineLogsCmd = &cli.Command{
Name: "logs",
Usage: "show pipeline logs",
- ArgsUsage: " [pipeline] [stepID]",
+ ArgsUsage: " [step-number|step-name]",
Action: pipelineLogs,
}
-func pipelineLogs(c *cli.Context) error {
+func pipelineLogs(ctx context.Context, c *cli.Command) error {
repoIDOrFullName := c.Args().First()
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
+ if len(repoIDOrFullName) == 0 {
+ return fmt.Errorf("missing required argument repo-id / repo-full-name")
+ }
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
if err != nil {
- return err
+ return fmt.Errorf("invalid repo '%s': %w ", repoIDOrFullName, err)
}
- numberArgIndex := 1
- number, err := strconv.ParseInt(c.Args().Get(numberArgIndex), 10, 64)
+ pipelineArg := c.Args().Get(1)
+ if len(pipelineArg) == 0 {
+ return fmt.Errorf("missing required argument pipeline")
+ }
+ number, err := strconv.ParseInt(pipelineArg, 10, 64)
+ if err != nil {
+ return fmt.Errorf("invalid pipeline '%s': %w", pipelineArg, err)
+ }
+
+ stepArg := c.Args().Get(2) //nolint:mnd
+ if len(stepArg) == 0 {
+ return showPipelineLog(client, repoID, number)
+ }
+
+ step, err := internal.ParseStep(client, repoID, number, stepArg)
+ if err != nil {
+ return fmt.Errorf("invalid step '%s': %w", stepArg, err)
+ }
+ return showStepLog(client, repoID, number, step)
+}
+
+func showPipelineLog(client woodpecker.Client, repoID, number int64) error {
+ pipeline, err := client.Pipeline(repoID, number)
if err != nil {
return err
}
- stepArgIndex := 2
- step, err := strconv.ParseInt(c.Args().Get(stepArgIndex), 10, 64)
+ tmpl, err := template.New("_").Parse(tmplPipelineLogs + "\n")
if err != nil {
return err
}
+ for _, workflow := range pipeline.Workflows {
+ for _, step := range workflow.Children {
+ if err := tmpl.Execute(os.Stdout, map[string]any{"workflow": workflow, "step": step}); err != nil {
+ return err
+ }
+ err := showStepLog(client, repoID, number, step.ID)
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ return nil
+}
+
+func showStepLog(client woodpecker.Client, repoID, number, step int64) error {
logs, err := client.StepLogEntries(repoID, number, step)
if err != nil {
return err
}
for _, log := range logs {
- fmt.Print(string(log.Data))
+ fmt.Println(string(log.Data))
}
return nil
}
+
+// template for pipeline ps information.
+var tmplPipelineLogs = "\x1b[33m{{ .workflow.Name }} > {{ .step.Name }} (#{{ .step.PID }}):\x1b[0m"
diff --git a/cli/pipeline/pipeline.go b/cli/pipeline/pipeline.go
index f596538cb..38fba42d1 100644
--- a/cli/pipeline/pipeline.go
+++ b/cli/pipeline/pipeline.go
@@ -20,7 +20,7 @@ import (
"os"
"text/template"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/output"
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
@@ -30,7 +30,7 @@ import (
var Command = &cli.Command{
Name: "pipeline",
Usage: "manage pipelines",
- Subcommands: []*cli.Command{
+ Commands: []*cli.Command{
pipelineListCmd,
pipelineLastCmd,
pipelineLogsCmd,
@@ -46,7 +46,7 @@ var Command = &cli.Command{
},
}
-func pipelineOutput(c *cli.Context, resources []woodpecker.Pipeline, fd ...io.Writer) error {
+func pipelineOutput(c *cli.Command, resources []woodpecker.Pipeline, fd ...io.Writer) error {
outFmt, outOpt := output.ParseOutputOptions(c.String("output"))
noHeader := c.Bool("output-no-headers")
@@ -77,7 +77,7 @@ func pipelineOutput(c *cli.Context, resources []woodpecker.Pipeline, fd ...io.Wr
fallthrough
default:
table := output.NewTable(out)
- cols := []string{"Number", "Status", "Event", "Branch", "Commit", "Author"}
+ cols := []string{"Number", "Status", "Event", "Branch", "Message", "Author"}
if len(outOpt) > 0 {
cols = outOpt
diff --git a/cli/pipeline/pipeline_test.go b/cli/pipeline/pipeline_test.go
index 7850c01b8..9812813d0 100644
--- a/cli/pipeline/pipeline_test.go
+++ b/cli/pipeline/pipeline_test.go
@@ -2,11 +2,12 @@ package pipeline
import (
"bytes"
+ "context"
"io"
"testing"
"github.com/stretchr/testify/assert"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
@@ -22,7 +23,7 @@ func TestPipelineOutput(t *testing.T) {
{
name: "table output with default columns",
args: []string{},
- expected: "NUMBER STATUS EVENT BRANCH COMMIT AUTHOR\n1 success push main abcdef John Doe\n",
+ expected: "NUMBER STATUS EVENT BRANCH MESSAGE AUTHOR\n1 success push main message John Doe\n",
},
{
name: "table output with custom columns",
@@ -32,7 +33,7 @@ func TestPipelineOutput(t *testing.T) {
{
name: "table output with no header",
args: []string{"output", "--output-no-headers"},
- expected: "1 success push main abcdef John Doe\n",
+ expected: "1 success push main message John Doe\n",
},
{
name: "go-template output",
@@ -48,39 +49,38 @@ func TestPipelineOutput(t *testing.T) {
pipelines := []woodpecker.Pipeline{
{
- Number: 1,
- Status: "success",
- Event: "push",
- Branch: "main",
- Commit: "abcdef",
- Author: "John Doe",
+ Number: 1,
+ Status: "success",
+ Event: "push",
+ Branch: "main",
+ Message: "message",
+ Author: "John Doe",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- app := &cli.App{Writer: io.Discard}
- c := cli.NewContext(app, nil, nil)
+ command := &cli.Command{
+ Writer: io.Discard,
+ Name: "output",
+ Flags: common.OutputFlags("table"),
+ Action: func(_ context.Context, c *cli.Command) error {
+ var buf bytes.Buffer
+ err := pipelineOutput(c, pipelines, &buf)
- command := &cli.Command{}
- command.Name = "output"
- command.Flags = common.OutputFlags("table")
- command.Action = func(c *cli.Context) error {
- var buf bytes.Buffer
- err := pipelineOutput(c, pipelines, &buf)
+ if tt.wantErr {
+ assert.Error(t, err)
+ return nil
+ }
+
+ assert.NoError(t, err)
+ assert.Equal(t, tt.expected, buf.String())
- if tt.wantErr {
- assert.Error(t, err)
return nil
- }
-
- assert.NoError(t, err)
- assert.Equal(t, tt.expected, buf.String())
-
- return nil
+ },
}
- _ = command.Run(c, tt.args...)
+ _ = command.Run(context.Background(), tt.args)
})
}
}
diff --git a/cli/pipeline/ps.go b/cli/pipeline/ps.go
index bba6f4043..6aca08545 100644
--- a/cli/pipeline/ps.go
+++ b/cli/pipeline/ps.go
@@ -15,11 +15,13 @@
package pipeline
import (
+ "context"
+ "fmt"
"os"
"strconv"
"text/template"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -28,20 +30,20 @@ import (
var pipelinePsCmd = &cli.Command{
Name: "ps",
Usage: "show pipeline steps",
- ArgsUsage: " [pipeline]",
+ ArgsUsage: " ",
Action: pipelinePs,
Flags: []cli.Flag{common.FormatFlag(tmplPipelinePs)},
}
-func pipelinePs(c *cli.Context) error {
+func pipelinePs(ctx context.Context, c *cli.Command) error {
repoIDOrFullName := c.Args().First()
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
if err != nil {
- return err
+ return fmt.Errorf("invalid repo '%s': %w", repoIDOrFullName, err)
}
pipelineArg := c.Args().Get(1)
@@ -58,7 +60,7 @@ func pipelinePs(c *cli.Context) error {
} else {
number, err = strconv.ParseInt(pipelineArg, 10, 64)
if err != nil {
- return err
+ return fmt.Errorf("invalid pipeline '%s': %w", pipelineArg, err)
}
}
@@ -72,9 +74,9 @@ func pipelinePs(c *cli.Context) error {
return err
}
- for _, step := range pipeline.Workflows {
- for _, child := range step.Children {
- if err := tmpl.Execute(os.Stdout, child); err != nil {
+ for _, workflow := range pipeline.Workflows {
+ for _, step := range workflow.Children {
+ if err := tmpl.Execute(os.Stdout, map[string]any{"workflow": workflow, "step": step}); err != nil {
return err
}
}
@@ -83,8 +85,11 @@ func pipelinePs(c *cli.Context) error {
return nil
}
-// Template for pipeline ps information.
-var tmplPipelinePs = "\x1b[33mStep #{{ .PID }} \x1b[0m" + `
-Step: {{ .Name }}
-State: {{ .State }}
+// template for pipeline ps information.
+var tmplPipelinePs = "\x1b[33m{{ .workflow.Name }} > {{ .step.Name }} (#{{ .step.PID }}):\x1b[0m" + `
+Step: {{ .step.Name }}
+Started: {{ .step.Started }}
+Stopped: {{ .step.Stopped }}
+Type: {{ .step.Type }}
+State: {{ .step.State }}
`
diff --git a/cli/pipeline/queue.go b/cli/pipeline/queue.go
index 1fbccd8a3..ffa123d4e 100644
--- a/cli/pipeline/queue.go
+++ b/cli/pipeline/queue.go
@@ -15,11 +15,12 @@
package pipeline
import (
+ "context"
"fmt"
"os"
"text/template"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -33,8 +34,8 @@ var pipelineQueueCmd = &cli.Command{
Flags: []cli.Flag{common.FormatFlag(tmplPipelineQueue)},
}
-func pipelineQueue(c *cli.Context) error {
- client, err := internal.NewClient(c)
+func pipelineQueue(ctx context.Context, c *cli.Command) error {
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/pipeline/start.go b/cli/pipeline/start.go
index c3d870982..4eeeaf5f2 100644
--- a/cli/pipeline/start.go
+++ b/cli/pipeline/start.go
@@ -15,11 +15,12 @@
package pipeline
import (
+ "context"
"errors"
"fmt"
"strconv"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
)
@@ -38,9 +39,9 @@ var pipelineStartCmd = &cli.Command{
},
}
-func pipelineStart(c *cli.Context) (err error) {
+func pipelineStart(ctx context.Context, c *cli.Command) (err error) {
repoIDOrFullName := c.Args().First()
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/pipeline/stop.go b/cli/pipeline/stop.go
index 4d949f9cb..a69352249 100644
--- a/cli/pipeline/stop.go
+++ b/cli/pipeline/stop.go
@@ -15,10 +15,11 @@
package pipeline
import (
+ "context"
"fmt"
"strconv"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
)
@@ -30,9 +31,9 @@ var pipelineStopCmd = &cli.Command{
Action: pipelineStop,
}
-func pipelineStop(c *cli.Context) (err error) {
+func pipelineStop(ctx context.Context, c *cli.Command) (err error) {
repoIDOrFullName := c.Args().First()
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/repo/registry/registry.go b/cli/repo/registry/registry.go
new file mode 100644
index 000000000..df3f09446
--- /dev/null
+++ b/cli/repo/registry/registry.go
@@ -0,0 +1,44 @@
+// Copyright 2023 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 registry
+
+import (
+ "github.com/urfave/cli/v3"
+
+ "go.woodpecker-ci.org/woodpecker/v2/cli/internal"
+ "go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
+)
+
+// Command exports the registry command set.
+var Command = &cli.Command{
+ Name: "registry",
+ Usage: "manage registries",
+ Commands: []*cli.Command{
+ registryCreateCmd,
+ registryDeleteCmd,
+ registryUpdateCmd,
+ registryInfoCmd,
+ registryListCmd,
+ },
+}
+
+func parseTargetArgs(client woodpecker.Client, c *cli.Command) (repoID int64, err error) {
+ repoIDOrFullName := c.String("repository")
+ if repoIDOrFullName == "" {
+ repoIDOrFullName = c.Args().First()
+ }
+
+ return internal.ParseRepo(client, repoIDOrFullName)
+}
diff --git a/cli/registry/registry_add.go b/cli/repo/registry/registry_add.go
similarity index 76%
rename from cli/registry/registry_add.go
rename to cli/repo/registry/registry_add.go
index 13d6ed25c..e894a698c 100644
--- a/cli/registry/registry_add.go
+++ b/cli/repo/registry/registry_add.go
@@ -15,10 +15,11 @@
package registry
import (
+ "context"
"os"
"strings"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -48,21 +49,14 @@ var registryCreateCmd = &cli.Command{
},
}
-func registryCreate(c *cli.Context) error {
+func registryCreate(ctx context.Context, c *cli.Command) error {
var (
- hostname = c.String("hostname")
- username = c.String("username")
- password = c.String("password")
- repoIDOrFullName = c.String("repository")
+ hostname = c.String("hostname")
+ username = c.String("username")
+ password = c.String("password")
)
- if repoIDOrFullName == "" {
- repoIDOrFullName = c.Args().First()
- }
- client, err := internal.NewClient(c)
- if err != nil {
- return err
- }
- repoID, err := internal.ParseRepo(client, repoIDOrFullName)
+
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
@@ -79,8 +73,12 @@ func registryCreate(c *cli.Context) error {
}
registry.Password = string(out)
}
- if _, err := client.RegistryCreate(repoID, registry); err != nil {
+
+ repoID, err := parseTargetArgs(client, c)
+ if err != nil {
return err
}
- return nil
+
+ _, err = client.RegistryCreate(repoID, registry)
+ return err
}
diff --git a/cli/registry/registry_info.go b/cli/repo/registry/registry_info.go
similarity index 78%
rename from cli/registry/registry_info.go
rename to cli/repo/registry/registry_info.go
index 8bbfceeba..f171d1d23 100644
--- a/cli/registry/registry_info.go
+++ b/cli/repo/registry/registry_info.go
@@ -15,10 +15,11 @@
package registry
import (
+ "context"
"html/template"
"os"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -40,27 +41,27 @@ var registryInfoCmd = &cli.Command{
},
}
-func registryInfo(c *cli.Context) error {
+func registryInfo(ctx context.Context, c *cli.Command) error {
var (
- hostname = c.String("hostname")
- repoIDOrFullName = c.String("repository")
- format = c.String("format") + "\n"
+ hostname = c.String("hostname")
+ format = c.String("format") + "\n"
)
- if repoIDOrFullName == "" {
- repoIDOrFullName = c.Args().First()
- }
- client, err := internal.NewClient(c)
+
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
- repoID, err := internal.ParseRepo(client, repoIDOrFullName)
+
+ repoID, err := parseTargetArgs(client, c)
if err != nil {
return err
}
+
registry, err := client.Registry(repoID, hostname)
if err != nil {
return err
}
+
tmpl, err := template.New("_").Parse(format)
if err != nil {
return err
diff --git a/cli/registry/registry_list.go b/cli/repo/registry/registry_list.go
similarity index 81%
rename from cli/registry/registry_list.go
rename to cli/repo/registry/registry_list.go
index 99221903d..0cb6f80b8 100644
--- a/cli/registry/registry_list.go
+++ b/cli/repo/registry/registry_list.go
@@ -15,10 +15,11 @@
package registry
import (
+ "context"
"html/template"
"os"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -35,26 +36,24 @@ var registryListCmd = &cli.Command{
},
}
-func registryList(c *cli.Context) error {
- var (
- format = c.String("format") + "\n"
- repoIDOrFullName = c.String("repository")
- )
- if repoIDOrFullName == "" {
- repoIDOrFullName = c.Args().First()
- }
- client, err := internal.NewClient(c)
+func registryList(ctx context.Context, c *cli.Command) error {
+ format := c.String("format") + "\n"
+
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
- repoID, err := internal.ParseRepo(client, repoIDOrFullName)
+
+ repoID, err := parseTargetArgs(client, c)
if err != nil {
return err
}
+
list, err := client.RegistryList(repoID)
if err != nil {
return err
}
+
tmpl, err := template.New("_").Parse(format)
if err != nil {
return err
diff --git a/cli/registry/registry_rm.go b/cli/repo/registry/registry_rm.go
similarity index 77%
rename from cli/registry/registry_rm.go
rename to cli/repo/registry/registry_rm.go
index 108c7b772..4b3437d48 100644
--- a/cli/registry/registry_rm.go
+++ b/cli/repo/registry/registry_rm.go
@@ -15,7 +15,9 @@
package registry
import (
- "github.com/urfave/cli/v2"
+ "context"
+
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -36,21 +38,18 @@ var registryDeleteCmd = &cli.Command{
},
}
-func registryDelete(c *cli.Context) error {
- var (
- hostname = c.String("hostname")
- repoIDOrFullName = c.String("repository")
- )
- if repoIDOrFullName == "" {
- repoIDOrFullName = c.Args().First()
- }
- client, err := internal.NewClient(c)
+func registryDelete(ctx context.Context, c *cli.Command) error {
+ hostname := c.String("hostname")
+
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
- repoID, err := internal.ParseRepo(client, repoIDOrFullName)
+
+ repoID, err := parseTargetArgs(client, c)
if err != nil {
return err
}
+
return client.RegistryDelete(repoID, hostname)
}
diff --git a/cli/registry/registry_set.go b/cli/repo/registry/registry_set.go
similarity index 80%
rename from cli/registry/registry_set.go
rename to cli/repo/registry/registry_set.go
index 48916ddad..4af39f5c2 100644
--- a/cli/registry/registry_set.go
+++ b/cli/repo/registry/registry_set.go
@@ -15,10 +15,11 @@
package registry
import (
+ "context"
"os"
"strings"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -48,24 +49,18 @@ var registryUpdateCmd = &cli.Command{
},
}
-func registryUpdate(c *cli.Context) error {
+func registryUpdate(ctx context.Context, c *cli.Command) error {
var (
- hostname = c.String("hostname")
- username = c.String("username")
- password = c.String("password")
- repoIDOrFullName = c.String("repository")
+ hostname = c.String("hostname")
+ username = c.String("username")
+ password = c.String("password")
)
- if repoIDOrFullName == "" {
- repoIDOrFullName = c.Args().First()
- }
- client, err := internal.NewClient(c)
- if err != nil {
- return err
- }
- repoID, err := internal.ParseRepo(client, repoIDOrFullName)
+
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
+
registry := &woodpecker.Registry{
Address: hostname,
Username: username,
@@ -79,6 +74,12 @@ func registryUpdate(c *cli.Context) error {
}
registry.Password = string(out)
}
+
+ repoID, err := parseTargetArgs(client, c)
+ if err != nil {
+ return err
+ }
+
_, err = client.RegistryUpdate(repoID, registry)
return err
}
diff --git a/cli/repo/repo.go b/cli/repo/repo.go
index 43e8d5338..1be57743e 100644
--- a/cli/repo/repo.go
+++ b/cli/repo/repo.go
@@ -15,14 +15,16 @@
package repo
import (
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
+
+ "go.woodpecker-ci.org/woodpecker/v2/cli/repo/registry"
)
// Command exports the repository command.
var Command = &cli.Command{
Name: "repo",
Usage: "manage repositories",
- Subcommands: []*cli.Command{
+ Commands: []*cli.Command{
repoListCmd,
repoInfoCmd,
repoAddCmd,
@@ -31,5 +33,6 @@ var Command = &cli.Command{
repoRepairCmd,
repoChownCmd,
repoSyncCmd,
+ registry.Command,
},
}
diff --git a/cli/repo/repo_add.go b/cli/repo/repo_add.go
index 00094b40c..594b8dd73 100644
--- a/cli/repo/repo_add.go
+++ b/cli/repo/repo_add.go
@@ -15,10 +15,11 @@
package repo
import (
+ "context"
"fmt"
"strconv"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
)
@@ -30,14 +31,14 @@ var repoAddCmd = &cli.Command{
Action: repoAdd,
}
-func repoAdd(c *cli.Context) error {
+func repoAdd(ctx context.Context, c *cli.Command) error {
_forgeRemoteID := c.Args().First()
forgeRemoteID, err := strconv.Atoi(_forgeRemoteID)
if err != nil {
return fmt.Errorf("invalid forge remote id: %s", _forgeRemoteID)
}
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/repo/repo_chown.go b/cli/repo/repo_chown.go
index 050a3975a..118940184 100644
--- a/cli/repo/repo_chown.go
+++ b/cli/repo/repo_chown.go
@@ -15,9 +15,10 @@
package repo
import (
+ "context"
"fmt"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
)
@@ -29,9 +30,9 @@ var repoChownCmd = &cli.Command{
Action: repoChown,
}
-func repoChown(c *cli.Context) error {
+func repoChown(ctx context.Context, c *cli.Command) error {
repoIDOrFullName := c.Args().First()
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/repo/repo_info.go b/cli/repo/repo_info.go
index 72d4bf7a6..e92d55be1 100644
--- a/cli/repo/repo_info.go
+++ b/cli/repo/repo_info.go
@@ -15,10 +15,11 @@
package repo
import (
+ "context"
"os"
"text/template"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -32,9 +33,9 @@ var repoInfoCmd = &cli.Command{
Flags: []cli.Flag{common.FormatFlag(tmplRepoInfo)},
}
-func repoInfo(c *cli.Context) error {
+func repoInfo(ctx context.Context, c *cli.Command) error {
repoIDOrFullName := c.Args().First()
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/repo/repo_list.go b/cli/repo/repo_list.go
index 9aa569338..d3e4d1dd3 100644
--- a/cli/repo/repo_list.go
+++ b/cli/repo/repo_list.go
@@ -15,10 +15,11 @@
package repo
import (
+ "context"
"os"
"text/template"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -38,8 +39,8 @@ var repoListCmd = &cli.Command{
},
}
-func repoList(c *cli.Context) error {
- client, err := internal.NewClient(c)
+func repoList(ctx context.Context, c *cli.Command) error {
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/repo/repo_repair.go b/cli/repo/repo_repair.go
index 15ab3157f..35ca8f398 100644
--- a/cli/repo/repo_repair.go
+++ b/cli/repo/repo_repair.go
@@ -15,9 +15,10 @@
package repo
import (
+ "context"
"fmt"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
)
@@ -29,9 +30,9 @@ var repoRepairCmd = &cli.Command{
Action: repoRepair,
}
-func repoRepair(c *cli.Context) error {
+func repoRepair(ctx context.Context, c *cli.Command) error {
repoIDOrFullName := c.Args().First()
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/repo/repo_rm.go b/cli/repo/repo_rm.go
index 5603cd336..b884dccf3 100644
--- a/cli/repo/repo_rm.go
+++ b/cli/repo/repo_rm.go
@@ -15,9 +15,10 @@
package repo
import (
+ "context"
"fmt"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
)
@@ -29,9 +30,9 @@ var repoRemoveCmd = &cli.Command{
Action: repoRemove,
}
-func repoRemove(c *cli.Context) error {
+func repoRemove(ctx context.Context, c *cli.Command) error {
repoIDOrFullName := c.Args().First()
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/repo/repo_sync.go b/cli/repo/repo_sync.go
index 14f13401f..17727eb83 100644
--- a/cli/repo/repo_sync.go
+++ b/cli/repo/repo_sync.go
@@ -15,10 +15,11 @@
package repo
import (
+ "context"
"os"
"text/template"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -33,8 +34,8 @@ var repoSyncCmd = &cli.Command{
}
// TODO: remove this and add an option to the list cmd as we do not store the remote repo list anymore
-func repoSync(c *cli.Context) error {
- client, err := internal.NewClient(c)
+func repoSync(ctx context.Context, c *cli.Command) error {
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/repo/repo_update.go b/cli/repo/repo_update.go
index 51999bc76..049bf0242 100644
--- a/cli/repo/repo_update.go
+++ b/cli/repo/repo_update.go
@@ -15,10 +15,11 @@
package repo
import (
+ "context"
"fmt"
"time"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
@@ -61,9 +62,9 @@ var repoUpdateCmd = &cli.Command{
},
}
-func repoUpdate(c *cli.Context) error {
+func repoUpdate(ctx context.Context, c *cli.Command) error {
repoIDOrFullName := c.Args().First()
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
@@ -78,7 +79,7 @@ func repoUpdate(c *cli.Context) error {
timeout = c.Duration("timeout")
trusted = c.Bool("trusted")
gated = c.Bool("gated")
- pipelineCounter = c.Int("pipeline-counter")
+ pipelineCounter = int(c.Int("pipeline-counter"))
unsafe = c.Bool("unsafe")
)
diff --git a/cli/secret/secret.go b/cli/secret/secret.go
index 0e78d8d0d..e44149241 100644
--- a/cli/secret/secret.go
+++ b/cli/secret/secret.go
@@ -19,7 +19,7 @@ import (
"strconv"
"strings"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
@@ -29,7 +29,7 @@ import (
var Command = &cli.Command{
Name: "secret",
Usage: "manage secrets",
- Subcommands: []*cli.Command{
+ Commands: []*cli.Command{
secretCreateCmd,
secretDeleteCmd,
secretUpdateCmd,
@@ -38,7 +38,7 @@ var Command = &cli.Command{
},
}
-func parseTargetArgs(client woodpecker.Client, c *cli.Context) (global bool, orgID, repoID int64, err error) {
+func parseTargetArgs(client woodpecker.Client, c *cli.Command) (global bool, orgID, repoID int64, err error) {
if c.Bool("global") {
return true, -1, -1, nil
}
diff --git a/cli/secret/secret_add.go b/cli/secret/secret_add.go
index 16b75e0e0..452ddc46d 100644
--- a/cli/secret/secret_add.go
+++ b/cli/secret/secret_add.go
@@ -15,10 +15,11 @@
package secret
import (
+ "context"
"os"
"strings"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -56,8 +57,8 @@ var secretCreateCmd = &cli.Command{
},
}
-func secretCreate(c *cli.Context) error {
- client, err := internal.NewClient(c)
+func secretCreate(ctx context.Context, c *cli.Command) error {
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/secret/secret_info.go b/cli/secret/secret_info.go
index 02d1a5d5e..f645741b9 100644
--- a/cli/secret/secret_info.go
+++ b/cli/secret/secret_info.go
@@ -15,10 +15,12 @@
package secret
import (
+ "context"
+ "fmt"
"html/template"
"os"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -45,12 +47,17 @@ var secretInfoCmd = &cli.Command{
},
}
-func secretInfo(c *cli.Context) error {
+func secretInfo(ctx context.Context, c *cli.Command) error {
var (
secretName = c.String("name")
format = c.String("format") + "\n"
)
- client, err := internal.NewClient(c)
+
+ if secretName == "" {
+ return fmt.Errorf("secret name is missing")
+ }
+
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/secret/secret_list.go b/cli/secret/secret_list.go
index e698cb505..4645089bc 100644
--- a/cli/secret/secret_list.go
+++ b/cli/secret/secret_list.go
@@ -15,11 +15,12 @@
package secret
import (
+ "context"
"html/template"
"os"
"strings"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -42,10 +43,10 @@ var secretListCmd = &cli.Command{
},
}
-func secretList(c *cli.Context) error {
+func secretList(ctx context.Context, c *cli.Command) error {
format := c.String("format") + "\n"
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/secret/secret_rm.go b/cli/secret/secret_rm.go
index 0dbc0c188..fa7d5b82f 100644
--- a/cli/secret/secret_rm.go
+++ b/cli/secret/secret_rm.go
@@ -15,7 +15,9 @@
package secret
import (
- "github.com/urfave/cli/v2"
+ "context"
+
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -40,10 +42,10 @@ var secretDeleteCmd = &cli.Command{
},
}
-func secretDelete(c *cli.Context) error {
+func secretDelete(ctx context.Context, c *cli.Command) error {
secretName := c.String("name")
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/secret/secret_set.go b/cli/secret/secret_set.go
index c1e0d1443..d8c0c38ce 100644
--- a/cli/secret/secret_set.go
+++ b/cli/secret/secret_set.go
@@ -15,10 +15,11 @@
package secret
import (
+ "context"
"os"
"strings"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -56,8 +57,8 @@ var secretUpdateCmd = &cli.Command{
},
}
-func secretUpdate(c *cli.Context) error {
- client, err := internal.NewClient(c)
+func secretUpdate(ctx context.Context, c *cli.Command) error {
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/setup/setup.go b/cli/setup/setup.go
index 1d3126efe..6705482e9 100644
--- a/cli/setup/setup.go
+++ b/cli/setup/setup.go
@@ -1,11 +1,12 @@
package setup
import (
+ "context"
"errors"
"strings"
"github.com/rs/zerolog/log"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal/config"
"go.woodpecker-ci.org/woodpecker/v2/cli/setup/ui"
@@ -15,7 +16,6 @@ import (
var Command = &cli.Command{
Name: "setup",
Usage: "setup the woodpecker-cli for the first time",
- Args: true,
ArgsUsage: "[server]",
Flags: []cli.Flag{
&cli.StringFlag{
@@ -30,8 +30,8 @@ var Command = &cli.Command{
Action: setup,
}
-func setup(c *cli.Context) error {
- _config, err := config.Get(c, c.String("config"))
+func setup(ctx context.Context, c *cli.Command) error {
+ _config, err := config.Get(ctx, c, c.String("config"))
if err != nil {
return err
} else if _config != nil {
@@ -68,7 +68,7 @@ func setup(c *cli.Context) error {
token := c.String("token")
if token == "" {
- token, err = receiveTokenFromUI(c.Context, serverURL)
+ token, err = receiveTokenFromUI(ctx, serverURL)
if err != nil {
return err
}
@@ -78,7 +78,7 @@ func setup(c *cli.Context) error {
}
}
- err = config.Save(c, c.String("config"), &config.Config{
+ err = config.Save(ctx, c, c.String("config"), &config.Config{
ServerURL: serverURL,
Token: token,
LogLevel: "info",
diff --git a/cli/update/command.go b/cli/update/command.go
index 786a5c62b..ad856402f 100644
--- a/cli/update/command.go
+++ b/cli/update/command.go
@@ -1,12 +1,13 @@
package update
import (
+ "context"
"fmt"
"os"
"path/filepath"
"github.com/rs/zerolog/log"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
)
// Command exports the update command.
@@ -22,10 +23,10 @@ var Command = &cli.Command{
Action: update,
}
-func update(c *cli.Context) error {
+func update(ctx context.Context, c *cli.Command) error {
log.Info().Msg("Checking for updates ...")
- newVersion, err := CheckForUpdate(c.Context, c.Bool("force"))
+ newVersion, err := CheckForUpdate(ctx, c.Bool("force"))
if err != nil {
return err
}
@@ -38,7 +39,7 @@ func update(c *cli.Context) error {
log.Info().Msgf("New version %s is available! Updating ...", newVersion.Version)
var tarFilePath string
- tarFilePath, err = downloadNewVersion(c.Context, newVersion.AssetURL)
+ tarFilePath, err = downloadNewVersion(ctx, newVersion.AssetURL)
if err != nil {
return err
}
diff --git a/cli/user/user.go b/cli/user/user.go
index a2323b672..78b552b36 100644
--- a/cli/user/user.go
+++ b/cli/user/user.go
@@ -15,14 +15,14 @@
package user
import (
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
)
// Command exports the user command set.
var Command = &cli.Command{
Name: "user",
Usage: "manage users",
- Subcommands: []*cli.Command{
+ Commands: []*cli.Command{
userListCmd,
userInfoCmd,
userAddCmd,
diff --git a/cli/user/user_add.go b/cli/user/user_add.go
index f3828b699..80012158e 100644
--- a/cli/user/user_add.go
+++ b/cli/user/user_add.go
@@ -15,9 +15,10 @@
package user
import (
+ "context"
"fmt"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
@@ -30,10 +31,10 @@ var userAddCmd = &cli.Command{
Action: userAdd,
}
-func userAdd(c *cli.Context) error {
+func userAdd(ctx context.Context, c *cli.Command) error {
login := c.Args().First()
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/user/user_info.go b/cli/user/user_info.go
index 7747f5d18..bfebed93f 100644
--- a/cli/user/user_info.go
+++ b/cli/user/user_info.go
@@ -15,11 +15,12 @@
package user
import (
+ "context"
"fmt"
"os"
"text/template"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -33,8 +34,8 @@ var userInfoCmd = &cli.Command{
Flags: []cli.Flag{common.FormatFlag(tmplUserInfo)},
}
-func userInfo(c *cli.Context) error {
- client, err := internal.NewClient(c)
+func userInfo(ctx context.Context, c *cli.Command) error {
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/user/user_list.go b/cli/user/user_list.go
index 63863b95f..4e721f0f4 100644
--- a/cli/user/user_list.go
+++ b/cli/user/user_list.go
@@ -15,10 +15,11 @@
package user
import (
+ "context"
"os"
"text/template"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
@@ -32,8 +33,8 @@ var userListCmd = &cli.Command{
Flags: []cli.Flag{common.FormatFlag(tmplUserList)},
}
-func userList(c *cli.Context) error {
- client, err := internal.NewClient(c)
+func userList(ctx context.Context, c *cli.Command) error {
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cli/user/user_rm.go b/cli/user/user_rm.go
index 081b0cf23..962fc03a1 100644
--- a/cli/user/user_rm.go
+++ b/cli/user/user_rm.go
@@ -15,9 +15,10 @@
package user
import (
+ "context"
"fmt"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
)
@@ -29,10 +30,10 @@ var userRemoveCmd = &cli.Command{
Action: userRemove,
}
-func userRemove(c *cli.Context) error {
+func userRemove(ctx context.Context, c *cli.Command) error {
login := c.Args().First()
- client, err := internal.NewClient(c)
+ client, err := internal.NewClient(ctx, c)
if err != nil {
return err
}
diff --git a/cmd/agent/core/agent.go b/cmd/agent/core/agent.go
index 1e6c57067..f0c7f0071 100644
--- a/cmd/agent/core/agent.go
+++ b/cmd/agent/core/agent.go
@@ -23,12 +23,12 @@ import (
"net/http"
"os"
"strings"
- "sync"
+ "sync/atomic"
"time"
"github.com/rs/zerolog/log"
- "github.com/tevino/abool/v2"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
+ "golang.org/x/sync/errgroup"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
grpc_credentials "google.golang.org/grpc/credentials"
@@ -47,26 +47,71 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/version"
)
-func run(c *cli.Context, backends []types.Backend) error {
+const (
+ reportHealthInterval = time.Second * 10
+ authInterceptorRefreshInterval = time.Minute * 30
+)
+
+const (
+ shutdownTimeout = time.Second * 5
+)
+
+var (
+ stopAgentFunc context.CancelCauseFunc = func(error) {}
+ shutdownCancelFunc context.CancelFunc = func() {}
+ shutdownCtx = context.Background()
+)
+
+func run(ctx context.Context, c *cli.Command, backends []types.Backend) error {
+ agentCtx, ctxCancel := context.WithCancelCause(ctx)
+ stopAgentFunc = func(err error) {
+ msg := "shutdown of whole agent"
+ if err != nil {
+ log.Error().Err(err).Msg(msg)
+ } else {
+ log.Info().Msg(msg)
+ }
+ stopAgentFunc = func(error) {}
+ shutdownCtx, shutdownCancelFunc = context.WithTimeout(shutdownCtx, shutdownTimeout)
+ ctxCancel(err)
+ }
+ defer stopAgentFunc(nil)
+ defer shutdownCancelFunc()
+
+ serviceWaitingGroup := errgroup.Group{}
+
agentConfigPath := c.String("agent-config")
hostname := c.String("hostname")
if len(hostname) == 0 {
hostname, _ = os.Hostname()
}
- counter.Polling = c.Int("max-workflows")
+ counter.Polling = int(c.Int("max-workflows"))
counter.Running = 0
if c.Bool("healthcheck") {
- go func() {
- if err := http.ListenAndServe(c.String("healthcheck-addr"), nil); err != nil {
- log.Error().Err(err).Msgf("cannot listen on address %s", c.String("healthcheck-addr"))
- }
- }()
+ serviceWaitingGroup.Go(
+ func() error {
+ server := &http.Server{Addr: c.String("healthcheck-addr")}
+ go func() {
+ <-agentCtx.Done()
+ log.Info().Msg("shutdown healthcheck server ...")
+ if err := server.Shutdown(shutdownCtx); err != nil { //nolint:contextcheck
+ log.Error().Err(err).Msg("shutdown healthcheck server failed")
+ } else {
+ log.Info().Msg("healthcheck server stopped")
+ }
+ }()
+ if err := server.ListenAndServe(); err != nil {
+ log.Error().Err(err).Msgf("cannot listen on address %s", c.String("healthcheck-addr"))
+ }
+ return nil
+ })
}
var transport grpc.DialOption
if c.Bool("grpc-secure") {
+ log.Trace().Msg("use ssl for grpc")
transport = grpc.WithTransportCredentials(grpc_credentials.NewTLS(&tls.Config{InsecureSkipVerify: c.Bool("grpc-skip-insecure")}))
} else {
transport = grpc.WithTransportCredentials(insecure.NewCredentials())
@@ -81,17 +126,19 @@ func run(c *cli.Context, backends []types.Backend) error {
}),
)
if err != nil {
- return err
+ return fmt.Errorf("could not create new gRPC 'channel' for authentication: %w", err)
}
defer authConn.Close()
agentConfig := readAgentConfig(agentConfigPath)
agentToken := c.String("grpc-token")
+ grpcClientCtx, grpcClientCtxCancel := context.WithCancelCause(context.Background())
+ defer grpcClientCtxCancel(nil)
authClient := agent_rpc.NewAuthGrpcClient(authConn, agentToken, agentConfig.AgentID)
- authInterceptor, err := agent_rpc.NewAuthInterceptor(authClient, 30*time.Minute) //nolint:mnd
+ authInterceptor, err := agent_rpc.NewAuthInterceptor(grpcClientCtx, authClient, authInterceptorRefreshInterval) //nolint:contextcheck
if err != nil {
- return err
+ return fmt.Errorf("could not create new auth interceptor: %w", err)
}
conn, err := grpc.NewClient(
@@ -105,35 +152,17 @@ func run(c *cli.Context, backends []types.Backend) error {
grpc.WithStreamInterceptor(authInterceptor.Stream()),
)
if err != nil {
- return err
+ return fmt.Errorf("could not create new gRPC 'channel' for normal orchestration: %w", err)
}
defer conn.Close()
- client := agent_rpc.NewGrpcClient(conn)
+ client := agent_rpc.NewGrpcClient(ctx, conn)
+ agentConfigPersisted := atomic.Bool{}
- sigterm := abool.New()
- ctx := metadata.NewOutgoingContext(
- context.Background(),
- metadata.Pairs("hostname", hostname),
- )
-
- agentConfigPersisted := abool.New()
- ctx = utils.WithContextSigtermCallback(ctx, func() {
- log.Info().Msg("termination signal is received, shutting down")
- sigterm.Set()
-
- // Remove stateless agents from server
- if agentConfigPersisted.IsNotSet() {
- log.Debug().Msg("unregistering agent from server")
- err := client.UnregisterAgent(ctx)
- if err != nil {
- log.Err(err).Msg("failed to unregister agent from server")
- }
- }
- })
+ grpcCtx := metadata.NewOutgoingContext(grpcClientCtx, metadata.Pairs("hostname", hostname))
// check if grpc server version is compatible with agent
- grpcServerVersion, err := client.Version(ctx)
+ grpcServerVersion, err := client.Version(grpcCtx) //nolint:contextcheck
if err != nil {
log.Error().Err(err).Msg("could not get grpc server version")
return err
@@ -147,12 +176,8 @@ func run(c *cli.Context, backends []types.Backend) error {
return err
}
- var wg sync.WaitGroup
- parallel := c.Int("max-workflows")
- wg.Add(parallel)
-
// new engine
- backendCtx := context.WithValue(ctx, types.CliContext, c)
+ backendCtx := context.WithValue(agentCtx, types.CliCommand, c)
backendName := c.String("backend-engine")
backendEngine, err := backend.FindBackend(backendCtx, backends, backendName)
if err != nil {
@@ -172,14 +197,34 @@ func run(c *cli.Context, backends []types.Backend) error {
}
log.Debug().Msgf("loaded %s backend engine", backendEngine.Name())
- agentConfig.AgentID, err = client.RegisterAgent(ctx, engInfo.Platform, backendEngine.Name(), version.String(), parallel)
+ maxWorkflows := int(c.Int("max-workflows"))
+ agentConfig.AgentID, err = client.RegisterAgent(grpcCtx, engInfo.Platform, backendEngine.Name(), version.String(), maxWorkflows) //nolint:contextcheck
if err != nil {
return err
}
+ serviceWaitingGroup.Go(func() error {
+ // we close grpc client context once unregister was handled
+ defer grpcClientCtxCancel(nil)
+ // we wait till agent context is done
+ <-agentCtx.Done()
+ // Remove stateless agents from server
+ if !agentConfigPersisted.Load() {
+ log.Debug().Msg("unregistering agent from server ...")
+ // we want to run it explicit run when context got canceled so run it in background
+ err := client.UnregisterAgent(grpcClientCtx)
+ if err != nil {
+ log.Err(err).Msg("failed to unregister agent from server")
+ } else {
+ log.Info().Msg("agent unregistered from server")
+ }
+ }
+ return nil
+ })
+
if agentConfigPath != "" {
if err := writeAgentConfig(agentConfig, agentConfigPath); err == nil {
- agentConfigPersisted.Set()
+ agentConfigPersisted.Store(true)
}
}
@@ -200,67 +245,62 @@ func run(c *cli.Context, backends []types.Backend) error {
log.Debug().Msgf("agent registered with ID %d", agentConfig.AgentID)
- go func() {
+ serviceWaitingGroup.Go(func() error {
for {
- if sigterm.IsSet() {
- log.Debug().Msg("terminating health reporting")
- return
- }
-
- err := client.ReportHealth(ctx)
+ err := client.ReportHealth(grpcCtx)
if err != nil {
log.Err(err).Msg("failed to report health")
- return
}
- <-time.After(time.Second * 10)
+ select {
+ case <-agentCtx.Done():
+ log.Debug().Msg("terminating health reporting")
+ return nil
+ case <-time.After(reportHealthInterval):
+ }
}
- }()
+ })
- for i := 0; i < parallel; i++ {
+ for i := 0; i < maxWorkflows; i++ {
i := i
- go func() {
- defer wg.Done()
-
- r := agent.NewRunner(client, filter, hostname, counter, &backendEngine)
+ serviceWaitingGroup.Go(func() error {
+ runner := agent.NewRunner(client, filter, hostname, counter, &backendEngine)
log.Debug().Msgf("created new runner %d", i)
for {
- if sigterm.IsSet() {
- log.Debug().Msgf("terminating runner %d", i)
- return
+ if agentCtx.Err() != nil {
+ return nil
}
log.Debug().Msg("polling new steps")
- if err := r.Run(ctx); err != nil {
- log.Error().Err(err).Msg("pipeline done with error")
- return
+ if err := runner.Run(agentCtx, shutdownCtx); err != nil {
+ log.Error().Err(err).Msg("runner done with error")
+ return err
}
}
- }()
+ })
}
log.Info().Msgf(
"starting Woodpecker agent with version '%s' and backend '%s' using platform '%s' running up to %d pipelines in parallel",
- version.String(), backendEngine.Name(), engInfo.Platform, parallel)
+ version.String(), backendEngine.Name(), engInfo.Platform, maxWorkflows)
- wg.Wait()
- return nil
+ return serviceWaitingGroup.Wait()
}
-func runWithRetry(backendEngines []types.Backend) func(context *cli.Context) error {
- return func(context *cli.Context) error {
- if err := logger.SetupGlobalLogger(context, true); err != nil {
+func runWithRetry(backendEngines []types.Backend) func(ctx context.Context, c *cli.Command) error {
+ return func(ctx context.Context, c *cli.Command) error {
+ if err := logger.SetupGlobalLogger(ctx, c, true); err != nil {
return err
}
initHealth()
- retryCount := context.Int("connect-retry-count")
- retryDelay := context.Duration("connect-retry-delay")
+ retryCount := int(c.Int("connect-retry-count"))
+ retryDelay := c.Duration("connect-retry-delay")
var err error
for i := 0; i < retryCount; i++ {
- if err = run(context, backendEngines); status.Code(err) == codes.Unavailable {
+ if err = run(ctx, c, backendEngines); status.Code(err) == codes.Unavailable {
log.Warn().Err(err).Msg(fmt.Sprintf("cannot connect to server, retrying in %v", retryDelay))
time.Sleep(retryDelay)
} else {
diff --git a/cmd/agent/core/flags.go b/cmd/agent/core/flags.go
index f0ab7cbcd..6770e36bd 100644
--- a/cmd/agent/core/flags.go
+++ b/cmd/agent/core/flags.go
@@ -19,93 +19,94 @@ import (
"os"
"time"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
)
//nolint:mnd
var flags = []cli.Flag{
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_SERVER"},
+ Sources: cli.EnvVars("WOODPECKER_SERVER"),
Name: "server",
Usage: "server address",
Value: "localhost:9000",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_AGENT_SECRET"},
- Name: "grpc-token",
- Usage: "server-agent shared token",
- FilePath: os.Getenv("WOODPECKER_AGENT_SECRET_FILE"),
+ Name: "grpc-token",
+ Usage: "server-agent shared token",
+ Sources: cli.NewValueSourceChain(
+ cli.File(os.Getenv("WOODPECKER_AGENT_SECRET_FILE")),
+ cli.EnvVar("WOODPECKER_AGENT_SECRET")),
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_GRPC_SECURE"},
+ Sources: cli.EnvVars("WOODPECKER_GRPC_SECURE"),
Name: "grpc-secure",
Usage: "should the connection to WOODPECKER_SERVER be made using a secure transport",
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_GRPC_VERIFY"},
+ Sources: cli.EnvVars("WOODPECKER_GRPC_VERIFY"),
Name: "grpc-skip-insecure",
Usage: "should the grpc server certificate be verified, only valid when WOODPECKER_GRPC_SECURE is true",
Value: true,
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_HOSTNAME"},
+ Sources: cli.EnvVars("WOODPECKER_HOSTNAME"),
Name: "hostname",
Usage: "agent hostname",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_AGENT_CONFIG_FILE"},
+ Sources: cli.EnvVars("WOODPECKER_AGENT_CONFIG_FILE"),
Name: "agent-config",
Usage: "agent config file path, if set empty the agent will be stateless and unregister on termination",
Value: "/etc/woodpecker/agent.conf",
},
&cli.StringSliceFlag{
- EnvVars: []string{"WOODPECKER_FILTER_LABELS"},
+ Sources: cli.EnvVars("WOODPECKER_FILTER_LABELS"),
Name: "filter",
Usage: "List of labels to filter tasks on. An agent must be assigned every tag listed in a task to be selected.",
},
&cli.IntFlag{
- EnvVars: []string{"WOODPECKER_MAX_WORKFLOWS", "WOODPECKER_MAX_PROCS"}, // cspell:words PROCS
+ Sources: cli.EnvVars("WOODPECKER_MAX_WORKFLOWS", "WOODPECKER_MAX_PROCS"), // cspell:words PROCS
Name: "max-workflows",
Usage: "agent parallel workflows",
Value: 1,
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_HEALTHCHECK"},
+ Sources: cli.EnvVars("WOODPECKER_HEALTHCHECK"),
Name: "healthcheck",
Usage: "enable healthcheck endpoint",
Value: true,
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_HEALTHCHECK_ADDR"},
+ Sources: cli.EnvVars("WOODPECKER_HEALTHCHECK_ADDR"),
Name: "healthcheck-addr",
Usage: "healthcheck endpoint address",
Value: ":3000",
},
&cli.DurationFlag{
- EnvVars: []string{"WOODPECKER_KEEPALIVE_TIME"},
+ Sources: cli.EnvVars("WOODPECKER_KEEPALIVE_TIME"),
Name: "keepalive-time",
Usage: "after a duration of this time of no activity, the agent pings the server to check if the transport is still alive",
},
&cli.DurationFlag{
- EnvVars: []string{"WOODPECKER_KEEPALIVE_TIMEOUT"},
+ Sources: cli.EnvVars("WOODPECKER_KEEPALIVE_TIMEOUT"),
Name: "keepalive-timeout",
Usage: "after pinging for a keepalive check, the agent waits for a duration of this time before closing the connection if no activity",
Value: time.Second * 20,
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_BACKEND"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND"),
Name: "backend-engine",
Usage: "backend to run pipelines on",
Value: "auto-detect",
},
&cli.IntFlag{
- EnvVars: []string{"WOODPECKER_CONNECT_RETRY_COUNT"},
+ Sources: cli.EnvVars("WOODPECKER_CONNECT_RETRY_COUNT"),
Name: "connect-retry-count",
Usage: "number of times to retry connecting to the server",
Value: 5,
},
&cli.DurationFlag{
- EnvVars: []string{"WOODPECKER_CONNECT_RETRY_DELAY"},
+ Sources: cli.EnvVars("WOODPECKER_CONNECT_RETRY_DELAY"),
Name: "connect-retry-delay",
Usage: "duration to wait before retrying to connect to the server",
Value: time.Second * 2,
diff --git a/cmd/agent/core/health.go b/cmd/agent/core/health.go
index 263bd3269..b9c6398b1 100644
--- a/cmd/agent/core/health.go
+++ b/cmd/agent/core/health.go
@@ -15,13 +15,14 @@
package core
import (
+ "context"
"encoding/json"
"fmt"
"net/http"
"strings"
"github.com/rs/zerolog/log"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/agent"
"go.woodpecker-ci.org/woodpecker/v2/version"
@@ -81,13 +82,18 @@ var counter = &agent.State{
// handles pinging the endpoint and returns an error if the
// agent is in an unhealthy state.
-func pinger(c *cli.Context) error {
+func pinger(ctx context.Context, c *cli.Command) error {
healthcheckAddress := c.String("healthcheck-addr")
if strings.HasPrefix(healthcheckAddress, ":") {
// this seems sufficient according to https://pkg.go.dev/net#Dial
healthcheckAddress = "localhost" + healthcheckAddress
}
- resp, err := http.Get("http://" + healthcheckAddress + "/healthz")
+
+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://"+healthcheckAddress+"/healthz", nil)
+ if err != nil {
+ return err
+ }
+ resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
diff --git a/cmd/agent/core/run.go b/cmd/agent/core/run.go
index 9c64fec3d..3b01c2dc7 100644
--- a/cmd/agent/core/run.go
+++ b/cmd/agent/core/run.go
@@ -15,12 +15,13 @@
package core
import (
+ "context"
"os"
// Load config from .env file.
_ "github.com/joho/godotenv/autoload"
"github.com/rs/zerolog/log"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
backend "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
"go.woodpecker-ci.org/woodpecker/v2/shared/logger"
@@ -28,8 +29,8 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/version"
)
-func RunAgent(backends []backend.Backend) {
- app := cli.NewApp()
+func RunAgent(ctx context.Context, backends []backend.Backend) {
+ app := &cli.Command{}
app.Name = "woodpecker-agent"
app.Version = version.String()
app.Usage = "woodpecker agent"
@@ -47,7 +48,7 @@ func RunAgent(backends []backend.Backend) {
}
app.Flags = agentFlags
- if err := app.Run(os.Args); err != nil {
+ if err := app.Run(ctx, os.Args); err != nil {
log.Fatal().Err(err).Msg("error running agent") //nolint:forbidigo
}
}
diff --git a/server/store/datastore/migration/006_drop_senders.go b/cmd/agent/dummy.go
similarity index 67%
rename from server/store/datastore/migration/006_drop_senders.go
rename to cmd/agent/dummy.go
index f547bda09..398b50f10 100644
--- a/server/store/datastore/migration/006_drop_senders.go
+++ b/cmd/agent/dummy.go
@@ -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.
@@ -12,16 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package migration
+//go:build test
+// +build test
-import (
- "src.techknowlogick.com/xormigrate"
- "xorm.io/xorm"
-)
+package main
-var dropSenders = xormigrate.Migration{
- ID: "drop-senders",
- MigrateSession: func(sess *xorm.Session) error {
- return sess.DropTable("senders")
- },
+import "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/dummy"
+
+func init() { //nolint:gochecknoinits
+ backends = append(backends, dummy.New())
}
diff --git a/cmd/agent/main.go b/cmd/agent/main.go
index 062fc0729..37316195e 100644
--- a/cmd/agent/main.go
+++ b/cmd/agent/main.go
@@ -15,17 +15,27 @@
package main
import (
+ "context"
+
+ "github.com/rs/zerolog/log"
+
"go.woodpecker-ci.org/woodpecker/v2/cmd/agent/core"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/docker"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/kubernetes"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/local"
backendTypes "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
+ "go.woodpecker-ci.org/woodpecker/v2/shared/utils"
)
-func main() {
- core.RunAgent([]backendTypes.Backend{
- kubernetes.New(),
- docker.New(),
- local.New(),
- })
+var backends = []backendTypes.Backend{
+ kubernetes.New(),
+ docker.New(),
+ local.New(),
+}
+
+func main() {
+ ctx := utils.WithContextSigtermCallback(context.Background(), func() {
+ log.Info().Msg("termination signal is received, shutting down agent")
+ })
+ core.RunAgent(ctx, backends)
}
diff --git a/cmd/cli/app.go b/cmd/cli/app.go
index db6edca17..086914804 100644
--- a/cmd/cli/app.go
+++ b/cmd/cli/app.go
@@ -15,8 +15,9 @@
package main
import (
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
+ "go.woodpecker-ci.org/woodpecker/v2/cli/admin"
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
"go.woodpecker-ci.org/woodpecker/v2/cli/cron"
"go.woodpecker-ci.org/woodpecker/v2/cli/deploy"
@@ -25,8 +26,8 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/cli/lint"
"go.woodpecker-ci.org/woodpecker/v2/cli/log"
"go.woodpecker-ci.org/woodpecker/v2/cli/loglevel"
+ "go.woodpecker-ci.org/woodpecker/v2/cli/org"
"go.woodpecker-ci.org/woodpecker/v2/cli/pipeline"
- "go.woodpecker-ci.org/woodpecker/v2/cli/registry"
"go.woodpecker-ci.org/woodpecker/v2/cli/repo"
"go.woodpecker-ci.org/woodpecker/v2/cli/secret"
"go.woodpecker-ci.org/woodpecker/v2/cli/setup"
@@ -36,25 +37,26 @@ import (
)
//go:generate go run docs.go app.go
-func newApp() *cli.App {
- app := cli.NewApp()
+func newApp() *cli.Command {
+ app := &cli.Command{}
app.Name = "woodpecker-cli"
app.Description = "Woodpecker command line utility"
app.Version = version.String()
- app.EnableBashCompletion = true
+ app.Usage = "command line utility"
app.Flags = common.GlobalFlags
app.Before = common.Before
app.After = common.After
app.Suggest = true
app.Commands = []*cli.Command{
+ admin.Command,
+ org.Command,
+ repo.Command,
pipeline.Command,
log.Command,
deploy.Command,
exec.Command,
info.Command,
- registry.Command,
secret.Command,
- repo.Command,
user.Command,
lint.Command,
loglevel.Command,
diff --git a/cmd/cli/docs.go b/cmd/cli/docs.go
index 9ed83ef47..d8dae41de 100644
--- a/cmd/cli/docs.go
+++ b/cmd/cli/docs.go
@@ -19,11 +19,13 @@ package main
import (
"os"
+
+ docs "github.com/urfave/cli-docs/v3"
)
func main() {
app := newApp()
- md, err := app.ToMarkdown()
+ md, err := docs.ToMarkdown(app)
if err != nil {
panic(err)
}
diff --git a/cmd/cli/main.go b/cmd/cli/main.go
index d0b155868..eb0f309df 100644
--- a/cmd/cli/main.go
+++ b/cmd/cli/main.go
@@ -15,15 +15,22 @@
package main
import (
+ "context"
"os"
_ "github.com/joho/godotenv/autoload"
"github.com/rs/zerolog/log"
+
+ "go.woodpecker-ci.org/woodpecker/v2/shared/utils"
)
func main() {
+ ctx := utils.WithContextSigtermCallback(context.Background(), func() {
+ log.Info().Msg("termination signal is received, terminate cli")
+ })
+
app := newApp()
- if err := app.Run(os.Args); err != nil {
+ if err := app.Run(ctx, os.Args); err != nil {
log.Fatal().Err(err).Msg("error running cli") //nolint:forbidigo
}
}
diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go
index 7ea2dd04f..ac80d2883 100644
--- a/cmd/server/docs/docs.go
+++ b/cmd/server/docs/docs.go
@@ -849,19 +849,12 @@ const docTemplate = `{
"200": {
"description": "OK",
"schema": {
- "allOf": [
- {
+ "type": "object",
+ "properties": {
+ "log-level": {
"type": "string"
- },
- {
- "type": "object",
- "properties": {
- "log-level": {
- "type": "string"
- }
- }
}
- ]
+ }
}
}
}
@@ -890,19 +883,12 @@ const docTemplate = `{
"in": "body",
"required": true,
"schema": {
- "allOf": [
- {
+ "type": "object",
+ "properties": {
+ "log-level": {
"type": "string"
- },
- {
- "type": "object",
- "properties": {
- "log-level": {
- "type": "string"
- }
- }
}
- ]
+ }
}
}
],
@@ -910,19 +896,12 @@ const docTemplate = `{
"200": {
"description": "OK",
"schema": {
- "allOf": [
- {
+ "type": "object",
+ "properties": {
+ "log-level": {
"type": "string"
- },
- {
- "type": "object",
- "properties": {
- "log-level": {
- "type": "string"
- }
- }
}
- ]
+ }
}
}
}
@@ -1123,6 +1102,233 @@ const docTemplate = `{
}
}
},
+ "/orgs/{org_id}/registries": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "Organization registries"
+ ],
+ "summary": "List organization registries",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "Bearer \u003cpersonal access token\u003e",
+ "description": "Insert your personal access token",
+ "name": "Authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "the org's id",
+ "name": "org_id",
+ "in": "path",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "default": 1,
+ "description": "for response pagination, page offset number",
+ "name": "page",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "default": 50,
+ "description": "for response pagination, max items per page",
+ "name": "perPage",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Registry"
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "Organization registries"
+ ],
+ "summary": "Create an organization registry",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "Bearer \u003cpersonal access token\u003e",
+ "description": "Insert your personal access token",
+ "name": "Authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "the org's id",
+ "name": "org_id",
+ "in": "path",
+ "required": true
+ },
+ {
+ "description": "the new registry",
+ "name": "registryData",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/Registry"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/Registry"
+ }
+ }
+ }
+ }
+ },
+ "/orgs/{org_id}/registries/{registry}": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "Organization registries"
+ ],
+ "summary": "Get a organization registry by address",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "Bearer \u003cpersonal access token\u003e",
+ "description": "Insert your personal access token",
+ "name": "Authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "the org's id",
+ "name": "org_id",
+ "in": "path",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "the registry's address",
+ "name": "registry",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/Registry"
+ }
+ }
+ }
+ },
+ "delete": {
+ "produces": [
+ "text/plain"
+ ],
+ "tags": [
+ "Organization registries"
+ ],
+ "summary": "Delete an organization registry by name",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "Bearer \u003cpersonal access token\u003e",
+ "description": "Insert your personal access token",
+ "name": "Authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "the org's id",
+ "name": "org_id",
+ "in": "path",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "the registry's name",
+ "name": "registry",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "No Content"
+ }
+ }
+ },
+ "patch": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "Organization registries"
+ ],
+ "summary": "Update an organization registry by name",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "Bearer \u003cpersonal access token\u003e",
+ "description": "Insert your personal access token",
+ "name": "Authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "the org's id",
+ "name": "org_id",
+ "in": "path",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "the registry's name",
+ "name": "registry",
+ "in": "path",
+ "required": true
+ },
+ {
+ "description": "the update registry data",
+ "name": "registryData",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/Registry"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/Registry"
+ }
+ }
+ }
+ }
+ },
"/orgs/{org_id}/secrets": {
"get": {
"produces": [
@@ -1493,6 +1699,198 @@ const docTemplate = `{
}
}
},
+ "/registries": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "Registries"
+ ],
+ "summary": "List global registries",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "Bearer \u003cpersonal access token\u003e",
+ "description": "Insert your personal access token",
+ "name": "Authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "default": 1,
+ "description": "for response pagination, page offset number",
+ "name": "page",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "default": 50,
+ "description": "for response pagination, max items per page",
+ "name": "perPage",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Registry"
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "Registries"
+ ],
+ "summary": "Create a global registry",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "Bearer \u003cpersonal access token\u003e",
+ "description": "Insert your personal access token",
+ "name": "Authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "description": "the registry object data",
+ "name": "registry",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/Registry"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/Registry"
+ }
+ }
+ }
+ }
+ },
+ "/registries/{registry}": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "Registries"
+ ],
+ "summary": "Get a global registry by name",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "Bearer \u003cpersonal access token\u003e",
+ "description": "Insert your personal access token",
+ "name": "Authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "the registry's name",
+ "name": "registry",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/Registry"
+ }
+ }
+ }
+ },
+ "delete": {
+ "produces": [
+ "text/plain"
+ ],
+ "tags": [
+ "Registries"
+ ],
+ "summary": "Delete a global registry by name",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "Bearer \u003cpersonal access token\u003e",
+ "description": "Insert your personal access token",
+ "name": "Authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "the registry's name",
+ "name": "registry",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "No Content"
+ }
+ }
+ },
+ "patch": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "Registries"
+ ],
+ "summary": "Update a global registry by name",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "Bearer \u003cpersonal access token\u003e",
+ "description": "Insert your personal access token",
+ "name": "Authorization",
+ "in": "header",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "the registry's name",
+ "name": "registry",
+ "in": "path",
+ "required": true
+ },
+ {
+ "description": "the registry's data",
+ "name": "registryData",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/Registry"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/Registry"
+ }
+ }
+ }
+ }
+ },
"/repos": {
"get": {
"description": "Returns a list of all repositories. Requires admin rights.",
@@ -2799,7 +3197,7 @@ const docTemplate = `{
}
}
},
- "/repos/{repo_id}/registry": {
+ "/repos/{repo_id}/registries": {
"get": {
"produces": [
"application/json"
@@ -2895,7 +3293,7 @@ const docTemplate = `{
}
}
},
- "/repos/{repo_id}/registry/{registry}": {
+ "/repos/{repo_id}/registries/{registry}": {
"get": {
"produces": [
"application/json"
@@ -3967,6 +4365,10 @@ const docTemplate = `{
"last_contact": {
"type": "integer"
},
+ "last_work": {
+ "description": "last time the agent did something, this value is used to determine if the agent is still doing work used by the autoscaler",
+ "type": "integer"
+ },
"name": {
"type": "string"
},
@@ -4013,7 +4415,7 @@ const docTemplate = `{
"branch": {
"type": "string"
},
- "created_at": {
+ "created": {
"type": "integer"
},
"creator_id": {
@@ -4055,13 +4457,13 @@ const docTemplate = `{
"commit": {
"type": "string"
},
- "created_at": {
+ "created": {
"type": "integer"
},
"event": {
"type": "string"
},
- "finished_at": {
+ "finished": {
"type": "integer"
},
"id": {
@@ -4082,7 +4484,7 @@ const docTemplate = `{
"repo_id": {
"type": "integer"
},
- "started_at": {
+ "started": {
"type": "integer"
},
"status": {
@@ -4239,7 +4641,7 @@ const docTemplate = `{
"commit": {
"type": "string"
},
- "created_at": {
+ "created": {
"type": "integer"
},
"deploy_task": {
@@ -4257,7 +4659,7 @@ const docTemplate = `{
"event": {
"$ref": "#/definitions/WebhookEvent"
},
- "finished_at": {
+ "finished": {
"type": "integer"
},
"forge_url": {
@@ -4290,7 +4692,7 @@ const docTemplate = `{
"refspec": {
"type": "string"
},
- "reviewed_at": {
+ "reviewed": {
"type": "integer"
},
"reviewed_by": {
@@ -4300,7 +4702,7 @@ const docTemplate = `{
"description": "uses reported user for webhooks and name of cron for cron pipelines",
"type": "string"
},
- "started_at": {
+ "started": {
"type": "integer"
},
"status": {
@@ -4312,7 +4714,7 @@ const docTemplate = `{
"title": {
"type": "string"
},
- "updated_at": {
+ "updated": {
"type": "integer"
},
"variables": {
@@ -4363,9 +4765,18 @@ const docTemplate = `{
"id": {
"type": "integer"
},
+ "org_id": {
+ "type": "integer"
+ },
"password": {
"type": "string"
},
+ "readonly": {
+ "type": "boolean"
+ },
+ "repo_id": {
+ "type": "integer"
+ },
"username": {
"type": "string"
}
@@ -4592,15 +5003,15 @@ const docTemplate = `{
"Step": {
"type": "object",
"properties": {
- "end_time": {
- "type": "integer"
- },
"error": {
"type": "string"
},
"exit_code": {
"type": "integer"
},
+ "finished": {
+ "type": "integer"
+ },
"id": {
"type": "integer"
},
@@ -4616,7 +5027,7 @@ const docTemplate = `{
"ppid": {
"type": "integer"
},
- "start_time": {
+ "started": {
"type": "integer"
},
"state": {
@@ -4653,12 +5064,6 @@ const docTemplate = `{
"agent_id": {
"type": "integer"
},
- "data": {
- "type": "array",
- "items": {
- "type": "integer"
- }
- },
"dep_status": {
"type": "object",
"additionalProperties": {
@@ -4776,9 +5181,6 @@ const docTemplate = `{
"$ref": "#/definitions/Step"
}
},
- "end_time": {
- "type": "integer"
- },
"environ": {
"type": "object",
"additionalProperties": {
@@ -4788,6 +5190,9 @@ const docTemplate = `{
"error": {
"type": "string"
},
+ "finished": {
+ "type": "integer"
+ },
"id": {
"type": "integer"
},
@@ -4803,7 +5208,7 @@ const docTemplate = `{
"platform": {
"type": "string"
},
- "start_time": {
+ "started": {
"type": "integer"
},
"state": {
diff --git a/cmd/server/flags.go b/cmd/server/flags.go
index a511a4b83..18023e207 100644
--- a/cmd/server/flags.go
+++ b/cmd/server/flags.go
@@ -1,3 +1,4 @@
+// Copyright 2023 Woodpecker Authors
// Copyright 2019 Laszlo Fogas
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +19,7 @@ import (
"os"
"time"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/shared/constant"
"go.woodpecker-ci.org/woodpecker/v2/shared/logger"
@@ -26,229 +27,238 @@ import (
var flags = append([]cli.Flag{
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_LOG_XORM"},
+ Sources: cli.EnvVars("WOODPECKER_LOG_XORM"),
Name: "log-xorm",
Usage: "enable xorm logging",
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_LOG_XORM_SQL"},
+ Sources: cli.EnvVars("WOODPECKER_LOG_XORM_SQL"),
Name: "log-xorm-sql",
Usage: "enable xorm sql command logging",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_HOST"},
+ Sources: cli.EnvVars("WOODPECKER_HOST"),
Name: "server-host",
Usage: "server fully qualified url. Format: ://[/]",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_SERVER_ADDR"},
+ Sources: cli.EnvVars("WOODPECKER_SERVER_ADDR"),
Name: "server-addr",
Usage: "server address",
Value: ":8000",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_SERVER_ADDR_TLS"},
+ Sources: cli.EnvVars("WOODPECKER_SERVER_ADDR_TLS"),
Name: "server-addr-tls",
Usage: "port https with tls (:443)",
Value: ":443",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_SERVER_CERT"},
+ Sources: cli.EnvVars("WOODPECKER_SERVER_CERT"),
Name: "server-cert",
Usage: "server ssl cert path",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_SERVER_KEY"},
+ Sources: cli.EnvVars("WOODPECKER_SERVER_KEY"),
Name: "server-key",
Usage: "server ssl key path",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_CUSTOM_CSS_FILE"},
+ Sources: cli.EnvVars("WOODPECKER_CUSTOM_CSS_FILE"),
Name: "custom-css-file",
Usage: "file path for the server to serve a custom .CSS file, used for customizing the UI",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_CUSTOM_JS_FILE"},
+ Sources: cli.EnvVars("WOODPECKER_CUSTOM_JS_FILE"),
Name: "custom-js-file",
Usage: "file path for the server to serve a custom .JS file, used for customizing the UI",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_LETS_ENCRYPT_EMAIL"},
+ Sources: cli.EnvVars("WOODPECKER_LETS_ENCRYPT_EMAIL"),
Name: "lets-encrypt-email",
Usage: "let's encrypt email",
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_LETS_ENCRYPT"},
+ Sources: cli.EnvVars("WOODPECKER_LETS_ENCRYPT"),
Name: "lets-encrypt",
Usage: "enable let's encrypt",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_GRPC_ADDR"},
+ Sources: cli.EnvVars("WOODPECKER_GRPC_ADDR"),
Name: "grpc-addr",
Usage: "grpc address",
Value: ":9000",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_GRPC_SECRET"},
- Name: "grpc-secret",
- Usage: "grpc jwt secret",
- Value: "secret",
- FilePath: os.Getenv("WOODPECKER_GRPC_SECRET_FILE"),
+ Sources: cli.NewValueSourceChain(
+ cli.File(os.Getenv("WOODPECKER_GRPC_SECRET_FILE")),
+ cli.EnvVar("WOODPECKER_GRPC_SECRET")),
+ Name: "grpc-secret",
+ Usage: "grpc jwt secret",
+ Value: "secret",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_METRICS_SERVER_ADDR"},
+ Sources: cli.EnvVars("WOODPECKER_METRICS_SERVER_ADDR"),
Name: "metrics-server-addr",
Usage: "metrics server address",
Value: "",
},
&cli.StringSliceFlag{
- EnvVars: []string{"WOODPECKER_ADMIN"},
+ Sources: cli.EnvVars("WOODPECKER_ADMIN"),
Name: "admin",
Usage: "list of admin users",
},
&cli.StringSliceFlag{
- EnvVars: []string{"WOODPECKER_ORGS"},
+ Sources: cli.EnvVars("WOODPECKER_ORGS"),
Name: "orgs",
Usage: "list of approved organizations",
},
&cli.StringSliceFlag{
- EnvVars: []string{"WOODPECKER_REPO_OWNERS"},
+ Sources: cli.EnvVars("WOODPECKER_REPO_OWNERS"),
Name: "repo-owners",
Usage: "Repositories by those owners will be allowed to be used in woodpecker",
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_OPEN"},
+ Sources: cli.EnvVars("WOODPECKER_OPEN"),
Name: "open",
Usage: "enable open user registration",
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_AUTHENTICATE_PUBLIC_REPOS"},
+ Sources: cli.EnvVars("WOODPECKER_AUTHENTICATE_PUBLIC_REPOS"),
Name: "authenticate-public-repos",
Usage: "Always use authentication to clone repositories even if they are public. Needed if the SCM requires to always authenticate as used by many companies.",
},
&cli.StringSliceFlag{
- EnvVars: []string{"WOODPECKER_DEFAULT_CANCEL_PREVIOUS_PIPELINE_EVENTS"},
+ Sources: cli.EnvVars("WOODPECKER_DEFAULT_CANCEL_PREVIOUS_PIPELINE_EVENTS"),
Name: "default-cancel-previous-pipeline-events",
Usage: "List of event names that will be canceled when a new pipeline for the same context (tag, branch) is created.",
- Value: cli.NewStringSlice("push", "pull_request"),
+ Value: []string{"push", "pull_request"},
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_DEFAULT_CLONE_IMAGE"},
- Name: "default-clone-image",
+ Sources: cli.EnvVars("WOODPECKER_DEFAULT_CLONE_PLUGIN", "WOODPECKER_DEFAULT_CLONE_IMAGE"),
+ Name: "default-clone-plugin",
+ Aliases: []string{"default-clone-image"},
Usage: "The default docker image to be used when cloning the repo",
- Value: constant.DefaultCloneImage,
+ Value: constant.DefaultClonePlugin,
},
- &cli.Int64Flag{
- EnvVars: []string{"WOODPECKER_DEFAULT_PIPELINE_TIMEOUT"},
+ &cli.IntFlag{
+ Sources: cli.EnvVars("WOODPECKER_DEFAULT_PIPELINE_TIMEOUT"),
Name: "default-pipeline-timeout",
Usage: "The default time in minutes for a repo in minutes before a pipeline gets killed",
Value: 60,
},
- &cli.Int64Flag{
- EnvVars: []string{"WOODPECKER_MAX_PIPELINE_TIMEOUT"},
+ &cli.IntFlag{
+ Sources: cli.EnvVars("WOODPECKER_MAX_PIPELINE_TIMEOUT"),
Name: "max-pipeline-timeout",
Usage: "The maximum time in minutes you can set in the repo settings before a pipeline gets killed",
Value: 120,
},
&cli.DurationFlag{
- EnvVars: []string{"WOODPECKER_SESSION_EXPIRES"},
+ Sources: cli.EnvVars("WOODPECKER_SESSION_EXPIRES"),
Name: "session-expires",
Usage: "session expiration time",
Value: time.Hour * 72,
},
&cli.StringSliceFlag{
- EnvVars: []string{"WOODPECKER_ESCALATE"},
- Name: "escalate",
- Usage: "images to run in privileged mode",
- Value: cli.NewStringSlice(constant.PrivilegedPlugins...),
+ Sources: cli.EnvVars("WOODPECKER_PLUGINS_PRIVILEGED"),
+ Name: "plugins-privileged",
+ Usage: "Allow plugins to run in privileged mode, if environment variable is defined but empty there will be none",
},
&cli.StringSliceFlag{
- EnvVars: []string{"WOODPECKER_VOLUME"},
+ Sources: cli.EnvVars("WOODPECKER_PLUGINS_TRUSTED_CLONE"),
+ Name: "plugins-trusted-clone",
+ Usage: "Plugins witch are trusted to handle the netrc info in clone steps",
+ Value: constant.TrustedClonePlugins,
+ },
+ &cli.StringSliceFlag{
+ Sources: cli.EnvVars("WOODPECKER_VOLUME"),
Name: "volume",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_DOCKER_CONFIG"},
+ Sources: cli.EnvVars("WOODPECKER_DOCKER_CONFIG"),
Name: "docker-config",
},
&cli.StringSliceFlag{
- EnvVars: []string{"WOODPECKER_ENVIRONMENT"},
+ Sources: cli.EnvVars("WOODPECKER_ENVIRONMENT"),
Name: "environment",
},
&cli.StringSliceFlag{
- EnvVars: []string{"WOODPECKER_NETWORK"},
+ Sources: cli.EnvVars("WOODPECKER_NETWORK"),
Name: "network",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_AGENT_SECRET"},
- Name: "agent-secret",
- Usage: "server-agent shared password",
- FilePath: os.Getenv("WOODPECKER_AGENT_SECRET_FILE"),
+ Sources: cli.NewValueSourceChain(
+ cli.File(os.Getenv("WOODPECKER_AGENT_SECRET_FILE")),
+ cli.EnvVar("WOODPECKER_AGENT_SECRET")),
+ Name: "agent-secret",
+ Usage: "server-agent shared password",
},
&cli.DurationFlag{
- EnvVars: []string{"WOODPECKER_KEEPALIVE_MIN_TIME"},
+ Sources: cli.EnvVars("WOODPECKER_KEEPALIVE_MIN_TIME"),
Name: "keepalive-min-time",
Usage: "server-side enforcement policy on the minimum amount of time a client should wait before sending a keepalive ping.",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_CONFIG_SERVICE_ENDPOINT"},
+ Sources: cli.EnvVars("WOODPECKER_CONFIG_SERVICE_ENDPOINT"),
Name: "config-service-endpoint",
Usage: "url used for calling configuration service endpoint",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_DATABASE_DRIVER"},
+ Sources: cli.EnvVars("WOODPECKER_DATABASE_DRIVER"),
Name: "driver",
Usage: "database driver",
Value: "sqlite3",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_DATABASE_DATASOURCE"},
- Name: "datasource",
- Usage: "database driver configuration string",
- Value: datasourceDefaultValue(),
- FilePath: os.Getenv("WOODPECKER_DATABASE_DATASOURCE_FILE"),
+ Sources: cli.NewValueSourceChain(
+ cli.File(os.Getenv("WOODPECKER_DATABASE_DATASOURCE_FILE")),
+ cli.EnvVar("WOODPECKER_DATABASE_DATASOURCE")),
+ Name: "datasource",
+ Usage: "database driver configuration string",
+ Value: datasourceDefaultValue(),
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_PROMETHEUS_AUTH_TOKEN"},
- Name: "prometheus-auth-token",
- Usage: "token to secure prometheus metrics endpoint",
- Value: "",
- FilePath: os.Getenv("WOODPECKER_PROMETHEUS_AUTH_TOKEN_FILE"),
+ Sources: cli.NewValueSourceChain(
+ cli.File(os.Getenv("WOODPECKER_PROMETHEUS_AUTH_TOKEN_FILE")),
+ cli.EnvVar("WOODPECKER_PROMETHEUS_AUTH_TOKEN")),
+ Name: "prometheus-auth-token",
+ Usage: "token to secure prometheus metrics endpoint",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_STATUS_CONTEXT", "WOODPECKER_GITHUB_CONTEXT", "WOODPECKER_GITEA_CONTEXT"},
+ Sources: cli.EnvVars("WOODPECKER_STATUS_CONTEXT", "WOODPECKER_GITHUB_CONTEXT", "WOODPECKER_GITEA_CONTEXT"),
Name: "status-context",
Usage: "status context prefix",
Value: "ci/woodpecker",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_STATUS_CONTEXT_FORMAT"},
+ Sources: cli.EnvVars("WOODPECKER_STATUS_CONTEXT_FORMAT"),
Name: "status-context-format",
Usage: "status context format",
Value: "{{ .context }}/{{ .event }}/{{ .workflow }}{{if not (eq .axis_id 0)}}/{{.axis_id}}{{end}}",
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_MIGRATIONS_ALLOW_LONG"},
+ Sources: cli.EnvVars("WOODPECKER_MIGRATIONS_ALLOW_LONG"),
Name: "migrations-allow-long",
Value: false,
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_ENABLE_SWAGGER"},
+ Sources: cli.EnvVars("WOODPECKER_ENABLE_SWAGGER"),
Name: "enable-swagger",
Value: true,
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_DISABLE_VERSION_CHECK"},
+ Sources: cli.EnvVars("WOODPECKER_DISABLE_VERSION_CHECK"),
Usage: "Disable version check in admin web ui.",
Name: "skip-version-check",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_LOG_STORE"},
+ Sources: cli.EnvVars("WOODPECKER_LOG_STORE"),
Name: "log-store",
Usage: "log store to use ('database' or 'file')",
Value: "database",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_LOG_STORE_FILE_PATH"},
+ Sources: cli.EnvVars("WOODPECKER_LOG_STORE_FILE_PATH"),
Name: "log-store-file-path",
Usage: "directory used for file based log storage",
},
@@ -256,17 +266,17 @@ var flags = append([]cli.Flag{
// backend options for pipeline compiler
//
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_NO_PROXY", "NO_PROXY", "no_proxy"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_NO_PROXY", "NO_PROXY", "no_proxy"),
Usage: "if set, pass the environment variable down as \"NO_PROXY\" to steps",
Name: "backend-no-proxy",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_HTTP_PROXY", "HTTP_PROXY", "http_proxy"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_HTTP_PROXY", "HTTP_PROXY", "http_proxy"),
Usage: "if set, pass the environment variable down as \"HTTP_PROXY\" to steps",
Name: "backend-http-proxy",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_HTTPS_PROXY", "HTTPS_PROXY", "https_proxy"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_HTTPS_PROXY", "HTTPS_PROXY", "https_proxy"),
Usage: "if set, pass the environment variable down as \"HTTPS_PROXY\" to steps",
Name: "backend-https-proxy",
},
@@ -274,44 +284,44 @@ var flags = append([]cli.Flag{
// resource limit parameters
//
&cli.DurationFlag{
- EnvVars: []string{"WOODPECKER_FORGE_TIMEOUT"},
+ Sources: cli.EnvVars("WOODPECKER_FORGE_TIMEOUT"),
Name: "forge-timeout",
Usage: "how many seconds before timeout when fetching the Woodpecker configuration from a Forge",
Value: time.Second * 3,
},
&cli.UintFlag{
- EnvVars: []string{"WOODPECKER_FORGE_RETRY"},
+ Sources: cli.EnvVars("WOODPECKER_FORGE_RETRY"),
Name: "forge-retry",
Usage: "How many retries of fetching the Woodpecker configuration from a forge are done before we fail",
Value: 3,
},
- &cli.Int64Flag{
- EnvVars: []string{"WOODPECKER_LIMIT_MEM_SWAP"},
+ &cli.IntFlag{
+ Sources: cli.EnvVars("WOODPECKER_LIMIT_MEM_SWAP"),
Name: "limit-mem-swap",
Usage: "maximum memory used for swap in bytes",
},
- &cli.Int64Flag{
- EnvVars: []string{"WOODPECKER_LIMIT_MEM"},
+ &cli.IntFlag{
+ Sources: cli.EnvVars("WOODPECKER_LIMIT_MEM"),
Name: "limit-mem",
Usage: "maximum memory allowed in bytes",
},
- &cli.Int64Flag{
- EnvVars: []string{"WOODPECKER_LIMIT_SHM_SIZE"},
+ &cli.IntFlag{
+ Sources: cli.EnvVars("WOODPECKER_LIMIT_SHM_SIZE"),
Name: "limit-shm-size",
Usage: "docker compose /dev/shm allowed in bytes",
},
- &cli.Int64Flag{
- EnvVars: []string{"WOODPECKER_LIMIT_CPU_QUOTA"},
+ &cli.IntFlag{
+ Sources: cli.EnvVars("WOODPECKER_LIMIT_CPU_QUOTA"),
Name: "limit-cpu-quota",
Usage: "impose a cpu quota",
},
- &cli.Int64Flag{
- EnvVars: []string{"WOODPECKER_LIMIT_CPU_SHARES"},
+ &cli.IntFlag{
+ Sources: cli.EnvVars("WOODPECKER_LIMIT_CPU_SHARES"),
Name: "limit-cpu-shares",
Usage: "change the cpu shares",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_LIMIT_CPU_SET"},
+ Sources: cli.EnvVars("WOODPECKER_LIMIT_CPU_SET"),
Name: "limit-cpu-set",
Usage: "set the cpus allowed to execute containers",
},
@@ -319,27 +329,62 @@ var flags = append([]cli.Flag{
&cli.StringFlag{
Name: "forge-url",
Usage: "url of the forge",
- EnvVars: []string{"WOODPECKER_FORGE_URL", "WOODPECKER_GITHUB_URL", "WOODPECKER_GITLAB_URL", "WOODPECKER_GITEA_URL", "WOODPECKER_FORGEJO_URL", "WOODPECKER_BITBUCKET_URL", "WOODPECKER_BITBUCKET_DC_URL"},
+ Sources: cli.EnvVars("WOODPECKER_FORGE_URL", "WOODPECKER_GITHUB_URL", "WOODPECKER_GITLAB_URL", "WOODPECKER_GITEA_URL", "WOODPECKER_FORGEJO_URL", "WOODPECKER_BITBUCKET_URL", "WOODPECKER_BITBUCKET_DC_URL"),
},
&cli.StringFlag{
- Name: "forge-oauth-client",
- Usage: "oauth2 client id",
- EnvVars: []string{"WOODPECKER_FORGE_CLIENT", "WOODPECKER_GITHUB_CLIENT", "WOODPECKER_GITLAB_CLIENT", "WOODPECKER_GITEA_CLIENT", "WOODPECKER_FORGEJO_CLIENT", "WOODPECKER_BITBUCKET_CLIENT", "WOODPECKER_BITBUCKET_DC_CLIENT_ID"},
- FilePath: getFirstNonEmptyEnvVar([]string{"WOODPECKER_FORGE_CLIENT_FILE", "WOODPECKER_GITHUB_CLIENT_FILE", "WOODPECKER_GITLAB_CLIENT_FILE", "WOODPECKER_GITEA_CLIENT_FILE", "WOODPECKER_FORGEJO_CLIENT_FILE", "WOODPECKER_BITBUCKET_CLIENT_FILE", "WOODPECKER_BITBUCKET_DC_CLIENT_ID_FILE"}),
+ Sources: cli.NewValueSourceChain(
+ cli.File(getFirstNonEmptyEnvVar(
+ "WOODPECKER_FORGE_CLIENT_FILE",
+ "WOODPECKER_GITHUB_CLIENT_FILE",
+ "WOODPECKER_GITLAB_CLIENT_FILE",
+ "WOODPECKER_GITEA_CLIENT_FILE",
+ "WOODPECKER_FORGEJO_CLIENT_FILE",
+ "WOODPECKER_BITBUCKET_CLIENT_FILE",
+ "WOODPECKER_BITBUCKET_DC_CLIENT_ID_FILE")),
+ cli.EnvVar("WOODPECKER_FORGE_CLIENT"),
+ cli.EnvVar("WOODPECKER_GITHUB_CLIENT"),
+ cli.EnvVar("WOODPECKER_GITLAB_CLIENT"),
+ cli.EnvVar("WOODPECKER_GITEA_CLIENT"),
+ cli.EnvVar("WOODPECKER_FORGEJO_CLIENT"),
+ cli.EnvVar("WOODPECKER_BITBUCKET_CLIENT"),
+ cli.EnvVar("WOODPECKER_BITBUCKET_DC_CLIENT_ID")),
+ Name: "forge-oauth-client",
+ Usage: "oauth2 client id",
},
&cli.StringFlag{
- Name: "forge-oauth-secret",
- Usage: "oauth2 client secret",
- EnvVars: []string{"WOODPECKER_FORGE_SECRET", "WOODPECKER_GITHUB_SECRET", "WOODPECKER_GITLAB_SECRET", "WOODPECKER_GITEA_SECRET", "WOODPECKER_FORGEJO_SECRET", "WOODPECKER_BITBUCKET_SECRET", "WOODPECKER_BITBUCKET_DC_CLIENT_SECRET"},
- FilePath: getFirstNonEmptyEnvVar([]string{"WOODPECKER_FORGE_SECRET_FILE", "WOODPECKER_GITHUB_SECRET_FILE", "WOODPECKER_GITLAB_SECRET_FILE", "WOODPECKER_GITEA_SECRET_FILE", "WOODPECKER_FORGEJO_SECRET_FILE", "WOODPECKER_BITBUCKET_SECRET_FILE", "WOODPECKER_BITBUCKET_DC_CLIENT_SECRET_FILE"}),
+ Sources: cli.NewValueSourceChain(
+ cli.File(getFirstNonEmptyEnvVar(
+ "WOODPECKER_FORGE_SECRET_FILE",
+ "WOODPECKER_GITHUB_SECRET_FILE",
+ "WOODPECKER_GITLAB_SECRET_FILE",
+ "WOODPECKER_GITEA_SECRET_FILE",
+ "WOODPECKER_FORGEJO_SECRET_FILE",
+ "WOODPECKER_BITBUCKET_SECRET_FILE",
+ "WOODPECKER_BITBUCKET_DC_CLIENT_SECRET_FILE",
+ )),
+ cli.EnvVar("WOODPECKER_FORGE_SECRET"),
+ cli.EnvVar("WOODPECKER_GITHUB_SECRET"),
+ cli.EnvVar("WOODPECKER_GITLAB_SECRET"),
+ cli.EnvVar("WOODPECKER_GITEA_SECRET"),
+ cli.EnvVar("WOODPECKER_FORGEJO_SECRET"),
+ cli.EnvVar("WOODPECKER_BITBUCKET_SECRET"),
+ cli.EnvVar("WOODPECKER_BITBUCKET_DC_CLIENT_SECRET")),
+ Name: "forge-oauth-secret",
+ Usage: "oauth2 client secret",
},
&cli.BoolFlag{
- Name: "forge-skip-verify",
- Usage: "skip ssl verification",
- EnvVars: []string{"WOODPECKER_FORGE_SKIP_VERIFY", "WOODPECKER_GITHUB_SKIP_VERIFY", "WOODPECKER_GITLAB_SKIP_VERIFY", "WOODPECKER_GITEA_SKIP_VERIFY", "WOODPECKER_FORGEJO_SKIP_VERIFY", "WOODPECKER_BITBUCKET_SKIP_VERIFY"},
+ Name: "forge-skip-verify",
+ Usage: "skip ssl verification",
+ Sources: cli.EnvVars(
+ "WOODPECKER_FORGE_SKIP_VERIFY",
+ "WOODPECKER_GITHUB_SKIP_VERIFY",
+ "WOODPECKER_GITLAB_SKIP_VERIFY",
+ "WOODPECKER_GITEA_SKIP_VERIFY",
+ "WOODPECKER_FORGEJO_SKIP_VERIFY",
+ "WOODPECKER_BITBUCKET_SKIP_VERIFY"),
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_EXPERT_FORGE_OAUTH_HOST", "WOODPECKER_DEV_GITEA_OAUTH_URL"}, // TODO: remove WOODPECKER_DEV_GITEA_OAUTH_URL in next major release
+ Sources: cli.EnvVars("WOODPECKER_EXPERT_FORGE_OAUTH_HOST"),
Name: "forge-oauth-host",
Usage: "!!!for experts!!! fully qualified public forge url. Use it if your forge url WOODPECKER_FORGE_URL or WOODPECKER_GITEA_URL, ... isn't a public url. Format: ://[/]",
},
@@ -347,7 +392,7 @@ var flags = append([]cli.Flag{
// Addon
//
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_ADDON_FORGE"},
+ Sources: cli.EnvVars("WOODPECKER_ADDON_FORGE"),
Name: "addon-forge",
Usage: "path to forge addon executable",
},
@@ -355,18 +400,18 @@ var flags = append([]cli.Flag{
// GitHub
//
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_GITHUB"},
+ Sources: cli.EnvVars("WOODPECKER_GITHUB"),
Name: "github",
Usage: "github driver is enabled",
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_GITHUB_MERGE_REF"},
+ Sources: cli.EnvVars("WOODPECKER_GITHUB_MERGE_REF"),
Name: "github-merge-ref",
Usage: "github pull requests use merge ref",
Value: true,
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_GITHUB_PUBLIC_ONLY"},
+ Sources: cli.EnvVars("WOODPECKER_GITHUB_PUBLIC_ONLY"),
Name: "github-public-only",
Usage: "github tokens should only get access to public repos",
Value: false,
@@ -375,7 +420,7 @@ var flags = append([]cli.Flag{
// Gitea
//
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_GITEA"},
+ Sources: cli.EnvVars("WOODPECKER_GITEA"),
Name: "gitea",
Usage: "gitea driver is enabled",
},
@@ -383,7 +428,7 @@ var flags = append([]cli.Flag{
// Forgejo
//
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_FORGEJO"},
+ Sources: cli.EnvVars("WOODPECKER_FORGEJO"),
Name: "forgejo",
Usage: "forgejo driver is enabled",
},
@@ -391,7 +436,7 @@ var flags = append([]cli.Flag{
// Bitbucket
//
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_BITBUCKET"},
+ Sources: cli.EnvVars("WOODPECKER_BITBUCKET"),
Name: "bitbucket",
Usage: "bitbucket driver is enabled",
},
@@ -399,7 +444,7 @@ var flags = append([]cli.Flag{
// Gitlab
//
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_GITLAB"},
+ Sources: cli.EnvVars("WOODPECKER_GITLAB"),
Name: "gitlab",
Usage: "gitlab driver is enabled",
},
@@ -407,27 +452,29 @@ var flags = append([]cli.Flag{
// Bitbucket DataCenter/Server (previously Stash)
//
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_BITBUCKET_DC"},
+ Sources: cli.EnvVars("WOODPECKER_BITBUCKET_DC"),
Name: "bitbucket-dc",
Usage: "Bitbucket DataCenter/Server driver is enabled",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_BITBUCKET_DC_GIT_USERNAME"},
- Name: "bitbucket-dc-git-username",
- Usage: "Bitbucket DataCenter/Server service account username",
- FilePath: os.Getenv("WOODPECKER_BITBUCKET_DC_GIT_USERNAME_FILE"),
+ Sources: cli.NewValueSourceChain(
+ cli.File(os.Getenv("WOODPECKER_BITBUCKET_DC_GIT_USERNAME_FILE")),
+ cli.EnvVar("WOODPECKER_BITBUCKET_DC_GIT_USERNAME")),
+ Name: "bitbucket-dc-git-username",
+ Usage: "Bitbucket DataCenter/Server service account username",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_BITBUCKET_DC_GIT_PASSWORD"},
- Name: "bitbucket-dc-git-password",
- Usage: "Bitbucket DataCenter/Server service account password",
- FilePath: os.Getenv("WOODPECKER_BITBUCKET_DC_GIT_PASSWORD_FILE"),
+ Sources: cli.NewValueSourceChain(
+ cli.File(os.Getenv("WOODPECKER_BITBUCKET_DC_GIT_PASSWORD_FILE")),
+ cli.EnvVar("WOODPECKER_BITBUCKET_DC_GIT_PASSWORD")),
+ Name: "bitbucket-dc-git-password",
+ Usage: "Bitbucket DataCenter/Server service account password",
},
//
// development flags
//
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_DEV_WWW_PROXY"},
+ Sources: cli.EnvVars("WOODPECKER_DEV_WWW_PROXY"),
Name: "www-proxy",
Usage: "serve the website by using a proxy (used for development)",
Hidden: true,
@@ -436,34 +483,27 @@ var flags = append([]cli.Flag{
// expert flags
//
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_EXPERT_WEBHOOK_HOST", "WOODPECKER_WEBHOOK_HOST"}, // TODO: remove WOODPECKER_WEBHOOK_HOST in next major release
+ Sources: cli.EnvVars("WOODPECKER_EXPERT_WEBHOOK_HOST"),
Name: "server-webhook-host",
Usage: "!!!for experts!!! fully qualified woodpecker server url called by forge's webhooks. Format: ://[/]",
},
- // TODO: remove in next major release
- &cli.StringFlag{
- EnvVars: []string{"WOODPECKER_DEV_OAUTH_HOST"},
- Name: "server-dev-oauth-host-deprecated",
- Usage: "DEPRECATED: use WOODPECKER_EXPERT_FORGE_OAUTH_HOST instead\nfully qualified url used for oauth redirects. Format: ://[/]",
- Value: "",
- Hidden: true,
- },
//
// secrets encryption in DB
//
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_ENCRYPTION_KEY"},
- Name: "encryption-raw-key",
- Usage: "Raw encryption key",
- FilePath: os.Getenv("WOODPECKER_ENCRYPTION_KEY_FILE"),
+ Sources: cli.NewValueSourceChain(
+ cli.File(os.Getenv("WOODPECKER_ENCRYPTION_KEY_FILE")),
+ cli.EnvVar("WOODPECKER_ENCRYPTION_KEY")),
+ Name: "encryption-raw-key",
+ Usage: "Raw encryption key",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_ENCRYPTION_TINK_KEYSET_FILE"},
+ Sources: cli.EnvVars("WOODPECKER_ENCRYPTION_TINK_KEYSET_FILE"),
Name: "encryption-tink-keyset",
Usage: "Google tink AEAD-compatible keyset file to encrypt secrets in DB",
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_ENCRYPTION_DISABLE"},
+ Sources: cli.EnvVars("WOODPECKER_ENCRYPTION_DISABLE"),
Name: "encryption-disable-flag",
Usage: "Flag to decrypt all encrypted data and disable encryption on server",
},
@@ -479,7 +519,7 @@ func datasourceDefaultValue() string {
return "woodpecker.sqlite"
}
-func getFirstNonEmptyEnvVar(envVars []string) string {
+func getFirstNonEmptyEnvVar(envVars ...string) string {
for _, envVar := range envVars {
val := os.Getenv(envVar)
if val != "" {
diff --git a/cmd/server/grpc_server.go b/cmd/server/grpc_server.go
new file mode 100644
index 000000000..f983bb158
--- /dev/null
+++ b/cmd/server/grpc_server.go
@@ -0,0 +1,88 @@
+// 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 main
+
+import (
+ "context"
+ "fmt"
+ "net"
+
+ "github.com/rs/zerolog/log"
+ "github.com/urfave/cli/v3"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/keepalive"
+
+ "go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc/proto"
+ "go.woodpecker-ci.org/woodpecker/v2/server"
+ woodpeckerGrpcServer "go.woodpecker-ci.org/woodpecker/v2/server/grpc"
+ "go.woodpecker-ci.org/woodpecker/v2/server/store"
+)
+
+func runGrpcServer(ctx context.Context, c *cli.Command, _store store.Store) error {
+ lis, err := net.Listen("tcp", c.String("grpc-addr"))
+ if err != nil {
+ return fmt.Errorf("failed to listen on grpc-addr: %w", err)
+ }
+
+ jwtSecret := c.String("grpc-secret")
+ jwtManager := woodpeckerGrpcServer.NewJWTManager(jwtSecret)
+
+ authorizer := woodpeckerGrpcServer.NewAuthorizer(jwtManager)
+ grpcServer := grpc.NewServer(
+ grpc.StreamInterceptor(authorizer.StreamInterceptor),
+ grpc.UnaryInterceptor(authorizer.UnaryInterceptor),
+ grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{
+ MinTime: c.Duration("keepalive-min-time"),
+ }),
+ )
+
+ woodpeckerServer := woodpeckerGrpcServer.NewWoodpeckerServer(
+ server.Config.Services.Queue,
+ server.Config.Services.Logs,
+ server.Config.Services.Pubsub,
+ _store,
+ )
+ proto.RegisterWoodpeckerServer(grpcServer, woodpeckerServer)
+
+ woodpeckerAuthServer := woodpeckerGrpcServer.NewWoodpeckerAuthServer(
+ jwtManager,
+ server.Config.Server.AgentToken,
+ _store,
+ )
+ proto.RegisterWoodpeckerAuthServer(grpcServer, woodpeckerAuthServer)
+
+ grpcCtx, cancel := context.WithCancelCause(ctx)
+ defer cancel(nil)
+
+ go func() {
+ <-grpcCtx.Done()
+ if grpcServer == nil {
+ return
+ }
+ log.Info().Msg("terminating grpc service gracefully")
+ grpcServer.GracefulStop()
+ log.Info().Msg("grpc service stopped")
+ }()
+
+ if err := grpcServer.Serve(lis); err != nil {
+ // signal that we don't have to stop the server gracefully anymore
+ grpcServer = nil
+
+ // wrap the error so we know where it did come from
+ return fmt.Errorf("grpc server failed: %w", err)
+ }
+
+ return nil
+}
diff --git a/cmd/server/health.go b/cmd/server/health.go
index eb780b9a9..10780889f 100644
--- a/cmd/server/health.go
+++ b/cmd/server/health.go
@@ -16,20 +16,21 @@
package main
import (
+ "context"
"fmt"
"net/http"
"strings"
"time"
"github.com/rs/zerolog/log"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
)
const pingTimeout = 1 * time.Second
// handles pinging the endpoint and returns an error if the
// server is in an unhealthy state.
-func pinger(c *cli.Context) error {
+func pinger(_ context.Context, c *cli.Command) error {
scheme := "http"
serverAddr := c.String("server-addr")
if strings.HasPrefix(serverAddr, ":") {
diff --git a/cmd/server/main.go b/cmd/server/main.go
index da7f986b4..71b17b23b 100644
--- a/cmd/server/main.go
+++ b/cmd/server/main.go
@@ -15,18 +15,24 @@
package main
import (
+ "context"
"os"
_ "github.com/joho/godotenv/autoload"
"github.com/rs/zerolog/log"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
_ "go.woodpecker-ci.org/woodpecker/v2/cmd/server/docs"
+ "go.woodpecker-ci.org/woodpecker/v2/shared/utils"
"go.woodpecker-ci.org/woodpecker/v2/version"
)
func main() {
- app := cli.NewApp()
+ ctx := utils.WithContextSigtermCallback(context.Background(), func() {
+ log.Info().Msg("termination signal is received, shutting down server")
+ })
+
+ app := cli.Command{}
app.Name = "woodpecker-server"
app.Version = version.String()
app.Usage = "woodpecker server"
@@ -42,7 +48,7 @@ func main() {
setupSwaggerStaticConfig()
- if err := app.Run(os.Args); err != nil {
- log.Fatal().Err(err).Msgf("error running server") //nolint:forbidigo
+ if err := app.Run(ctx, os.Args); err != nil {
+ log.Error().Err(err).Msgf("error running server")
}
}
diff --git a/cmd/server/metrics_server.go b/cmd/server/metrics_server.go
new file mode 100644
index 000000000..007d2e48d
--- /dev/null
+++ b/cmd/server/metrics_server.go
@@ -0,0 +1,108 @@
+// 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 main
+
+import (
+ "context"
+ "errors"
+ "time"
+
+ "github.com/prometheus/client_golang/prometheus"
+ prometheus_auto "github.com/prometheus/client_golang/prometheus/promauto"
+ "github.com/rs/zerolog/log"
+
+ "go.woodpecker-ci.org/woodpecker/v2/server"
+ "go.woodpecker-ci.org/woodpecker/v2/server/store"
+)
+
+func startMetricsCollector(ctx context.Context, _store store.Store) {
+ pendingSteps := prometheus_auto.NewGauge(prometheus.GaugeOpts{
+ Namespace: "woodpecker",
+ Name: "pending_steps",
+ Help: "Total number of pending pipeline steps.",
+ })
+ waitingSteps := prometheus_auto.NewGauge(prometheus.GaugeOpts{
+ Namespace: "woodpecker",
+ Name: "waiting_steps",
+ Help: "Total number of pipeline waiting on deps.",
+ })
+ runningSteps := prometheus_auto.NewGauge(prometheus.GaugeOpts{
+ Namespace: "woodpecker",
+ Name: "running_steps",
+ Help: "Total number of running pipeline steps.",
+ })
+ workers := prometheus_auto.NewGauge(prometheus.GaugeOpts{
+ Namespace: "woodpecker",
+ Name: "worker_count",
+ Help: "Total number of workers.",
+ })
+ pipelines := prometheus_auto.NewGauge(prometheus.GaugeOpts{
+ Namespace: "woodpecker",
+ Name: "pipeline_total_count",
+ Help: "Total number of pipelines.",
+ })
+ users := prometheus_auto.NewGauge(prometheus.GaugeOpts{
+ Namespace: "woodpecker",
+ Name: "user_count",
+ Help: "Total number of users.",
+ })
+ repos := prometheus_auto.NewGauge(prometheus.GaugeOpts{
+ Namespace: "woodpecker",
+ Name: "repo_count",
+ Help: "Total number of repos.",
+ })
+
+ go func() {
+ log.Info().Msg("queue metric collector started")
+
+ for {
+ stats := server.Config.Services.Queue.Info(ctx)
+ pendingSteps.Set(float64(stats.Stats.Pending))
+ waitingSteps.Set(float64(stats.Stats.WaitingOnDeps))
+ runningSteps.Set(float64(stats.Stats.Running))
+ workers.Set(float64(stats.Stats.Workers))
+
+ select {
+ case <-ctx.Done():
+ log.Info().Msg("queue metric collector stopped")
+ return
+ case <-time.After(queueInfoRefreshInterval):
+ }
+ }
+ }()
+ go func() {
+ log.Info().Msg("store metric collector started")
+
+ for {
+ repoCount, repoErr := _store.GetRepoCount()
+ userCount, userErr := _store.GetUserCount()
+ pipelineCount, pipelineErr := _store.GetPipelineCount()
+ pipelines.Set(float64(pipelineCount))
+ users.Set(float64(userCount))
+ repos.Set(float64(repoCount))
+
+ if err := errors.Join(repoErr, userErr, pipelineErr); err != nil {
+ log.Error().Err(err).Msg("could not update store information for metrics")
+ }
+
+ select {
+ case <-ctx.Done():
+ log.Info().Msg("store metric collector stopped")
+ return
+ case <-time.After(storeInfoRefreshInterval):
+ }
+ }
+ }()
+}
diff --git a/cmd/server/server.go b/cmd/server/server.go
index 76e73679b..42338ddd5 100644
--- a/cmd/server/server.go
+++ b/cmd/server/server.go
@@ -15,10 +15,10 @@
package main
import (
+ "context"
"crypto/tls"
"errors"
"fmt"
- "net"
"net/http"
"net/http/httputil"
"net/url"
@@ -30,35 +30,45 @@ import (
prometheus_http "github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"golang.org/x/sync/errgroup"
- "google.golang.org/grpc"
- "google.golang.org/grpc/keepalive"
- "go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc/proto"
"go.woodpecker-ci.org/woodpecker/v2/server"
"go.woodpecker-ci.org/woodpecker/v2/server/cron"
- "go.woodpecker-ci.org/woodpecker/v2/server/forge/setup"
- woodpeckerGrpcServer "go.woodpecker-ci.org/woodpecker/v2/server/grpc"
- "go.woodpecker-ci.org/woodpecker/v2/server/logging"
- "go.woodpecker-ci.org/woodpecker/v2/server/model"
- "go.woodpecker-ci.org/woodpecker/v2/server/pubsub"
"go.woodpecker-ci.org/woodpecker/v2/server/router"
"go.woodpecker-ci.org/woodpecker/v2/server/router/middleware"
- "go.woodpecker-ci.org/woodpecker/v2/server/services"
- "go.woodpecker-ci.org/woodpecker/v2/server/services/permissions"
- "go.woodpecker-ci.org/woodpecker/v2/server/store"
"go.woodpecker-ci.org/woodpecker/v2/server/web"
- "go.woodpecker-ci.org/woodpecker/v2/shared/constant"
"go.woodpecker-ci.org/woodpecker/v2/shared/logger"
"go.woodpecker-ci.org/woodpecker/v2/version"
)
-func run(c *cli.Context) error {
- if err := logger.SetupGlobalLogger(c, true); err != nil {
+const (
+ shutdownTimeout = time.Second * 5
+)
+
+var (
+ stopServerFunc context.CancelCauseFunc = func(error) {}
+ shutdownCancelFunc context.CancelFunc = func() {}
+ shutdownCtx = context.Background()
+)
+
+func run(ctx context.Context, c *cli.Command) error {
+ if err := logger.SetupGlobalLogger(ctx, c, true); err != nil {
return err
}
+ ctx, ctxCancel := context.WithCancelCause(ctx)
+ stopServerFunc = func(err error) {
+ if err != nil {
+ log.Error().Err(err).Msg("shutdown of whole server")
+ }
+ stopServerFunc = func(error) {}
+ shutdownCtx, shutdownCancelFunc = context.WithTimeout(shutdownCtx, shutdownTimeout)
+ ctxCancel(err)
+ }
+ defer stopServerFunc(nil)
+ defer shutdownCancelFunc()
+
// set gin mode based on log level
if zerolog.GlobalLevel() > zerolog.DebugLevel {
gin.SetMode(gin.ReleaseMode)
@@ -82,7 +92,7 @@ func run(c *cli.Context) error {
)
}
- _store, err := setupStore(c)
+ _store, err := setupStore(ctx, c)
if err != nil {
return fmt.Errorf("can't setup store: %w", err)
}
@@ -92,56 +102,35 @@ func run(c *cli.Context) error {
}
}()
- err = setupEvilGlobals(c, _store)
+ err = setupEvilGlobals(ctx, c, _store)
if err != nil {
return fmt.Errorf("can't setup globals: %w", err)
}
- var g errgroup.Group
+ // wait for all services until one do stops with an error
+ serviceWaitingGroup := errgroup.Group{}
- setupMetrics(&g, _store)
+ log.Info().Msgf("starting Woodpecker server with version '%s'", version.String())
- g.Go(func() error {
- return cron.Start(c.Context, _store)
+ startMetricsCollector(ctx, _store)
+
+ serviceWaitingGroup.Go(func() error {
+ log.Info().Msg("starting cron service ...")
+ if err := cron.Run(ctx, _store); err != nil {
+ go stopServerFunc(err)
+ return err
+ }
+ log.Info().Msg("cron service stopped")
+ return nil
})
// start the grpc server
- g.Go(func() error {
- lis, err := net.Listen("tcp", c.String("grpc-addr"))
- if err != nil {
- log.Fatal().Err(err).Msg("failed to listen on grpc-addr") //nolint:forbidigo
- }
-
- jwtSecret := c.String("grpc-secret")
- jwtManager := woodpeckerGrpcServer.NewJWTManager(jwtSecret)
-
- authorizer := woodpeckerGrpcServer.NewAuthorizer(jwtManager)
- grpcServer := grpc.NewServer(
- grpc.StreamInterceptor(authorizer.StreamInterceptor),
- grpc.UnaryInterceptor(authorizer.UnaryInterceptor),
- grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{
- MinTime: c.Duration("keepalive-min-time"),
- }),
- )
-
- woodpeckerServer := woodpeckerGrpcServer.NewWoodpeckerServer(
- server.Config.Services.Queue,
- server.Config.Services.Logs,
- server.Config.Services.Pubsub,
- _store,
- )
- proto.RegisterWoodpeckerServer(grpcServer, woodpeckerServer)
-
- woodpeckerAuthServer := woodpeckerGrpcServer.NewWoodpeckerAuthServer(
- jwtManager,
- server.Config.Server.AgentToken,
- _store,
- )
- proto.RegisterWoodpeckerAuthServer(grpcServer, woodpeckerAuthServer)
-
- err = grpcServer.Serve(lis)
- if err != nil {
- log.Fatal().Err(err).Msg("failed to serve grpc server") //nolint:forbidigo
+ serviceWaitingGroup.Go(func() error {
+ log.Info().Msg("starting grpc server ...")
+ if err := runGrpcServer(ctx, c, _store); err != nil {
+ // stop whole server as grpc is essential
+ go stopServerFunc(err)
+ return err
}
return nil
})
@@ -181,20 +170,33 @@ func run(c *cli.Context) error {
switch {
case c.String("server-cert") != "":
// start the server with tls enabled
- g.Go(func() error {
- serve := &http.Server{
+ serviceWaitingGroup.Go(func() error {
+ tlsServer := &http.Server{
Addr: server.Config.Server.PortTLS,
Handler: handler,
TLSConfig: &tls.Config{
NextProtos: []string{"h2", "http/1.1"},
},
}
- err = serve.ListenAndServeTLS(
+
+ go func() {
+ <-ctx.Done()
+ log.Info().Msg("shutdown tls server ...")
+ if err := tlsServer.Shutdown(shutdownCtx); err != nil { //nolint:contextcheck
+ log.Error().Err(err).Msg("shutdown tls server failed")
+ } else {
+ log.Info().Msg("tls server stopped")
+ }
+ }()
+
+ log.Info().Msg("starting tls server ...")
+ err := tlsServer.ListenAndServeTLS(
c.String("server-cert"),
c.String("server-key"),
)
if err != nil && !errors.Is(err, http.ErrServerClosed) {
- log.Fatal().Err(err).Msg("failed to start server with tls") //nolint:forbidigo
+ log.Error().Err(err).Msg("TLS server failed")
+ stopServerFunc(fmt.Errorf("TLS server failed: %w", err))
}
return err
})
@@ -210,12 +212,27 @@ func run(c *cli.Context) error {
http.Redirect(w, req, req.URL.String(), http.StatusMovedPermanently)
}
- g.Go(func() error {
- err := http.ListenAndServe(server.Config.Server.Port, http.HandlerFunc(redirect))
- if err != nil && !errors.Is(err, http.ErrServerClosed) {
- log.Fatal().Err(err).Msg("unable to start server to redirect from http to https") //nolint:forbidigo
+ serviceWaitingGroup.Go(func() error {
+ redirectServer := &http.Server{
+ Addr: server.Config.Server.Port,
+ Handler: http.HandlerFunc(redirect),
}
- return err
+ go func() {
+ <-ctx.Done()
+ log.Info().Msg("shutdown redirect server ...")
+ if err := redirectServer.Shutdown(shutdownCtx); err != nil { //nolint:contextcheck
+ log.Error().Err(err).Msg("shutdown redirect server failed")
+ } else {
+ log.Info().Msg("redirect server stopped")
+ }
+ }()
+
+ log.Info().Msg("starting redirect server ...")
+ if err := redirectServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
+ log.Error().Err(err).Msg("redirect server failed")
+ stopServerFunc(fmt.Errorf("redirect server failed: %w", err))
+ }
+ return nil
})
case c.Bool("lets-encrypt"):
// start the server with lets-encrypt
@@ -227,132 +244,76 @@ func run(c *cli.Context) error {
return err
}
- g.Go(func() error {
+ 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.Fatal().Err(err).Msg("certmagic does not work") //nolint:forbidigo
+ log.Error().Err(err).Msg("certmagic does not work")
+ stopServerFunc(fmt.Errorf("certmagic failed: %w", err))
}
return nil
})
default:
// start the server without tls
- g.Go(func() error {
- err := http.ListenAndServe(
- c.String("server-addr"),
- handler,
- )
- if err != nil && !errors.Is(err, http.ErrServerClosed) {
- log.Fatal().Err(err).Msg("could not start server") //nolint:forbidigo
+ serviceWaitingGroup.Go(func() error {
+ httpServer := &http.Server{
+ Addr: c.String("server-addr"),
+ Handler: handler,
+ }
+
+ go func() {
+ <-ctx.Done()
+ log.Info().Msg("shutdown http server ...")
+ if err := httpServer.Shutdown(shutdownCtx); err != nil { //nolint:contextcheck
+ log.Error().Err(err).Msg("shutdown http server failed")
+ } else {
+ log.Info().Msg("http server stopped")
+ }
+ }()
+
+ log.Info().Msg("starting http server ...")
+ if err := httpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
+ log.Error().Err(err).Msg("http server failed")
+ stopServerFunc(fmt.Errorf("http server failed: %w", err))
}
return err
})
}
if metricsServerAddr := c.String("metrics-server-addr"); metricsServerAddr != "" {
- g.Go(func() error {
+ serviceWaitingGroup.Go(func() error {
metricsRouter := gin.New()
metricsRouter.GET("/metrics", gin.WrapH(prometheus_http.Handler()))
- err := http.ListenAndServe(metricsServerAddr, metricsRouter)
- if err != nil && !errors.Is(err, http.ErrServerClosed) {
- log.Fatal().Err(err).Msg("could not start metrics server") //nolint:forbidigo
+
+ metricsServer := &http.Server{
+ Addr: metricsServerAddr,
+ Handler: metricsRouter,
+ }
+
+ go func() {
+ <-ctx.Done()
+ log.Info().Msg("shutdown metrics server ...")
+ if err := metricsServer.Shutdown(shutdownCtx); err != nil { //nolint:contextcheck
+ log.Error().Err(err).Msg("shutdown metrics server failed")
+ } else {
+ log.Info().Msg("metrics server stopped")
+ }
+ }()
+
+ log.Info().Msg("starting metrics server ...")
+ if err := metricsServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
+ log.Error().Err(err).Msg("metrics server failed")
+ stopServerFunc(fmt.Errorf("metrics server failed: %w", err))
}
return err
})
}
- log.Info().Msgf("starting Woodpecker server with version '%s'", version.String())
-
- return g.Wait()
-}
-
-func setupEvilGlobals(c *cli.Context, s store.Store) error {
- // services
- server.Config.Services.Queue = setupQueue(c, s)
- server.Config.Services.Logs = logging.New()
- server.Config.Services.Pubsub = pubsub.New()
- server.Config.Services.Membership = setupMembershipService(c, s)
- serviceManager, err := services.NewManager(c, s, setup.Forge)
- if err != nil {
- return fmt.Errorf("could not setup service manager: %w", err)
- }
- server.Config.Services.Manager = serviceManager
-
- server.Config.Services.LogStore, err = setupLogStore(c, s)
- if err != nil {
- return fmt.Errorf("could not setup log store: %w", err)
- }
-
- // authentication
- server.Config.Pipeline.AuthenticatePublicRepos = c.Bool("authenticate-public-repos")
-
- // Cloning
- server.Config.Pipeline.DefaultCloneImage = c.String("default-clone-image")
- constant.TrustedCloneImages = append(constant.TrustedCloneImages, server.Config.Pipeline.DefaultCloneImage)
-
- // Execution
- _events := c.StringSlice("default-cancel-previous-pipeline-events")
- events := make([]model.WebhookEvent, 0, len(_events))
- for _, v := range _events {
- events = append(events, model.WebhookEvent(v))
- }
- server.Config.Pipeline.DefaultCancelPreviousPipelineEvents = events
- server.Config.Pipeline.DefaultTimeout = c.Int64("default-pipeline-timeout")
- server.Config.Pipeline.MaxTimeout = c.Int64("max-pipeline-timeout")
-
- // limits
- server.Config.Pipeline.Limits.MemSwapLimit = c.Int64("limit-mem-swap")
- server.Config.Pipeline.Limits.MemLimit = c.Int64("limit-mem")
- server.Config.Pipeline.Limits.ShmSize = c.Int64("limit-shm-size")
- server.Config.Pipeline.Limits.CPUQuota = c.Int64("limit-cpu-quota")
- server.Config.Pipeline.Limits.CPUShares = c.Int64("limit-cpu-shares")
- server.Config.Pipeline.Limits.CPUSet = c.String("limit-cpu-set")
-
- // backend options for pipeline compiler
- server.Config.Pipeline.Proxy.No = c.String("backend-no-proxy")
- server.Config.Pipeline.Proxy.HTTP = c.String("backend-http-proxy")
- server.Config.Pipeline.Proxy.HTTPS = c.String("backend-https-proxy")
-
- // server configuration
- server.Config.Server.Cert = c.String("server-cert")
- server.Config.Server.Key = c.String("server-key")
- server.Config.Server.AgentToken = c.String("agent-secret")
- serverHost := strings.TrimSuffix(c.String("server-host"), "/")
- server.Config.Server.Host = serverHost
- if c.IsSet("server-webhook-host") {
- server.Config.Server.WebhookHost = c.String("server-webhook-host")
- } else {
- server.Config.Server.WebhookHost = serverHost
- }
- if c.IsSet("server-dev-oauth-host-deprecated") {
- server.Config.Server.OAuthHost = c.String("server-dev-oauth-host-deprecated")
- } else {
- server.Config.Server.OAuthHost = serverHost
- }
- server.Config.Server.Port = c.String("server-addr")
- server.Config.Server.PortTLS = c.String("server-addr-tls")
- server.Config.Server.StatusContext = c.String("status-context")
- server.Config.Server.StatusContextFormat = c.String("status-context-format")
- server.Config.Server.SessionExpires = c.Duration("session-expires")
- u, _ := url.Parse(server.Config.Server.Host)
- rootPath := strings.TrimSuffix(u.Path, "/")
- if rootPath != "" && !strings.HasPrefix(rootPath, "/") {
- rootPath = "/" + rootPath
- }
- server.Config.Server.RootPath = rootPath
- server.Config.Server.CustomCSSFile = strings.TrimSpace(c.String("custom-css-file"))
- server.Config.Server.CustomJsFile = strings.TrimSpace(c.String("custom-js-file"))
- server.Config.Pipeline.Networks = c.StringSlice("network")
- server.Config.Pipeline.Volumes = c.StringSlice("volume")
- server.Config.Pipeline.Privileged = c.StringSlice("escalate")
- server.Config.WebUI.EnableSwagger = c.Bool("enable-swagger")
- server.Config.WebUI.SkipVersionCheck = c.Bool("skip-version-check")
-
- // prometheus
- server.Config.Prometheus.AuthToken = c.String("prometheus-auth-token")
-
- // permissions
- server.Config.Permissions.Open = c.Bool("open")
- server.Config.Permissions.Admins = permissions.NewAdmins(c.StringSlice("admin"))
- server.Config.Permissions.Orgs = permissions.NewOrgs(c.StringSlice("orgs"))
- server.Config.Permissions.OwnersAllowlist = permissions.NewOwnersAllowlist(c.StringSlice("repo-owners"))
- return nil
+ return serviceWaitingGroup.Wait()
}
diff --git a/cmd/server/setup.go b/cmd/server/setup.go
index b22e8e01a..f221aebc7 100644
--- a/cmd/server/setup.go
+++ b/cmd/server/setup.go
@@ -17,26 +17,40 @@ package main
import (
"context"
+ "encoding/base32"
+ "errors"
"fmt"
+ "net/url"
"os"
+ "strings"
"time"
- "github.com/prometheus/client_golang/prometheus"
- prometheus_auto "github.com/prometheus/client_golang/prometheus/promauto"
+ "github.com/gorilla/securecookie"
"github.com/rs/zerolog/log"
- "github.com/urfave/cli/v2"
- "golang.org/x/sync/errgroup"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/server"
"go.woodpecker-ci.org/woodpecker/v2/server/cache"
+ "go.woodpecker-ci.org/woodpecker/v2/server/forge/setup"
+ "go.woodpecker-ci.org/woodpecker/v2/server/logging"
+ "go.woodpecker-ci.org/woodpecker/v2/server/model"
+ "go.woodpecker-ci.org/woodpecker/v2/server/pubsub"
"go.woodpecker-ci.org/woodpecker/v2/server/queue"
+ "go.woodpecker-ci.org/woodpecker/v2/server/services"
logService "go.woodpecker-ci.org/woodpecker/v2/server/services/log"
"go.woodpecker-ci.org/woodpecker/v2/server/services/log/file"
+ "go.woodpecker-ci.org/woodpecker/v2/server/services/permissions"
"go.woodpecker-ci.org/woodpecker/v2/server/store"
"go.woodpecker-ci.org/woodpecker/v2/server/store/datastore"
+ "go.woodpecker-ci.org/woodpecker/v2/server/store/types"
)
-func setupStore(c *cli.Context) (store.Store, error) {
+const (
+ queueInfoRefreshInterval = 500 * time.Millisecond
+ storeInfoRefreshInterval = 10 * time.Second
+)
+
+func setupStore(ctx context.Context, c *cli.Command) (store.Store, error) {
datasource := c.String("datasource")
driver := c.String("driver")
xorm := store.XORM{
@@ -73,7 +87,7 @@ func setupStore(c *cli.Context) (store.Store, error) {
return nil, fmt.Errorf("could not open datastore: %w", err)
}
- if err := store.Migrate(c.Bool("migrations-allow-long")); err != nil {
+ if err := store.Migrate(ctx, c.Bool("migrations-allow-long")); err != nil {
return nil, fmt.Errorf("could not migrate datastore: %w", err)
}
@@ -89,75 +103,15 @@ func checkSqliteFileExist(path string) error {
return err
}
-func setupQueue(c *cli.Context, s store.Store) queue.Queue {
- return queue.WithTaskStore(queue.New(c.Context), s)
+func setupQueue(ctx context.Context, s store.Store) queue.Queue {
+ return queue.WithTaskStore(ctx, queue.New(ctx), s)
}
-func setupMembershipService(_ *cli.Context, _store store.Store) cache.MembershipService {
+func setupMembershipService(_ context.Context, _store store.Store) cache.MembershipService {
return cache.NewMembershipService(_store)
}
-func setupMetrics(g *errgroup.Group, _store store.Store) {
- pendingSteps := prometheus_auto.NewGauge(prometheus.GaugeOpts{
- Namespace: "woodpecker",
- Name: "pending_steps",
- Help: "Total number of pending pipeline steps.",
- })
- waitingSteps := prometheus_auto.NewGauge(prometheus.GaugeOpts{
- Namespace: "woodpecker",
- Name: "waiting_steps",
- Help: "Total number of pipeline waiting on deps.",
- })
- runningSteps := prometheus_auto.NewGauge(prometheus.GaugeOpts{
- Namespace: "woodpecker",
- Name: "running_steps",
- Help: "Total number of running pipeline steps.",
- })
- workers := prometheus_auto.NewGauge(prometheus.GaugeOpts{
- Namespace: "woodpecker",
- Name: "worker_count",
- Help: "Total number of workers.",
- })
- pipelines := prometheus_auto.NewGauge(prometheus.GaugeOpts{
- Namespace: "woodpecker",
- Name: "pipeline_total_count",
- Help: "Total number of pipelines.",
- })
- users := prometheus_auto.NewGauge(prometheus.GaugeOpts{
- Namespace: "woodpecker",
- Name: "user_count",
- Help: "Total number of users.",
- })
- repos := prometheus_auto.NewGauge(prometheus.GaugeOpts{
- Namespace: "woodpecker",
- Name: "repo_count",
- Help: "Total number of repos.",
- })
-
- g.Go(func() error {
- for {
- stats := server.Config.Services.Queue.Info(context.TODO())
- pendingSteps.Set(float64(stats.Stats.Pending))
- waitingSteps.Set(float64(stats.Stats.WaitingOnDeps))
- runningSteps.Set(float64(stats.Stats.Running))
- workers.Set(float64(stats.Stats.Workers))
- time.Sleep(500 * time.Millisecond)
- }
- })
- g.Go(func() error {
- for {
- repoCount, _ := _store.GetRepoCount()
- userCount, _ := _store.GetUserCount()
- pipelineCount, _ := _store.GetPipelineCount()
- pipelines.Set(float64(pipelineCount))
- users.Set(float64(userCount))
- repos.Set(float64(repoCount))
- time.Sleep(10 * time.Second)
- }
- })
-}
-
-func setupLogStore(c *cli.Context, s store.Store) (logService.Service, error) {
+func setupLogStore(c *cli.Command, s store.Store) (logService.Service, error) {
switch c.String("log-store") {
case "file":
return file.NewLogStore(c.String("log-store-file-path"))
@@ -165,3 +119,120 @@ func setupLogStore(c *cli.Context, s store.Store) (logService.Service, error) {
return s, nil
}
}
+
+const jwtSecretID = "jwt-secret"
+
+func setupJWTSecret(_store store.Store) (string, error) {
+ jwtSecret, err := _store.ServerConfigGet(jwtSecretID)
+ if errors.Is(err, types.RecordNotExist) {
+ jwtSecret := base32.StdEncoding.EncodeToString(
+ securecookie.GenerateRandomKey(32),
+ )
+ err = _store.ServerConfigSet(jwtSecretID, jwtSecret)
+ if err != nil {
+ return "", err
+ }
+ log.Debug().Msg("created jwt secret")
+ return jwtSecret, nil
+ }
+
+ if err != nil {
+ return "", err
+ }
+
+ return jwtSecret, nil
+}
+
+func setupEvilGlobals(ctx context.Context, c *cli.Command, s store.Store) error {
+ // services
+ server.Config.Services.Queue = setupQueue(ctx, s)
+ server.Config.Services.Logs = logging.New()
+ server.Config.Services.Pubsub = pubsub.New()
+ server.Config.Services.Membership = setupMembershipService(ctx, s)
+ serviceManager, err := services.NewManager(c, s, setup.Forge)
+ if err != nil {
+ return fmt.Errorf("could not setup service manager: %w", err)
+ }
+ server.Config.Services.Manager = serviceManager
+
+ server.Config.Services.LogStore, err = setupLogStore(c, s)
+ if err != nil {
+ return fmt.Errorf("could not setup log store: %w", err)
+ }
+
+ // authentication
+ server.Config.Pipeline.AuthenticatePublicRepos = c.Bool("authenticate-public-repos")
+
+ // Cloning
+ server.Config.Pipeline.DefaultClonePlugin = c.String("default-clone-plugin")
+ server.Config.Pipeline.TrustedClonePlugins = c.StringSlice("plugins-trusted-clone")
+ server.Config.Pipeline.TrustedClonePlugins = append(server.Config.Pipeline.TrustedClonePlugins, server.Config.Pipeline.DefaultClonePlugin)
+
+ // Execution
+ _events := c.StringSlice("default-cancel-previous-pipeline-events")
+ events := make([]model.WebhookEvent, 0, len(_events))
+ for _, v := range _events {
+ events = append(events, model.WebhookEvent(v))
+ }
+ server.Config.Pipeline.DefaultCancelPreviousPipelineEvents = events
+ server.Config.Pipeline.DefaultTimeout = c.Int("default-pipeline-timeout")
+ server.Config.Pipeline.MaxTimeout = c.Int("max-pipeline-timeout")
+
+ // limits
+ server.Config.Pipeline.Limits.MemSwapLimit = c.Int("limit-mem-swap")
+ server.Config.Pipeline.Limits.MemLimit = c.Int("limit-mem")
+ server.Config.Pipeline.Limits.ShmSize = c.Int("limit-shm-size")
+ server.Config.Pipeline.Limits.CPUQuota = c.Int("limit-cpu-quota")
+ server.Config.Pipeline.Limits.CPUShares = c.Int("limit-cpu-shares")
+ server.Config.Pipeline.Limits.CPUSet = c.String("limit-cpu-set")
+
+ // backend options for pipeline compiler
+ server.Config.Pipeline.Proxy.No = c.String("backend-no-proxy")
+ server.Config.Pipeline.Proxy.HTTP = c.String("backend-http-proxy")
+ server.Config.Pipeline.Proxy.HTTPS = c.String("backend-https-proxy")
+
+ // server configuration
+ server.Config.Server.JWTSecret, err = setupJWTSecret(s)
+ if err != nil {
+ return fmt.Errorf("could not setup jwt secret: %w", err)
+ }
+ server.Config.Server.Cert = c.String("server-cert")
+ server.Config.Server.Key = c.String("server-key")
+ server.Config.Server.AgentToken = c.String("agent-secret")
+ serverHost := strings.TrimSuffix(c.String("server-host"), "/")
+ server.Config.Server.Host = serverHost
+ if c.IsSet("server-webhook-host") {
+ server.Config.Server.WebhookHost = c.String("server-webhook-host")
+ } else {
+ server.Config.Server.WebhookHost = serverHost
+ }
+ server.Config.Server.OAuthHost = serverHost
+ server.Config.Server.Port = c.String("server-addr")
+ server.Config.Server.PortTLS = c.String("server-addr-tls")
+ server.Config.Server.StatusContext = c.String("status-context")
+ server.Config.Server.StatusContextFormat = c.String("status-context-format")
+ server.Config.Server.SessionExpires = c.Duration("session-expires")
+ u, _ := url.Parse(server.Config.Server.Host)
+ rootPath := strings.TrimSuffix(u.Path, "/")
+ if rootPath != "" && !strings.HasPrefix(rootPath, "/") {
+ rootPath = "/" + rootPath
+ }
+ server.Config.Server.RootPath = rootPath
+ server.Config.Server.CustomCSSFile = strings.TrimSpace(c.String("custom-css-file"))
+ server.Config.Server.CustomJsFile = strings.TrimSpace(c.String("custom-js-file"))
+ server.Config.Pipeline.Networks = c.StringSlice("network")
+ server.Config.Pipeline.Volumes = c.StringSlice("volume")
+ server.Config.WebUI.EnableSwagger = c.Bool("enable-swagger")
+ server.Config.WebUI.SkipVersionCheck = c.Bool("skip-version-check")
+ server.Config.Pipeline.PrivilegedPlugins = c.StringSlice("plugins-privileged")
+
+ // prometheus
+ server.Config.Prometheus.AuthToken = c.String("prometheus-auth-token")
+
+ // permissions
+ server.Config.Permissions.Open = c.Bool("open")
+ server.Config.Permissions.Admins = permissions.NewAdmins(c.StringSlice("admin"))
+ server.Config.Permissions.Orgs = permissions.NewOrgs(c.StringSlice("orgs"))
+ server.Config.Permissions.OwnersAllowlist = permissions.NewOwnersAllowlist(c.StringSlice("repo-owners"))
+ return nil
+}
diff --git a/cmd/server/swagger.go b/cmd/server/swagger.go
index c38e5dd62..2acb8be76 100644
--- a/cmd/server/swagger.go
+++ b/cmd/server/swagger.go
@@ -21,7 +21,7 @@ import (
// Generate docs/swagger.json via:
//go:generate go run woodpecker_docs_gen.go swagger.go
-//go:generate go run github.com/go-swagger/go-swagger/cmd/swagger@latest validate ../../docs/swagger.json
+//go:generate go run github.com/getkin/kin-openapi/cmd/validate@latest ../../docs/swagger.json
// setupSwaggerStaticConfig initializes static content only (contacts, title and description)
// for dynamic configuration of e.g. hostname, etc. see router.setupSwaggerConfigAndRoutes
@@ -33,7 +33,7 @@ func setupSwaggerStaticConfig() {
docs.SwaggerInfo.InfoInstanceName = "api"
docs.SwaggerInfo.Title = "Woodpecker CI API"
docs.SwaggerInfo.Version = version.String()
- docs.SwaggerInfo.Description = "Woodpecker is a simple yet powerful CI/CD engine with great extensibility.\n" +
+ docs.SwaggerInfo.Description = "Woodpecker is a simple, yet powerful CI/CD engine with great extensibility.\n" +
"To get a personal access token (PAT) for authentication, please log in your Woodpecker server,\n" +
"and go to you personal profile page, by clicking the user icon at the top right."
}
diff --git a/cmd/server/woodpecker_docs_gen.go b/cmd/server/woodpecker_docs_gen.go
index 9f5069a62..0ca776671 100644
--- a/cmd/server/woodpecker_docs_gen.go
+++ b/cmd/server/woodpecker_docs_gen.go
@@ -22,10 +22,13 @@
package main
import (
+ "context"
"encoding/json"
"os"
"path"
+ "github.com/getkin/kin-openapi/openapi2"
+ "github.com/getkin/kin-openapi/openapi2conv"
"go.woodpecker-ci.org/woodpecker/v2/cmd/server/docs"
)
@@ -33,29 +36,69 @@ func main() {
// set swagger infos
setupSwaggerStaticConfig()
+ basePath := path.Join("..", "..")
+ filePath := path.Join(basePath, "docs", "swagger.json")
+
// generate swagger file
- f, err := os.Create(path.Join("..", "..", "docs", "swagger.json"))
+ f, err := os.Create(filePath)
if err != nil {
panic(err)
}
defer f.Close()
doc := docs.SwaggerInfo.ReadDoc()
- doc = removeHost(doc)
+ doc, err = removeHost(doc)
+ if err != nil {
+ panic(err)
+ }
_, err = f.WriteString(doc)
if err != nil {
panic(err)
}
+
+ // convert to OpenApi3
+ if err := toOpenApi3(filePath, filePath); err != nil {
+ panic(err)
+ }
}
-func removeHost(jsonIn string) string {
+func removeHost(jsonIn string) (string, error) {
m := make(map[string]interface{})
if err := json.Unmarshal([]byte(jsonIn), &m); err != nil {
- panic(err)
+ return "", err
}
delete(m, "host")
raw, err := json.Marshal(m)
if err != nil {
- panic(err)
+ return "", err
}
- return string(raw)
+ return string(raw), nil
+}
+
+func toOpenApi3(input, output string) error {
+ data2, err := os.ReadFile(input)
+ if err != nil {
+ return err
+ }
+
+ var doc2 openapi2.T
+ err = json.Unmarshal(data2, &doc2)
+ if err != nil {
+ return err
+ }
+
+ doc3, err := openapi2conv.ToV3(&doc2)
+ if err != nil {
+ return err
+ }
+ err = doc3.Validate(context.Background())
+ if err != nil {
+ return err
+ }
+
+ data, err := json.Marshal(doc3)
+ if err != nil {
+ return err
+ }
+
+ return os.WriteFile(output, data, 0o644)
}
diff --git a/docker/Dockerfile.agent.alpine.multiarch b/docker/Dockerfile.agent.alpine.multiarch
index 5de3db18c..74ece6be9 100644
--- a/docker/Dockerfile.agent.alpine.multiarch
+++ b/docker/Dockerfile.agent.alpine.multiarch
@@ -1,4 +1,4 @@
-FROM --platform=$BUILDPLATFORM docker.io/golang:1.22 AS build
+FROM --platform=$BUILDPLATFORM docker.io/golang:1.23 AS build
WORKDIR /src
COPY . .
@@ -8,10 +8,10 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
make build-agent
FROM docker.io/alpine:3.20
-# renovate: datasource=repology depName=alpine_3_18/ca-certificates versioning=loose
-ENV CA_CERTIFICATES_VERSION="20240226-r0"
-RUN apk add -U --no-cache ca-certificates=${CA_CERTIFICATES_VERSION}
+RUN apk add -U --no-cache ca-certificates
ENV GODEBUG=netdns=go
+# Internal setting do NOT change! Signals that woodpecker is running inside a container
+ENV WOODPECKER_IN_CONTAINER=true
EXPOSE 3000
COPY --from=build /src/dist/woodpecker-agent /bin/
diff --git a/docker/Dockerfile.agent.multiarch b/docker/Dockerfile.agent.multiarch
index 6349a3d50..ccf5b3a23 100644
--- a/docker/Dockerfile.agent.multiarch
+++ b/docker/Dockerfile.agent.multiarch
@@ -1,4 +1,4 @@
-FROM --platform=$BUILDPLATFORM docker.io/golang:1.22 AS build
+FROM --platform=$BUILDPLATFORM docker.io/golang:1.23 AS build
WORKDIR /src
COPY . .
@@ -10,6 +10,8 @@ RUN mkdir -p /etc/woodpecker
FROM scratch
ENV GODEBUG=netdns=go
+# Internal setting do NOT change! Signals that woodpecker is running inside a container
+ENV WOODPECKER_IN_CONTAINER=true
EXPOSE 3000
# copy certs from build image
diff --git a/docker/Dockerfile.cli.alpine.multiarch b/docker/Dockerfile.cli.alpine.multiarch
index e8348da87..de5fd0688 100644
--- a/docker/Dockerfile.cli.alpine.multiarch
+++ b/docker/Dockerfile.cli.alpine.multiarch
@@ -1,4 +1,4 @@
-FROM --platform=$BUILDPLATFORM docker.io/golang:1.22 AS build
+FROM --platform=$BUILDPLATFORM docker.io/golang:1.23 AS build
WORKDIR /src
COPY . .
@@ -8,9 +8,10 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
make build-cli
FROM docker.io/alpine:3.20
-# renovate: datasource=repology depName=alpine_3_18/ca-certificates versioning=loose
-ENV CA_CERTIFICATES_VERSION="20240226-r0"
-RUN apk add -U --no-cache ca-certificates=${CA_CERTIFICATES_VERSION}
+WORKDIR /woodpecker
+
+RUN apk add -U --no-cache ca-certificates
+
ENV GODEBUG=netdns=go
ENV WOODPECKER_DISABLE_UPDATE_CHECK=true
diff --git a/docker/Dockerfile.cli.multiarch b/docker/Dockerfile.cli.multiarch
index 2afeb82e2..2e1a7009f 100644
--- a/docker/Dockerfile.cli.multiarch
+++ b/docker/Dockerfile.cli.multiarch
@@ -1,4 +1,4 @@
-FROM --platform=$BUILDPLATFORM docker.io/golang:1.22 AS build
+FROM --platform=$BUILDPLATFORM docker.io/golang:1.23 AS build
WORKDIR /src
COPY . .
@@ -8,6 +8,8 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
make build-cli
FROM scratch
+WORKDIR /woodpecker
+
ENV GODEBUG=netdns=go
ENV WOODPECKER_DISABLE_UPDATE_CHECK=true
diff --git a/docker/Dockerfile.make b/docker/Dockerfile.make
index d18cf733e..6a37955ad 100644
--- a/docker/Dockerfile.make
+++ b/docker/Dockerfile.make
@@ -1,5 +1,5 @@
# docker build --rm -f docker/Dockerfile.make -t woodpecker/make:local .
-FROM docker.io/golang:1.22-alpine3.19 as golang_image
+FROM docker.io/golang:1.23-alpine3.19 as golang_image
FROM docker.io/node:22-alpine3.19
# renovate: datasource=repology depName=alpine_3_19/make versioning=loose
diff --git a/docker/Dockerfile.server.alpine.multiarch b/docker/Dockerfile.server.alpine.multiarch
index 002cbcb69..094a9fe4d 100644
--- a/docker/Dockerfile.server.alpine.multiarch
+++ b/docker/Dockerfile.server.alpine.multiarch
@@ -1,10 +1,7 @@
FROM docker.io/alpine:3.20
-# renovate: datasource=repology depName=alpine_3_18/ca-certificates versioning=loose
-ENV CA_CERTIFICATES_VERSION="20240226-r0"
-
ARG TARGETOS TARGETARCH
-RUN apk add -U --no-cache ca-certificates=${CA_CERTIFICATES_VERSION}
+RUN apk add -U --no-cache ca-certificates
ENV GODEBUG=netdns=go
# Internal setting do NOT change! Signals that woodpecker is running inside a container
ENV WOODPECKER_IN_CONTAINER=true
diff --git a/docker/Dockerfile.server.multiarch b/docker/Dockerfile.server.multiarch
index 3bf86a3be..56e02b462 100644
--- a/docker/Dockerfile.server.multiarch
+++ b/docker/Dockerfile.server.multiarch
@@ -1,4 +1,4 @@
-FROM --platform=$BUILDPLATFORM docker.io/golang:1.22 AS certs
+FROM --platform=$BUILDPLATFORM docker.io/golang:1.23 AS certs
FROM scratch
ARG TARGETOS TARGETARCH
diff --git a/docs/blog/2023-12-12-podman-image-builds/index.md b/docs/blog/2023-12-12-podman-image-builds/index.md
new file mode 100644
index 000000000..3e7fe9008
--- /dev/null
+++ b/docs/blog/2023-12-12-podman-image-builds/index.md
@@ -0,0 +1,58 @@
+---
+title: '[Community] Podman-in-Podman image builds'
+description: Build images in Podman with buildah
+slug: podman-image-builds
+authors:
+ - name: handlebargh
+ url: https://github.com/handlebargh
+ image_url: https://github.com/handlebargh.png
+hide_table_of_contents: true
+tags: [community, image, podman]
+---
+
+
+
+I run Woodpecker CI with podman backend instead of docker and just figured out how to build images with buildah. Since I couldn't find this anywhere documented, I thought I might as well just share it here.
+
+It's actually pretty straight forward. Here's what my repository structure looks like:
+
+```bash
+.
+├── roundcube
+│ ├── Containerfile
+│ ├── docker-entrypoint.sh
+│ └── php.ini
+└── .woodpecker
+ └── .build_roundcube.yml
+```
+
+As you can see I'm building a roundcube mail image.
+
+This is the `.woodpecker/.build_roundcube.yaml`
+
+```yaml
+when:
+ event: [cron, manual]
+ cron: build_roundcube
+
+steps:
+ build-image:
+ image: quay.io/buildah/stable:latest
+ pull: true
+ privileged: true
+ commands:
+ - echo $REGISTRY_LOGIN_TOKEN | buildah login -u --password-stdin registry.gitlab.com
+ - cd roundcube
+ - buildah build --tag registry.gitlab.com///roundcube:latest .
+ - buildah push registry.gitlab.com///roundcube:latest
+
+ secrets: [registry_login_token]
+```
+
+As you can see, I'm using this workflow over at gitlab.com. It should work with GitHub as well, with adjusting the registry login.
+
+You may have to adjust the `when:` to your needs. Furthermore, you must check the `trusted` checkbox in project settings. Therefore, be sure to run trusted code only in this setup.
+
+This seems to work fine so far. I wonder if anybody else made this work a different way.
+
+EDIT: Removed the additional step that would run buildah in a podman container. I didn't know it could be that easy to be honest.
diff --git a/docs/blog/2023-12-13-debug-pipeline-steps/index.md b/docs/blog/2023-12-13-debug-pipeline-steps/index.md
new file mode 100644
index 000000000..5f5d116c9
--- /dev/null
+++ b/docs/blog/2023-12-13-debug-pipeline-steps/index.md
@@ -0,0 +1,29 @@
+---
+title: '[Community] Debug pipeline steps'
+description: Debug pipeline steps using sshx
+slug: debug-pipeline-steps
+authors:
+ - name: anbraten
+ url: https://github.com/anbraten
+ image_url: https://github.com/anbraten.png
+hide_table_of_contents: true
+tags: [community, debug]
+---
+
+
+
+Sometimes you want to debug a pipeline.
+Therefore I recently discovered:
+
+A simple step like should allow you to debug:
+
+```yaml
+steps:
+ - name: debug
+ image: alpine
+ commands:
+ - curl -sSf https://sshx.io/get | sh && sshx
+ # ^
+ # └ This will open a remote terminal session and print the URL. It
+ # should take under a second.
+```
diff --git a/docs/blog/2023-12-15-podman-sigstore/index.md b/docs/blog/2023-12-15-podman-sigstore/index.md
new file mode 100644
index 000000000..db3d5b964
--- /dev/null
+++ b/docs/blog/2023-12-15-podman-sigstore/index.md
@@ -0,0 +1,138 @@
+---
+title: '[Community] Podman image build with sigstore'
+description: Build images in Podman with sigstore signature checking and signing
+slug: podman-image-build-sigstore
+authors:
+ - name: handlebargh
+ url: https://github.com/handlebargh
+ image_url: https://github.com/handlebargh.png
+hide_table_of_contents: false
+tags: [community, image, podman, sigstore, signature]
+---
+
+
+
+This example shows how to build a container image with podman while verifying the base image and signing the resulting image.
+
+The image being pulled uses a keyless signature, while the image being built will be signed by a pre-generated private key.
+
+## Prerequisites
+
+### Generate signing keypair
+
+You can use cosing or skopeo to generate the keypair.
+
+Using skopeo:
+
+```bash
+skopeo generate-sigstore-key --output-prefix myKey
+```
+
+This command will generate a `myKey.private` and a `myKey.pub` keyfile.
+
+Store the `myKey.private` as secret in Woodpecker. In the example below, the secret is called `sigstore_private_key`
+
+### Configure hosts pulling the resulting image
+
+See [here](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/building_running_and_managing_containers/assembly_signing-container-images_building-running-and-managing-containers#proc_verifying-sigstore-image-signatures-using-a-public-key_assembly_signing-container-images) on how to configure the hosts pulling the built and signed image.
+
+## Repository structure
+
+Consider the `Makefile` having a `build` target that will be used in the following workflow.
+This target yields a Go binary with the filename `app` that will be placed in the root directory.
+
+```bash
+.
+├── Containerfile
+├── main.go
+├── go.mod
+├── go.sum
+├── .woodpecker.yml
+└── Makefile
+```
+
+### Containerfile
+
+The Containerfile refers to the base image that will be verified when pulled.
+
+```dockerfile
+FROM gcr.io/distroless/static-debian12:nonroot
+COPY app /app
+CMD ["/app"]
+```
+
+### Woodpecker workflow
+
+```yaml
+steps:
+ build:
+ image: docker.io/library/golang:1.21
+ pull: true
+ commands:
+ - make build
+
+ publish:
+ image: quay.io/podman/stable:latest
+ # Caution: This image is built daily. It might fill up your image store quickly.
+ pull: true
+ # Fill in the trusted checkbox in Woodpecker's settings as well
+ privileged: true
+ commands:
+ # Configure podman to use sigstore attachments for both, the registry you pull from and the registry you push to.
+ - |
+ printf "docker:
+ registry.gitlab.com:
+ use-sigstore-attachments: true
+ gcr.io:
+ use-sigstore-attachments: true" >> /etc/containers/registries.d/default.yaml
+
+ # At pull, check the keyless sigstore signature of the distroless image.
+ # This is a very strict container policy. It allows pulling from gcr.io/distroless only. Every other registry will be rejected.
+ # See https://github.com/containers/image/blob/main/docs/containers-policy.json.5.md for more information.
+
+ # fulcio CA crt obtained from https://github.com/sigstore/sigstore/blob/main/pkg/tuf/repository/targets/fulcio_v1.crt.pem
+ # rekor public key obtained from https://github.com/sigstore/sigstore/blob/main/pkg/tuf/repository/targets/rekor.pub
+ # crt/key data is base64 encoded. --> echo "$CERT" | base64
+ - |
+ printf '{
+ "default": [
+ {
+ "type": "reject"
+ }
+ ],
+ "transports": {
+ "docker": {
+ "gcr.io/distroless": [
+ {
+ "type": "sigstoreSigned",
+ "fulcio": {
+ "caData": "LS0tLS1CRUdJTiBDR...QVRFLS0tLS0K",
+ "oidcIssuer": "https://accounts.google.com",
+ "subjectEmail": "keyless@distroless.iam.gserviceaccount.com"
+ },
+ "rekorPublicKeyData": "LS0tLS1CRUdJTiBQVUJ...lDIEtFWS0tLS0tCg==",
+ "signedIdentity": { "type": "matchRepository" }
+ }
+ ]
+ },
+ "docker-daemon": {
+ "": [
+ {
+ "type": "reject"
+ }
+ ]
+ }
+ }
+ }' > /etc/containers/policy.json
+
+ # Use this key to sign the built image at push.
+ - echo "$SIGSTORE_PRIVATE_KEY" > key.private
+ # Login at the registry
+ - echo $REGISTRY_LOGIN_TOKEN | podman login -u --password-stdin registry.gitlab.com
+ # Build the container image
+ - podman build --tag registry.gitlab.com///:latest .
+ # Sign and push the image
+ - podman push --sign-by-sigstore-private-key ./key.private registry.gitlab.com///:latest
+
+ secrets: [sigstore_private_key, registry_login_token]
+```
diff --git a/docs/cookbook/2024-1-1-continuous-deployment/index.md b/docs/blog/2024-01-01-continuous-deployment/index.md
similarity index 97%
rename from docs/cookbook/2024-1-1-continuous-deployment/index.md
rename to docs/blog/2024-01-01-continuous-deployment/index.md
index c1bedcc37..f455186a6 100644
--- a/docs/cookbook/2024-1-1-continuous-deployment/index.md
+++ b/docs/blog/2024-01-01-continuous-deployment/index.md
@@ -1,5 +1,5 @@
---
-title: Continuous Deployment
+title: '[Community] Continuous Deployment'
description: Deploy your artifacts to an app server
slug: continuous-deployment
authors:
@@ -7,16 +7,17 @@ authors:
url: https://github.com/lonix1
image_url: https://github.com/lonix1.png
hide_table_of_contents: false
+tags: [community, cd, deployment]
---
-
-
A typical CI pipeline contains steps such as: _clone_, _build_, _test_, _package_ and _push_. The final build product may be artifacts pushed to a git repository or a docker container pushed to a container registry.
When these should be deployed on an app server, the pipeline should include a _deploy_ step, which represents the "CD" in CI/CD - the automatic deployment of a pipeline's final product.
There are various ways to accomplish CD with Woodpecker, depending on your project's specific needs.
+
+
## Invoking deploy script via SSH
The final step in your pipeline could SSH into the app server and run a deployment script.
diff --git a/docs/blog/2024-05-27-release-v2.5.0/index.md b/docs/blog/2024-05-27-release-v2.5.0/index.md
index 2adee0bc0..3f9bd3d6c 100644
--- a/docs/blog/2024-05-27-release-v2.5.0/index.md
+++ b/docs/blog/2024-05-27-release-v2.5.0/index.md
@@ -45,7 +45,7 @@ NUMBER STATUS EVENT BRANCH COMMIT AUTHO
42 success push
```
-In addition especially useful for programmtic usage there is a `go-template` output format which will output the data using the provided go template like this:
+In addition especially useful for programmatic usage there is a `go-template` output format which will output the data using the provided go template like this:
```bash
########
diff --git a/docs/cookbook/2023-12-23-hello-cookbook/index.md b/docs/cookbook/2023-12-23-hello-cookbook/index.md
deleted file mode 100644
index d3055dfba..000000000
--- a/docs/cookbook/2023-12-23-hello-cookbook/index.md
+++ /dev/null
@@ -1,13 +0,0 @@
----
-title: Welcome to Woodpecker's cookbook blog
-description: Here, we'll publish various guides and tutorials.
-slug: hello-cookbook
-authors:
- - name: qwerty287
- title: Maintainer of Woodpecker
- url: https://github.com/qwerty287
- image_url: https://github.com/qwerty287.png
-hide_table_of_contents: false
----
-
-Welcome to this cookbook blog. Here, we and any other interested user can publish guides and tutorials. If you got something in mind, just add your guide!
diff --git a/docs/docs/10-intro.md b/docs/docs/10-intro.md
deleted file mode 100644
index 309c6f1af..000000000
--- a/docs/docs/10-intro.md
+++ /dev/null
@@ -1,89 +0,0 @@
-# Welcome to Woodpecker
-
-Woodpecker is a simple yet powerful CI/CD engine with great extensibility. It focuses on executing pipelines inside [containers](https://opencontainers.org/).
-If you are already using containers in your daily workflow, you'll for sure love Woodpecker.
-
-![woodpecker](woodpecker.png)
-
-## `.woodpecker.yaml`
-
-- Place your pipeline in a file named `.woodpecker.yaml` in your repository
-- Pipeline steps can be named as you like
-- Run any command in the commands section
-
-```yaml title=".woodpecker.yaml"
-steps:
- - name: build
- image: debian
- commands:
- - echo "This is the build step"
- - name: a-test-step
- image: debian
- commands:
- - echo "Testing.."
-```
-
-### Steps are containers
-
-- Define any container image as context
- - either use your own and install the needed tools in a custom image
- - or search for available images that are already tailored for your needs in image registries like [Docker Hub](https://hub.docker.com/search?type=image)
-- List the commands that should be executed in the container
-
-```diff
- steps:
- - name: build
-- image: debian
-+ image: mycompany/image-with-awscli
- commands:
- - aws help
-```
-
-### File changes are incremental
-
-- Woodpecker clones the source code in the beginning
-- File changes are persisted throughout individual steps as the same volume is being mounted in all steps
-
-```yaml title=".woodpecker.yaml"
-steps:
- - name: build
- image: debian
- commands:
- - touch myfile
- - name: a-test-step
- image: debian
- commands:
- - cat myfile
-```
-
-## Plugins are straightforward
-
-- If you copy the same shell script from project to project
-- Pack it into a plugin instead
-- And make the yaml declarative
-- Plugins are Docker images with your script as an entrypoint
-
-```dockerfile title="Dockerfile"
-FROM laszlocloud/kubectl
-COPY deploy /usr/local/deploy
-ENTRYPOINT ["/usr/local/deploy"]
-```
-
-```bash title="deploy"
-kubectl apply -f $PLUGIN_TEMPLATE
-```
-
-```yaml title=".woodpecker.yaml"
-steps:
- - name: deploy-to-k8s
- image: laszlocloud/my-k8s-plugin
- settings:
- template: config/k8s/service.yaml
-```
-
-See [plugin docs](./20-usage/51-plugins/51-overview.md).
-
-## Continue reading
-
-- [Create a Woodpecker pipeline for your repository](./20-usage/10-intro.md)
-- [Setup your own Woodpecker instance](./30-administration/00-deployment/00-overview.md)
diff --git a/docs/docs/10-intro/index.md b/docs/docs/10-intro/index.md
new file mode 100644
index 000000000..7d9ced179
--- /dev/null
+++ b/docs/docs/10-intro/index.md
@@ -0,0 +1,26 @@
+# Welcome to Woodpecker
+
+Woodpecker is a CI/CD tool. It is designed to be lightweight, simple to use and fast. Before we dive into the details, let's have a look at some of the basics.
+
+## Have you ever heard of CI/CD or pipelines?
+
+Don't worry if you haven't. We'll guide you through the basics. CI/CD stands for Continuous Integration and Continuous Deployment. It's basically like a conveyor belt that moves your code from development to production doing all kinds of
+checks, tests and routines along the way. A typical pipeline might include the following steps:
+
+1. Running tests
+2. Building your application
+3. Deploying your application
+
+[Have a deeper look into the idea of CI/CD](https://www.redhat.com/en/topics/devops/what-is-ci-cd)
+
+## Do you know containers?
+
+If you are already using containers in your daily workflow, you'll for sure love Woodpecker. If not yet, you'll be amazed how easy it is to get started with [containers](https://opencontainers.org/).
+
+## Already have access to a Woodpecker instance?
+
+Then you might want to jump directly into it and [start creating your first pipelines](../20-usage/10-intro.md).
+
+## Want to start from scratch and deploy your own Woodpecker instance?
+
+Woodpecker is [pretty lightweight](../30-administration/00-getting-started.md#hardware-requirements) and will even run on your Raspberry Pi. You can follow the [deployment guide](../30-administration/00-getting-started.md) to set up your own Woodpecker instance.
diff --git a/docs/docs/20-usage/10-intro.md b/docs/docs/20-usage/10-intro.md
index 477466173..1c4baec1f 100644
--- a/docs/docs/20-usage/10-intro.md
+++ b/docs/docs/20-usage/10-intro.md
@@ -1,72 +1,110 @@
-# Getting started
+# Your first pipeline
-## Repository Activation
+Let's get started and create your first pipeline.
-To activate your project navigate to your account settings. You will see a list of repositories which can be activated with a simple toggle. When you activate your repository, Woodpecker automatically adds webhooks to your forge (e.g. GitHub, Gitea, ...).
+## 1. Repository Activation
-Webhooks are used to trigger pipeline executions. When you push code to your repository, open a pull request, or create a tag, your forge will automatically send a webhook to Woodpecker which will in turn trigger the pipeline execution.
+To activate your repository in Woodpecker navigate to the repository list and `New repository`. You will see a list of repositories from your forge (GitHub, Gitlab, ...) which can be activated with a simple click.
-![repository list](repo-list.png)
+![new repository list](repo-new.png)
-## Required Permissions
+To enable a repository in Woodpecker you must have `Admin` rights on that repository, so that Woodpecker can add something
+that is called a webhook (Woodpecker needs it to know about actions like pushes, pull requests, tags, etc.).
-The user who enables a repo in Woodpecker must have `Admin` rights on that repo, so that Woodpecker can add the webhook.
+## 2. Define first workflow
-:::note
-Note that manually creating webhooks yourself is not possible.
-This is because webhooks are signed using a per-repository secret key which is not exposed to end users.
-:::
+After enabling a repository Woodpecker will listen for changes in your repository. When a change is detected, Woodpecker will check for a pipeline configuration. So let's create a file at `.woodpecker/my-first-workflow.yaml` inside your repository:
-## Configuration
+```yaml title=".woodpecker/my-first-workflow.yaml"
+when:
+ - event: push
+ branch: main
-To configure your pipeline you must create a `.woodpecker.yaml` file in the root of your repository. The `.woodpecker.yaml` file is used to define your pipeline steps.
-
-:::note
-We support most of YAML 1.2, but preserve some behavior from 1.1 for backward compatibility.
-Read more at: [https://github.com/go-yaml/yaml](https://github.com/go-yaml/yaml/tree/v3)
-:::
-
-Example pipeline configuration:
-
-```yaml
steps:
- name: build
- image: golang
+ image: debian
commands:
- - go get
- - go build
- - go test
-
-services:
- - name: postgres
- image: postgres:9.4.5
- environment:
- - POSTGRES_USER=myapp
+ - echo "This is the build step"
+ - echo "binary-data-123" > executable
+ - name: a-test-step
+ image: golang:1.16
+ commands:
+ - echo "Testing ..."
+ - ./executable
```
-Example pipeline configuration with multiple, serial steps:
+**So what did we do here?**
+
+1. We defined your first workflow file `my-first-workflow.yaml`.
+2. This workflow will be executed when a push event happens on the `main` branch,
+ because we added a filter using the `when` section:
+
+ ```diff
+ + when:
+ + - event: push
+ + branch: main
+
+ ...
+ ```
+
+3. We defined two steps: `build` and `a-test-step`
+
+The steps are executed in the order they are defined, so `build` will be executed first and then `a-test-step`.
+
+In the `build` step we use the `debian` image and build a "binary file" called `executable`.
+
+In the `a-test-step` we use the `golang:1.16` image and run the `executable` file to test it.
+
+You can use any image from registries like the [Docker Hub](https://hub.docker.com/search?type=image) you have access to:
+
+```diff
+ steps:
+ - name: build
+- image: debian
++ image: my-company/image-with-aws_cli
+ commands:
+ - aws help
+```
+
+## 3. Push the file and trigger first pipeline
+
+If you push this file to your repository now, Woodpecker will already execute your first pipeline.
+
+You can check the pipeline execution in the Woodpecker UI by navigating to the `Pipelines` section of your repository.
+
+![pipeline view](./pipeline.png)
+
+As you probably noticed, there is another step in called `clone` which is executed before your steps. This step clones your repository into a folder called `workspace` which is available throughout all steps.
+
+This for example allows the first step to build your application using your source code and as the second step will receive
+the same workspace it can use the previously built binary and test it.
+
+## 4. Use a plugin for reusable tasks
+
+Sometimes you have some tasks that you need to do in every project. For example, deploying to Kubernetes or sending a Slack message. Therefore you can use one of the [official and community plugins](/plugins) or simply [create your own](./51-plugins/20-creating-plugins.md).
+
+If you want to get a Slack notification after your pipeline has finished, you can add a Slack plugin to your pipeline:
```yaml
steps:
- - name: backend
- image: golang
- commands:
- - go get
- - go build
- - go test
-
- - name: frontend
- image: node:6
- commands:
- - npm install
- - npm test
-
- - name: notify
+ # ...
+ - name: notify me on Slack
image: plugins/slack
- channel: developers
- username: woodpecker
+ settings:
+ channel: developers
+ username: woodpecker
+ password:
+ from_secret: slack_token
+ when:
+ status: [success, failure] # This will execute the step on success and failure
```
-## Execution
+To configure a plugin you can use the `settings` section.
-To trigger your first pipeline execution you can push code to your repository, open a pull request, or push a tag. Any of these events triggers a webhook from your forge and execute your pipeline.
+Sometime you need to provide secrets to the plugin. You can do this by using the `from_secret` key. The secret must be defined in the Woodpecker UI. You can find more information about secrets [here](./40-secrets.md).
+
+Similar to the `when` section at the top of the file which is for the complete workflow, you can use the `when` section for each step to define when a step should be executed.
+
+Learn more about [plugins](./51-plugins/51-overview.md).
+
+As you now have a basic understanding of how to create a pipeline, you can dive deeper into the [workflow syntax](./20-workflow-syntax.md) and [plugins](./51-plugins/51-overview.md).
diff --git a/docs/docs/20-usage/15-terminology/index.md b/docs/docs/20-usage/15-terminology/index.md
index 5e9d8e5de..0b5eafd8a 100644
--- a/docs/docs/20-usage/15-terminology/index.md
+++ b/docs/docs/20-usage/15-terminology/index.md
@@ -1,13 +1,5 @@
# Terminology
-## Woodpecker architecture
-
-![Woodpecker architecture](architecture.svg)
-
-## Pipeline, workflow & step
-
-![Relation between pipelines, workflows and steps](pipeline-workflow-step.svg)
-
## Glossary
- **Woodpecker CI**: The project name around Woodpecker.
@@ -15,33 +7,31 @@
- **Server**: The component of Woodpecker that handles webhooks from forges, orchestrates agents, and sends status back. It also serves the API and web UI for administration and configuration.
- **Agent**: A component of Woodpecker that executes [pipelines][Pipeline] (specifically one or more [workflows][Workflow]) with a specific backend (e.g. [Docker][], Kubernetes, [local][Local]). It connects to the server via GRPC.
- **CLI**: The Woodpecker command-line interface (CLI) is a terminal tool used to administer the server, to execute pipelines locally for debugging / testing purposes, and to perform tasks like linting pipelines.
-- **Pipeline**: A sequence of [workflows][Workflow] that are executed on the code. [Pipelines][Pipeline] are triggered by events.
-- **Workflow**: A sequence of steps and services that are executed as part of a [pipeline][Pipeline]. Workflows are represented by YAML files. Each [workflow][Workflow] has its own isolated [workspace][Workspace], and often additional resources like a shared network (docker).
+- **[Pipeline][Pipeline]**: A sequence of [workflows][Workflow] that are executed on the code. Pipelines are triggered by events.
+- **[Workflow][Workflow]**: A sequence of steps and services that are executed as part of a [pipeline][Pipeline]. Workflows are represented by YAML files. Each workflow has its own isolated [workspace][Workspace], and often additional resources like a shared network (docker).
- **Steps**: Individual commands, actions or tasks within a [workflow][Workflow].
- **Code**: Refers to the files tracked by the version control system used by the [forge][Forge].
- **Repos**: Short for repositories, these are storage locations where code is stored.
-- **Forge**: The hosting platform or service where the repositories are hosted.
-- **Workspace**: A folder shared between all steps of a [workflow][Workflow] containing the repository and all the generated data from previous steps.
-- **Event**: Triggers the execution of a [pipeline][Pipeline], such as a [forge][Forge] event like `push`, or `manual` triggered manually from the UI.
+- **[Forge][Forge]**: The hosting platform or service where the repositories are hosted.
+- **[Workspace][workspace]**: A folder shared between all steps of a [workflow][Workflow] containing the repository and all the generated data from previous steps.
+- **[Event][Event]**: Triggers the execution of a [pipeline][Pipeline], such as a [forge][Forge] event like `push`, or `manual` triggered manually from the UI.
- **Commit**: A defined state of the code, usually associated with a version control system like Git.
-- **Matrix**: A configuration option that allows the execution of [workflows][Workflow] for each value in the [matrix][Matrix].
+- **[Matrix][Matrix]**: A configuration option that allows the execution of [workflows][Workflow] for each value in the matrix.
- **Service**: A service is a step that is executed from the start of a [workflow][Workflow] until its end. It can be accessed by name via the network from other steps within the same [workflow][Workflow].
-- **Plugins**: [Plugins][Plugin] are extensions that provide pre-defined actions or commands for a step in a [workflow][Workflow]. They can be configured via settings.
+- **[Plugins][Plugin]**: Plugins are extensions that provide pre-defined actions or commands for a step in a [workflow][Workflow]. They can be configured via settings.
- **Container**: A lightweight and isolated environment where commands are executed.
- **YAML File**: A file format used to define and configure [workflows][Workflow].
- **Dependency**: [Workflows][Workflow] can depend on each other, and if possible, they are executed in parallel.
- **Status**: Status refers to the outcome of a step or [workflow][Workflow] after it has been executed, determined by the internal command exit code. At the end of a [workflow][Workflow], its status is sent to the [forge][Forge].
- **Service extension**: Some parts of Woodpecker internal services like secrets storage or config fetcher can be replaced through service extensions.
-## Pipeline events
+## Woodpecker architecture
-- `push`: A push event is triggered when a commit is pushed to a branch.
-- `pull_request`: A pull request event is triggered when a pull request is opened or a new commit is pushed to it.
-- `pull_request_closed`: A pull request closed event is triggered when a pull request is closed or merged.
-- `tag`: A tag event is triggered when a tag is pushed.
-- `release`: A release event is triggered when a release, pre-release or draft is created. (You can apply further filters using [evaluate](../20-workflow-syntax.md#evaluate) with [environment variables](../50-environment.md#built-in-environment-variables).)
-- `manual`: A manual event is triggered when a user manually triggers a pipeline.
-- `cron`: A cron event is triggered when a cron job is executed.
+![Woodpecker architecture](architecture.svg)
+
+## Pipeline, workflow & step
+
+![Relation between pipelines, workflows and steps](pipeline-workflow-step.svg)
## Conventions
@@ -54,6 +44,7 @@ Sometimes there are multiple terms that can be used to describe something. This
+[Event]: ../20-workflow-syntax.md#event
[Pipeline]: ../20-workflow-syntax.md
[Workflow]: ../25-workflows.md
[Forge]: ../../30-administration/11-forges/11-overview.md
diff --git a/docs/docs/20-usage/20-workflow-syntax.md b/docs/docs/20-usage/20-workflow-syntax.md
index 7b966fc48..22de53e7d 100644
--- a/docs/docs/20-usage/20-workflow-syntax.md
+++ b/docs/docs/20-usage/20-workflow-syntax.md
@@ -6,6 +6,11 @@ The Workflow section defines a list of steps to build, test and deploy your code
An exception to this rule are steps with a [`status: [failure]`](#status) condition, which ensures that they are executed in the case of a failed run.
:::
+:::note
+We support most of YAML 1.2, but preserve some behavior from 1.1 for backward compatibility.
+Read more at: [https://github.com/go-yaml/yaml](https://github.com/go-yaml/yaml/tree/v3)
+:::
+
Example steps:
```yaml
@@ -99,7 +104,7 @@ When using the `local` backend, the `image` entry is used to specify the shell,
- go test
- name: publish
-+ image: plugins/docker
++ image: woodpeckerci/plugin-kaniko
repo: foo/bar
services:
@@ -196,7 +201,7 @@ Some of the steps may be allowed to fail without causing the whole workflow and
### `when` - Conditional Execution
-Woodpecker supports defining a list of conditions for a step by using a `when` block. If at least one of the conditions in the `when` block evaluate to true the step is executed, otherwise it is skipped. A condition is evaluated to true if _all_ subconditions are true.
+Woodpecker supports defining a list of conditions for a step by using a `when` block. If at least one of the conditions in the `when` block evaluate to true the step is executed, otherwise it is skipped. A condition is evaluated to true if _all_ sub-conditions are true.
A condition can be a check like:
```diff
@@ -215,7 +220,7 @@ A condition can be a check like:
The `slack` step is executed if one of these conditions is met:
1. The pipeline is executed from a pull request in the repo `test/test`
-2. The pipeline is executed from a push to `maiǹ`
+2. The pipeline is executed from a push to `main`
#### `repo`
@@ -283,7 +288,16 @@ when:
#### `event`
-Available events: `push`, `pull_request`, `pull_request_closed`, `tag`, `release`, `deployment`, `cron`, `manual`
+The available events are:
+
+- `push`: triggered when a commit is pushed to a branch.
+- `pull_request`: triggered when a pull request is opened or a new commit is pushed to it.
+- `pull_request_closed`: triggered when a pull request is closed or merged.
+- `tag`: triggered when a tag is pushed.
+- `release`: triggered when a release, pre-release or draft is created. (You can apply further filters using [evaluate](#evaluate) with [environment variables](./50-environment.md#built-in-environment-variables).)
+- `deployment` (only available for GitHub): triggered when a deployment is created in the repository.
+- `cron`: triggered when a cron job is executed.
+- `manual`: triggered when a user manually triggers a pipeline.
Execute a step if the build event is a `tag`:
@@ -470,7 +484,7 @@ Normally steps of a workflow are executed serially in the order in which they ar
- go build
- name: deploy
- image: plugins/docker
+ image: woodpeckerci/plugin-kaniko
settings:
repo: foo/bar
+ depends_on: [build, test] # deploy will be executed after build and test finished
@@ -518,7 +532,9 @@ For more details check the [services docs](./60-services.md).
## `workspace`
-The workspace defines the shared volume and working directory shared by all workflow steps. The default workspace matches the pattern `/woodpecker/src/github.com/octocat/hello-world`, based on your repository URL.
+The workspace defines the shared volume and working directory shared by all workflow steps.
+The default workspace base is `/woodpecker` and the path is extended with the repository URL (`src/{url-without-schema}`).
+So an example would be `/woodpecker/src/github.com/octocat/hello-world`.
The workspace can be customized using the workspace block in the YAML file:
@@ -535,6 +551,10 @@ The workspace can be customized using the workspace block in the YAML file:
- go test
```
+:::note
+Plugins will always have the workspace base at `/woodpecker`
+:::
+
The base attribute defines a shared base volume available to all steps. This ensures your source code, dependencies and compiled binaries are persisted and shared between steps.
```diff
diff --git a/docs/docs/20-usage/25-workflows.md b/docs/docs/20-usage/25-workflows.md
index 5adc39f85..ef09d485e 100644
--- a/docs/docs/20-usage/25-workflows.md
+++ b/docs/docs/20-usage/25-workflows.md
@@ -23,13 +23,13 @@ If you still need to pass artifacts between the workflows you need use some stor
```bash
.woodpecker/
-├── .build.yaml
-├── .deploy.yaml
-├── .lint.yaml
-└── .test.yaml
+├── build.yaml
+├── deploy.yaml
+├── lint.yaml
+└── test.yaml
```
-```yaml title=".woodpecker/.build.yaml"
+```yaml title=".woodpecker/build.yaml"
steps:
- name: build
image: debian:stable-slim
@@ -38,7 +38,7 @@ steps:
- sleep 5
```
-```yaml title=".woodpecker/.deploy.yaml"
+```yaml title=".woodpecker/deploy.yaml"
steps:
- name: deploy
image: debian:stable-slim
@@ -51,7 +51,7 @@ depends_on:
- test
```
-```yaml title=".woodpecker/.test.yaml"
+```yaml title=".woodpecker/test.yaml"
steps:
- name: test
image: debian:stable-slim
@@ -63,7 +63,7 @@ depends_on:
- build
```
-```yaml title=".woodpecker/.lint.yaml"
+```yaml title=".woodpecker/lint.yaml"
steps:
- name: lint
image: debian:stable-slim
diff --git a/docs/docs/20-usage/40-secrets.md b/docs/docs/20-usage/40-secrets.md
index 1b55d9ce1..aadb7734d 100644
--- a/docs/docs/20-usage/40-secrets.md
+++ b/docs/docs/20-usage/40-secrets.md
@@ -70,9 +70,16 @@ Secrets are not exposed to pull requests by default. You can override this behav
Please be careful when exposing secrets to pull requests. If your repository is open source and accepts pull requests your secrets are not safe. A bad actor can submit a malicious pull request that exposes your secrets.
:::
-## Image filter
+## Plugins filter
-To prevent abusing your secrets from malicious usage, you can limit a secret to a list of images. If enabled they are not available to any other plugin (steps without user-defined commands). If you or an attacker defines explicit commands, the secrets will not be available to the container to prevent leaking them.
+To prevent abusing your secrets from malicious usage, you can limit a secret to a list of plugins. If enabled they are not available to any other plugin (steps without user-defined commands). If you or an attacker defines explicit commands, the secrets will not be available to the container to prevent leaking them.
+
+:::note
+If you specify a tag, the filter will respect it.
+Just make sure you don't specify the same image without one, otherwise it will be ignored again.
+:::
+
+![plugins filter](./secrets-plugins-filter.png)
## Adding Secrets
@@ -105,7 +112,7 @@ Create the secrets and limit to a set of images:
woodpecker-cli secret add \
-repository octocat/hello-world \
+ -image plugins/s3 \
-+ -image peloton/woodpecker-ecs \
++ -image woodpeckerci/plugin-ecs \
-name aws_access_key_id \
-value
```
diff --git a/docs/docs/20-usage/41-registries.md b/docs/docs/20-usage/41-registries.md
index 8508da876..7cbcc3138 100644
--- a/docs/docs/20-usage/41-registries.md
+++ b/docs/docs/20-usage/41-registries.md
@@ -32,8 +32,8 @@ Example registry hostname matching logic:
- Hostname `gcr.io` matches image `gcr.io/foo/bar`
- Hostname `docker.io` matches `golang`
- Hostname `docker.io` matches `library/golang`
-- Hostname `docker.io` matches `bradyrydzewski/golang`
-- Hostname `docker.io` matches `bradyrydzewski/golang:latest`
+- Hostname `docker.io` matches `bradrydzewski/golang`
+- Hostname `docker.io` matches `bradrydzewski/golang:latest`
:::note
The flow above doesn't work in Kubernetes. There is [workaround](../30-administration/22-backends/40-kubernetes.md#images-from-private-registries).
diff --git a/docs/docs/20-usage/45-cron.md b/docs/docs/20-usage/45-cron.md
index 95ee8202e..2cb088122 100644
--- a/docs/docs/20-usage/45-cron.md
+++ b/docs/docs/20-usage/45-cron.md
@@ -23,12 +23,6 @@ To configure cron jobs you need at least push access to the repository.
![cron settings](./cron-settings.png)
- The supported schedule syntax can be found at . If you need general understanding of the cron syntax is a good place to start and experiment.
+ The supported schedule syntax can be found at . If you need general understanding of the cron syntax is a good place to start and experiment.
- Examples: `@every 5m`, `@daily`, `0 30 * * * *` ...
-
- :::info
- Woodpeckers cron syntax starts with seconds instead of minutes as used by most linux cron schedulers.
-
- Example: "At minute 30 every hour" would be `0 30 * * * *` instead of `30 * * * *`
- :::
+ Examples: `@every 5m`, `@daily`, `30 * * * *` ...
diff --git a/docs/docs/20-usage/50-environment.md b/docs/docs/20-usage/50-environment.md
index 299bb8f53..0aa0a988d 100644
--- a/docs/docs/20-usage/50-environment.md
+++ b/docs/docs/20-usage/50-environment.md
@@ -48,97 +48,93 @@ Please note that the environment section is not able to expand environment varia
This is the reference list of all environment variables available to your pipeline containers. These are injected into your pipeline step and plugins containers, at runtime.
-| NAME | Description |
-| -------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
-| `CI` | CI environment name (value: `woodpecker`) |
-| | **Repository** |
-| `CI_REPO` | repository full name `/` |
-| `CI_REPO_OWNER` | repository owner |
-| `CI_REPO_NAME` | repository name |
-| `CI_REPO_REMOTE_ID` | repository remote ID, is the UID it has in the forge |
-| `CI_REPO_SCM` | repository SCM (git) |
-| `CI_REPO_URL` | repository web URL |
-| `CI_REPO_CLONE_URL` | repository clone URL |
-| `CI_REPO_CLONE_SSH_URL` | repository SSH clone URL |
-| `CI_REPO_DEFAULT_BRANCH` | repository default branch (main) |
-| `CI_REPO_PRIVATE` | repository is private |
-| `CI_REPO_TRUSTED` | repository is trusted |
-| | **Current Commit** |
-| `CI_COMMIT_SHA` | commit SHA |
-| `CI_COMMIT_REF` | commit ref |
-| `CI_COMMIT_REFSPEC` | commit ref spec |
-| `CI_COMMIT_BRANCH` | commit branch (equals target branch for pull requests) |
-| `CI_COMMIT_SOURCE_BRANCH` | commit source branch (empty if event is not `pull_request` or `pull_request_closed`) |
-| `CI_COMMIT_TARGET_BRANCH` | commit target branch (empty if event is not `pull_request` or `pull_request_closed`) |
-| `CI_COMMIT_TAG` | commit tag name (empty if event is not `tag`) |
-| `CI_COMMIT_PULL_REQUEST` | commit pull request number (empty if event is not `pull_request` or `pull_request_closed`) |
-| `CI_COMMIT_PULL_REQUEST_LABELS` | labels assigned to pull request (empty if event is not `pull_request` or `pull_request_closed`) |
-| `CI_COMMIT_MESSAGE` | commit message |
-| `CI_COMMIT_AUTHOR` | commit author username |
-| `CI_COMMIT_AUTHOR_EMAIL` | commit author email address |
-| `CI_COMMIT_AUTHOR_AVATAR` | commit author avatar |
-| `CI_COMMIT_PRERELEASE` | release is a pre-release (empty if event is not `release`) |
-| | **Current pipeline** |
-| `CI_PIPELINE_NUMBER` | pipeline number |
-| `CI_PIPELINE_PARENT` | number of parent pipeline |
-| `CI_PIPELINE_EVENT` | pipeline event (see [pipeline events](../20-usage/15-terminology/index.md#pipeline-events)) |
-| `CI_PIPELINE_URL` | link to the web UI for the pipeline |
-| `CI_PIPELINE_FORGE_URL` | link to the forge's web UI for the commit(s) or tag that triggered the pipeline |
-| `CI_PIPELINE_DEPLOY_TARGET` | pipeline deploy target for `deployment` events (i.e. production) |
-| `CI_PIPELINE_DEPLOY_TASK` | pipeline deploy task for `deployment` events (i.e. migration) |
-| `CI_PIPELINE_STATUS` | pipeline status (success, failure) |
-| `CI_PIPELINE_CREATED` | pipeline created UNIX timestamp |
-| `CI_PIPELINE_STARTED` | pipeline started UNIX timestamp |
-| `CI_PIPELINE_FINISHED` | pipeline finished UNIX timestamp |
-| `CI_PIPELINE_FILES` | changed files (empty if event is not `push` or `pull_request`), it is undefined if more than 500 files are touched |
-| | **Current workflow** |
-| `CI_WORKFLOW_NAME` | workflow name |
-| | **Current step** |
-| `CI_STEP_NAME` | step name |
-| `CI_STEP_NUMBER` | step number |
-| `CI_STEP_STATUS` | step status (success, failure) |
-| `CI_STEP_STARTED` | step started UNIX timestamp |
-| `CI_STEP_FINISHED` | step finished UNIX timestamp |
-| `CI_STEP_URL` | URL to step in UI |
-| | **Previous commit** |
-| `CI_PREV_COMMIT_SHA` | previous commit SHA |
-| `CI_PREV_COMMIT_REF` | previous commit ref |
-| `CI_PREV_COMMIT_REFSPEC` | previous commit ref spec |
-| `CI_PREV_COMMIT_BRANCH` | previous commit branch |
-| `CI_PREV_COMMIT_SOURCE_BRANCH` | previous commit source branch |
-| `CI_PREV_COMMIT_TARGET_BRANCH` | previous commit target branch |
-| `CI_PREV_COMMIT_URL` | previous commit link in forge |
-| `CI_PREV_COMMIT_MESSAGE` | previous commit message |
-| `CI_PREV_COMMIT_AUTHOR` | previous commit author username |
-| `CI_PREV_COMMIT_AUTHOR_EMAIL` | previous commit author email address |
-| `CI_PREV_COMMIT_AUTHOR_AVATAR` | previous commit author avatar |
-| | **Previous pipeline** |
-| `CI_PREV_PIPELINE_NUMBER` | previous pipeline number |
-| `CI_PREV_PIPELINE_PARENT` | previous pipeline number of parent pipeline |
-| `CI_PREV_PIPELINE_EVENT` | previous pipeline event (see [pipeline events](../20-usage/15-terminology/index.md#pipeline-events)) |
-| `CI_PREV_PIPELINE_URL` | previous pipeline link in CI |
-| `CI_PREV_PIPELINE_FORGE_URL` | previous pipeline link to event in forge |
-| `CI_PREV_PIPELINE_DEPLOY_TARGET` | previous pipeline deploy target for `deployment` events (ie production) |
-| `CI_PREV_PIPELINE_DEPLOY_TASK` | previous pipeline deploy task for `deployment` events (ie migration) |
-| `CI_PREV_PIPELINE_STATUS` | previous pipeline status (success, failure) |
-| `CI_PREV_PIPELINE_CREATED` | previous pipeline created UNIX timestamp |
-| `CI_PREV_PIPELINE_STARTED` | previous pipeline started UNIX timestamp |
-| `CI_PREV_PIPELINE_FINISHED` | previous pipeline finished UNIX timestamp |
-| | |
-| `CI_WORKSPACE` | Path of the workspace where source code gets cloned to |
-| | **System** |
-| `CI_SYSTEM_NAME` | name of the CI system: `woodpecker` |
-| `CI_SYSTEM_URL` | link to CI system |
-| `CI_SYSTEM_HOST` | hostname of CI server |
-| `CI_SYSTEM_VERSION` | version of the server |
-| | **Forge** |
-| `CI_FORGE_TYPE` | name of forge (gitea, github, ...) |
-| `CI_FORGE_URL` | root URL of configured forge |
-| | **Internal** - Please don't use! |
-| `CI_SCRIPT` | Internal script path. Used to call pipeline step commands. |
-| `CI_NETRC_USERNAME` | Credentials for private repos to be able to clone data. (Only available for specific images) |
-| `CI_NETRC_PASSWORD` | Credentials for private repos to be able to clone data. (Only available for specific images) |
-| `CI_NETRC_MACHINE` | Credentials for private repos to be able to clone data. (Only available for specific images) |
+| NAME | Description | Example |
+| -------------------------------- | ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ |
+| `CI` | CI environment name | `woodpecker` |
+| | **Repository** | |
+| `CI_REPO` | repository full name `/` | `john-doe/my-repo` |
+| `CI_REPO_OWNER` | repository owner | `john-doe` |
+| `CI_REPO_NAME` | repository name | `my-repo` |
+| `CI_REPO_REMOTE_ID` | repository remote ID, is the UID it has in the forge | `82` |
+| `CI_REPO_SCM` | repository SCM | `git` |
+| `CI_REPO_URL` | repository web URL | `https://git.example.com/john-doe/my-repo` |
+| `CI_REPO_CLONE_URL` | repository clone URL | `https://git.example.com/john-doe/my-repo.git` |
+| `CI_REPO_CLONE_SSH_URL` | repository SSH clone URL | `git@git.example.com:john-doe/my-repo.git` |
+| `CI_REPO_DEFAULT_BRANCH` | repository default branch | `main` |
+| `CI_REPO_PRIVATE` | repository is private | `true` |
+| `CI_REPO_TRUSTED` | repository is trusted | `false` |
+| | **Current Commit** | |
+| `CI_COMMIT_SHA` | commit SHA | `eba09b46064473a1d345da7abf28b477468e8dbd` |
+| `CI_COMMIT_REF` | commit ref | `refs/heads/main` |
+| `CI_COMMIT_REFSPEC` | commit ref spec | `issue-branch:main` |
+| `CI_COMMIT_BRANCH` | commit branch (equals target branch for pull requests) | `main` |
+| `CI_COMMIT_SOURCE_BRANCH` | commit source branch (empty if event is not `pull_request` or `pull_request_closed`) | `issue-branch` |
+| `CI_COMMIT_TARGET_BRANCH` | commit target branch (empty if event is not `pull_request` or `pull_request_closed`) | `main` |
+| `CI_COMMIT_TAG` | commit tag name (empty if event is not `tag`) | `v1.10.3` |
+| `CI_COMMIT_PULL_REQUEST` | commit pull request number (empty if event is not `pull_request` or `pull_request_closed`) | `1` |
+| `CI_COMMIT_PULL_REQUEST_LABELS` | labels assigned to pull request (empty if event is not `pull_request` or `pull_request_closed`) | `server` |
+| `CI_COMMIT_MESSAGE` | commit message | `Initial commit` |
+| `CI_COMMIT_AUTHOR` | commit author username | `john-doe` |
+| `CI_COMMIT_AUTHOR_EMAIL` | commit author email address | `john-doe@example.com` |
+| `CI_COMMIT_AUTHOR_AVATAR` | commit author avatar | `https://git.example.com/avatars/5dcbcadbce6f87f8abef` |
+| `CI_COMMIT_PRERELEASE` | release is a pre-release (empty if event is not `release`) | `false` |
+| | **Current pipeline** | |
+| `CI_PIPELINE_NUMBER` | pipeline number | `8` |
+| `CI_PIPELINE_PARENT` | number of parent pipeline | `0` |
+| `CI_PIPELINE_EVENT` | pipeline event (see [`event`](../20-usage/20-workflow-syntax.md#event)) | `push`, `pull_request`, `pull_request_closed`, `tag`, `release`, `manual`, `cron` |
+| `CI_PIPELINE_URL` | link to the web UI for the pipeline | `https://ci.example.com/repos/7/pipeline/8` |
+| `CI_PIPELINE_FORGE_URL` | link to the forge's web UI for the commit(s) or tag that triggered the pipeline | `https://git.example.com/john-doe/my-repo/commit/eba09b46064473a1d345da7abf28b477468e8dbd` |
+| `CI_PIPELINE_DEPLOY_TARGET` | pipeline deploy target for `deployment` events | `production` |
+| `CI_PIPELINE_DEPLOY_TASK` | pipeline deploy task for `deployment` events | `migration` |
+| `CI_PIPELINE_CREATED` | pipeline created UNIX timestamp | `1722617519` |
+| `CI_PIPELINE_STARTED` | pipeline started UNIX timestamp | `1722617519` |
+| `CI_PIPELINE_FILES` | changed files (empty if event is not `push` or `pull_request`), it is undefined if more than 500 files are touched | `[]`, `[".woodpecker.yml","README.md"]` |
+| | **Current workflow** | |
+| `CI_WORKFLOW_NAME` | workflow name | `release` |
+| | **Current step** | |
+| `CI_STEP_NAME` | step name | `build package` |
+| `CI_STEP_NUMBER` | step number | `0` |
+| `CI_STEP_STARTED` | step started UNIX timestamp | `1722617519` |
+| `CI_STEP_URL` | URL to step in UI | `https://ci.example.com/repos/7/pipeline/8` |
+| | **Previous commit** | |
+| `CI_PREV_COMMIT_SHA` | previous commit SHA | `15784117e4e103f36cba75a9e29da48046eb82c4` |
+| `CI_PREV_COMMIT_REF` | previous commit ref | `refs/heads/main` |
+| `CI_PREV_COMMIT_REFSPEC` | previous commit ref spec | `issue-branch:main` |
+| `CI_PREV_COMMIT_BRANCH` | previous commit branch | `main` |
+| `CI_PREV_COMMIT_SOURCE_BRANCH` | previous commit source branch | `issue-branch` |
+| `CI_PREV_COMMIT_TARGET_BRANCH` | previous commit target branch | `main` |
+| `CI_PREV_COMMIT_URL` | previous commit link in forge | `https://git.example.com/john-doe/my-repo/commit/15784117e4e103f36cba75a9e29da48046eb82c4` |
+| `CI_PREV_COMMIT_MESSAGE` | previous commit message | `test` |
+| `CI_PREV_COMMIT_AUTHOR` | previous commit author username | `john-doe` |
+| `CI_PREV_COMMIT_AUTHOR_EMAIL` | previous commit author email address | `john-doe@example.com` |
+| `CI_PREV_COMMIT_AUTHOR_AVATAR` | previous commit author avatar | `https://git.example.com/avatars/12` |
+| | **Previous pipeline** | |
+| `CI_PREV_PIPELINE_NUMBER` | previous pipeline number | `7` |
+| `CI_PREV_PIPELINE_PARENT` | previous pipeline number of parent pipeline | `0` |
+| `CI_PREV_PIPELINE_EVENT` | previous pipeline event (see [`event`](../20-usage/20-workflow-syntax.md#event)) | `push`, `pull_request`, `pull_request_closed`, `tag`, `release`, `manual`, `cron` |
+| `CI_PREV_PIPELINE_URL` | previous pipeline link in CI | `https://ci.example.com/repos/7/pipeline/7` |
+| `CI_PREV_PIPELINE_FORGE_URL` | previous pipeline link to event in forge | `https://git.example.com/john-doe/my-repo/commit/15784117e4e103f36cba75a9e29da48046eb82c4` |
+| `CI_PREV_PIPELINE_DEPLOY_TARGET` | previous pipeline deploy target for `deployment` events | `production` |
+| `CI_PREV_PIPELINE_DEPLOY_TASK` | previous pipeline deploy task for `deployment` events | `migration` |
+| `CI_PREV_PIPELINE_STATUS` | previous pipeline status | `success`, `failure` |
+| `CI_PREV_PIPELINE_CREATED` | previous pipeline created UNIX timestamp | `1722610173` |
+| `CI_PREV_PIPELINE_STARTED` | previous pipeline started UNIX timestamp | `1722610173` |
+| `CI_PREV_PIPELINE_FINISHED` | previous pipeline finished UNIX timestamp | `1722610383` |
+| | | |
+| `CI_WORKSPACE` | Path of the workspace where source code gets cloned to | `/woodpecker/src/git.example.com/john-doe/my-repo` |
+| | **System** | |
+| `CI_SYSTEM_NAME` | name of the CI system | `woodpecker` |
+| `CI_SYSTEM_URL` | link to CI system | `https://ci.example.com` |
+| `CI_SYSTEM_HOST` | hostname of CI server | `ci.example.com` |
+| `CI_SYSTEM_VERSION` | version of the server | `2.7.0` |
+| | **Forge** | |
+| `CI_FORGE_TYPE` | name of forge | `bitbucket` , `bitbucket_dc` , `forgejo` , `gitea` , `github` , `gitlab` |
+| `CI_FORGE_URL` | root URL of configured forge | `https://git.example.com` |
+| | **Internal** - Please don't use! | |
+| `CI_SCRIPT` | Internal script path. Used to call pipeline step commands. | |
+| `CI_NETRC_USERNAME` | Credentials for private repos to be able to clone data. (Only available for specific images) | |
+| `CI_NETRC_PASSWORD` | Credentials for private repos to be able to clone data. (Only available for specific images) | |
+| `CI_NETRC_MACHINE` | Credentials for private repos to be able to clone data. (Only available for specific images) | |
## Global environment variables
@@ -172,7 +168,7 @@ Example commit substitution:
```diff
steps:
- name: docker
- image: plugins/docker
+ image: woodpeckerci/plugin-kaniko
settings:
+ tags: ${CI_COMMIT_SHA}
```
@@ -182,7 +178,7 @@ Example tag substitution:
```diff
steps:
- name: docker
- image: plugins/docker
+ image: woodpeckerci/plugin-kaniko
settings:
+ tags: ${CI_COMMIT_TAG}
```
@@ -210,7 +206,7 @@ Example variable substitution with substring:
```diff
steps:
- name: docker
- image: plugins/docker
+ image: woodpeckerci/plugin-kaniko
settings:
+ tags: ${CI_COMMIT_SHA:0:8}
```
@@ -220,7 +216,7 @@ Example variable substitution strips `v` prefix from `v.1.0.0`:
```diff
steps:
- name: docker
- image: plugins/docker
+ image: woodpeckerci/plugin-kaniko
settings:
+ tags: ${CI_COMMIT_TAG##v}
```
diff --git a/docs/docs/20-usage/51-plugins/20-creating-plugins.md b/docs/docs/20-usage/51-plugins/20-creating-plugins.md
index 8a0ea5920..c09a6226d 100644
--- a/docs/docs/20-usage/51-plugins/20-creating-plugins.md
+++ b/docs/docs/20-usage/51-plugins/20-creating-plugins.md
@@ -10,7 +10,7 @@ These are passed to your plugin as uppercase env vars with a `PLUGIN_` prefix.
Using a setting like `url` results in an env var named `PLUGIN_URL`.
Characters like `-` are converted to an underscore (`_`). `some_String` gets `PLUGIN_SOME_STRING`.
-CamelCase is not respected, `anInt` get `PLUGIN_ANINT`.
+CamelCase is not respected, `anInt` get `PLUGIN_ANINT`.
### Basic settings
diff --git a/docs/docs/20-usage/51-plugins/51-overview.md b/docs/docs/20-usage/51-plugins/51-overview.md
index ab8db3df3..1599b8cca 100644
--- a/docs/docs/20-usage/51-plugins/51-overview.md
+++ b/docs/docs/20-usage/51-plugins/51-overview.md
@@ -1,9 +1,28 @@
# Plugins
-Plugins are pipeline steps that perform pre-defined tasks and are configured as steps in your pipeline. Plugins can be used to deploy code, publish artifacts, send notification, and more.
+Plugins are pipeline steps that perform pre-defined tasks and are configured as steps in your pipeline.
+Plugins can be used to deploy code, publish artifacts, send notification, and more.
They are automatically pulled from the default container registry the agent's have configured.
+```dockerfile title="Dockerfile"
+FROM cloud/kubectl
+COPY deploy /usr/local/deploy
+ENTRYPOINT ["/usr/local/deploy"]
+```
+
+```bash title="deploy"
+kubectl apply -f $PLUGIN_TEMPLATE
+```
+
+```yaml title=".woodpecker.yaml"
+steps:
+ - name: deploy-to-k8s
+ image: cloud/my-k8s-plugin
+ settings:
+ template: config/k8s/service.yaml
+```
+
Example pipeline using the Docker and Slack plugins:
```yaml
@@ -15,7 +34,7 @@ steps:
- go test
- name: publish
- image: plugins/docker
+ image: woodpeckerci/plugin-kaniko
settings:
repo: foo/bar
tags: latest
@@ -29,6 +48,12 @@ steps:
## Plugin Isolation
Plugins are just pipeline steps. They share the build workspace, mounted as a volume, and therefore have access to your source tree.
+While normal steps are all about arbitrary code execution, plugins should only allow the functions intended by the plugin author.
+
+That's why there are a few limitations. The workspace base is always mounted at `/woodpecker`, but the working directory is dynamically
+adjusted accordingly, as user of a plugin you should not have to care about this. Also, you cannot use the plugin together with `commands`
+or `entrypoint` which will fail. Using `secrets` or `environment` is possible, but in this case, the plugin is internally not treated as plugin
+anymore. The container then cannot access secrets with plugin filter anymore and the containers won't be privileged without explicit definition.
## Finding Plugins
diff --git a/docs/docs/20-usage/60-services.md b/docs/docs/20-usage/60-services.md
index 4992e5dc2..14262855c 100644
--- a/docs/docs/20-usage/60-services.md
+++ b/docs/docs/20-usage/60-services.md
@@ -110,5 +110,5 @@ steps:
commands:
- ( apt update && apt dist-upgrade -y && apt install -y mysql-client 2>&1 )> /dev/null
- sleep 30s # need to wait for mysql-server init
- - echo 'SHOW VARIABLES LIKE "version"' | mysql -uroot -hdatabase test -pexample
+ - echo 'SHOW VARIABLES LIKE "version"' | mysql -u root -h database test -p example
```
diff --git a/docs/docs/20-usage/90-advanced-usage.md b/docs/docs/20-usage/90-advanced-usage.md
index 065386fdf..910646629 100644
--- a/docs/docs/20-usage/90-advanced-usage.md
+++ b/docs/docs/20-usage/90-advanced-usage.md
@@ -97,7 +97,7 @@ steps:
### References
- [Official YAML specification](https://yaml.org/spec/1.2.2/#3222-anchors-and-aliases)
-- [YAML Cheatsheet](https://learnxinyminutes.com/docs/yaml)
+- [YAML cheat sheet](https://learnxinyminutes.com/docs/yaml)
## Persisting environment data between steps
diff --git a/docs/docs/20-usage/pipeline.png b/docs/docs/20-usage/pipeline.png
new file mode 100644
index 000000000..dd4063c9a
Binary files /dev/null and b/docs/docs/20-usage/pipeline.png differ
diff --git a/docs/docs/20-usage/repo-list.png b/docs/docs/20-usage/repo-list.png
deleted file mode 100644
index b47380087..000000000
Binary files a/docs/docs/20-usage/repo-list.png and /dev/null differ
diff --git a/docs/docs/20-usage/repo-new.png b/docs/docs/20-usage/repo-new.png
new file mode 100644
index 000000000..e6136bc12
Binary files /dev/null and b/docs/docs/20-usage/repo-new.png differ
diff --git a/docs/docs/20-usage/secrets-plugins-filter.png b/docs/docs/20-usage/secrets-plugins-filter.png
new file mode 100644
index 000000000..460d852fb
Binary files /dev/null and b/docs/docs/20-usage/secrets-plugins-filter.png differ
diff --git a/docs/docs/30-administration/00-deployment/00-overview.md b/docs/docs/30-administration/00-deployment/00-overview.md
deleted file mode 100644
index d17ca3501..000000000
--- a/docs/docs/30-administration/00-deployment/00-overview.md
+++ /dev/null
@@ -1,77 +0,0 @@
-# Deployment
-
-A Woodpecker deployment consists of two parts:
-
-- A server which is the heart of Woodpecker and ships the web interface.
-- Next to one server, you can deploy any number of agents which will run the pipelines.
-
-Each agent is able to process one pipeline step by default.
-If you have four agents installed and connected to the Woodpecker server, your system will process four workflows in parallel.
-
-:::tip
-You can add more agents to increase the number of parallel workflows or set the agent's `WOODPECKER_MAX_WORKFLOWS=1` environment variable to increase the number of parallel workflows for that agent.
-:::
-
-## Which version of Woodpecker should I use?
-
-Woodpecker is having two different kinds of releases: **stable** and **next**.
-
-Find more information about the different versions [here](/versions).
-
-## Hardware Requirements
-
-Below are minimal resources requirements for Woodpecker components itself:
-
-| Component | Memory | CPU |
-| --------- | ------ | --- |
-| Server | 200 MB | 1 |
-| Agent | 32 MB | 1 |
-
-Note, that those values do not include the operating system or workload (pipelines execution) resources consumption.
-
-In addition you need at least some kind of database which requires additional resources depending on the selected database system.
-
-## Installation
-
-You can install Woodpecker on multiple ways:
-
-- Using [docker-compose](./10-docker-compose.md) with the official [container images](./10-docker-compose.md#docker-images)
-- Using [Kubernetes](./20-kubernetes.md) via the Woodpecker Helm chart
-- Using binaries, DEBs or RPMs you can download from [latest release](https://github.com/woodpecker-ci/woodpecker/releases/latest)
-
-## Authentication
-
-Authentication is done using OAuth and is delegated to your forge which is configured using environment variables.
-
-See the complete reference for all supported forges [here](../11-forges/11-overview.md).
-
-## Database
-
-By default Woodpecker uses a SQLite database which requires zero installation or configuration. See the [database settings](../30-database.md) page to further configure it or use MySQL or Postgres.
-
-## SSL
-
-Woodpecker supports SSL configuration by using Let's encrypt or by using own certificates. See the [SSL guide](../60-ssl.md). You can also put it behind a [reverse proxy](#behind-a-proxy)
-
-## Metrics
-
-A [Prometheus endpoint](../90-prometheus.md) is exposed.
-
-## Behind a proxy
-
-See the [proxy guide](../70-proxy.md) if you want to see a setup behind Apache, Nginx, Caddy or ngrok.
-
-In the case you need to use Woodpecker with a URL path prefix (like: ), add the root path to [`WOODPECKER_HOST`](../10-server-config.md#woodpecker_host).
-
-## Third-party installation methods
-
-:::info
-These installation methods are not officially supported. If you experience issues with them, please open issues in the specific repositories.
-:::
-
-- [Using NixOS](./30-nixos.md) via the [NixOS module](https://search.nixos.org/options?channel=unstable&size=200&sort=relevance&query=woodpecker)
-- [On Alpine Edge](https://pkgs.alpinelinux.org/packages?name=woodpecker&branch=edge&repo=&arch=&maintainer=)
-- [On Arch Linux](https://archlinux.org/packages/?q=woodpecker)
-- [On openSUSE](https://software.opensuse.org/package/woodpecker)
-- [Using YunoHost](https://apps.yunohost.org/app/woodpecker)
-- [On Cloudron](https://www.cloudron.io/store/org.woodpecker_ci.cloudronapp.html)
diff --git a/docs/docs/30-administration/00-getting-started.md b/docs/docs/30-administration/00-getting-started.md
new file mode 100644
index 000000000..e5d573e56
--- /dev/null
+++ b/docs/docs/30-administration/00-getting-started.md
@@ -0,0 +1,59 @@
+# Getting started
+
+A Woodpecker deployment consists of two parts:
+
+- A server which is the heart of Woodpecker and ships the web interface.
+- Next to one server, you can deploy any number of agents which will run the pipelines.
+
+Each agent is able to process one [workflow](../20-usage/15-terminology/index.md) by default. If you have 4 agents installed and connected to the Woodpecker server, your system will process four workflows (not pipelines) in parallel.
+
+:::tip
+You can add more agents to increase the number of parallel workflows or set the agent's `WOODPECKER_MAX_WORKFLOWS=1` environment variable to increase the number of parallel workflows per agent.
+:::
+
+## Which version of Woodpecker should I use?
+
+Woodpecker is having two different kinds of releases: **stable** and **next**.
+
+Find more information about the different versions [here](/versions).
+
+## Hardware Requirements
+
+Below are minimal resources requirements for Woodpecker components itself:
+
+| Component | Memory | CPU |
+| --------- | ------ | --- |
+| Server | 200 MB | 1 |
+| Agent | 32 MB | 1 |
+
+Note, that those values do not include the operating system or workload (pipelines execution) resource consumption.
+
+In addition you need at least some kind of database which requires additional resources depending on the selected database system.
+
+## Installation
+
+You can install Woodpecker on multiple ways. If you are not sure which one to choose, we recommend using the [docker compose](./05-deployment-methods/10-docker-compose.md) method for the beginning:
+
+- Using [docker compose](./05-deployment-methods/10-docker-compose.md) with the official [container images](./05-deployment-methods/10-docker-compose.md#docker-images)
+- Using [Kubernetes](./05-deployment-methods/20-kubernetes.md) via the Woodpecker Helm chart
+- Using binaries, DEBs or RPMs you can download from [latest release](https://github.com/woodpecker-ci/woodpecker/releases/latest)
+- Or using a [third-party installation method](./05-deployment-methods/30-third-party.md)
+
+## Database
+
+By default Woodpecker uses a SQLite database which requires zero installation or configuration. See the [database settings](./10-database.md) page if you want to use a different database system like MySQL or PostgreSQL.
+
+## Forge
+
+What would be a CI/CD system without any code? By connecting Woodpecker to your [forge](../20-usage/15-terminology/index.md) like GitHub or Gitea you can start running pipelines on events like pushes or pull requests. Woodpecker will also use your forge for authentication and to report back the status of your pipelines. See the [forge settings](./11-forges/11-overview.md) to connect it to Woodpecker.
+
+## Configuration
+
+Check the [server configuration](./10-server-config.md) and [agent configuration](./15-agent-config.md) pages to see if you need to adjust any additional parts and after that you should be ready to start with [your first pipeline](../20-usage/10-intro.md).
+
+## Agent
+
+The agent is the worker which executes the [workflows](../20-usage/15-terminology/index.md).
+Woodpecker agents can execute work using a [backend](../20-usage/15-terminology/index.md) like [docker](./22-backends/10-docker.md) or [kubernetes](./22-backends/40-kubernetes.md).
+By default if you choose to deploy an agent using [docker compose](./05-deployment-methods/10-docker-compose.md) the agent simply use docker for the backend as well.
+So nothing to worry about here. If you still prefer to adjust the agent to your needs, check the [agent configuration](./15-agent-config.md) page.
diff --git a/docs/docs/30-administration/00-deployment/10-docker-compose.md b/docs/docs/30-administration/05-deployment-methods/10-docker-compose.md
similarity index 89%
rename from docs/docs/30-administration/00-deployment/10-docker-compose.md
rename to docs/docs/30-administration/05-deployment-methods/10-docker-compose.md
index a9c2bb6ab..161e75bd8 100644
--- a/docs/docs/30-administration/00-deployment/10-docker-compose.md
+++ b/docs/docs/30-administration/05-deployment-methods/10-docker-compose.md
@@ -1,12 +1,10 @@
-# docker-compose
+# docker compose
-The below [docker-compose](https://docs.docker.com/compose/) configuration can be used to start a Woodpecker server with a single agent.
+The below [docker compose](https://docs.docker.com/compose/) configuration can be used to start a Woodpecker server with a single agent.
-It relies on a number of environment variables that you must set before running `docker-compose up`. The variables are described below.
+It relies on a number of environment variables that you must set before running `docker compose up`. The variables are described below.
```yaml title="docker-compose.yaml"
-version: '3'
-
services:
woodpecker-server:
image: woodpeckerci/woodpecker-server:latest
@@ -43,8 +41,6 @@ volumes:
Woodpecker needs to know its own address. You must therefore provide the public address of it in `://` format. Please omit trailing slashes:
```diff title="docker-compose.yaml"
- version: '3'
-
services:
woodpecker-server:
[...]
@@ -57,7 +53,6 @@ Woodpecker can also have its port's configured. It uses a separate port for gRPC
They can be configured with `*_ADDR` variables:
```diff title="docker-compose.yaml"
- version: '3'
services:
woodpecker-server:
[...]
@@ -67,10 +62,9 @@ They can be configured with `*_ADDR` variables:
+ - WOODPECKER_SERVER_ADDR=${WOODPECKER_HTTP_ADDR}
```
-Reverse proxying can also be [configured for gRPC](../70-proxy.md#caddy). If the agents are connecting over the internet, it should also be SSL encrypted. The agent then needs to be configured to be secure:
+Reverse proxying can also be [configured for gRPC](../40-advanced/10-proxy.md#caddy). If the agents are connecting over the internet, it should also be SSL encrypted. The agent then needs to be configured to be secure:
```diff title="docker-compose.yaml"
- version: '3'
services:
woodpecker-server:
[...]
@@ -83,8 +77,6 @@ Reverse proxying can also be [configured for gRPC](../70-proxy.md#caddy). If the
As agents run pipeline steps as docker containers they require access to the host machine's Docker daemon:
```diff title="docker-compose.yaml"
- version: '3'
-
services:
[...]
woodpecker-agent:
@@ -96,8 +88,6 @@ As agents run pipeline steps as docker containers they require access to the hos
Agents require the server address for agent-to-server communication. The agent connects to the server's gRPC port:
```diff title="docker-compose.yaml"
- version: '3'
-
services:
woodpecker-agent:
[...]
@@ -108,8 +98,6 @@ Agents require the server address for agent-to-server communication. The agent c
The server and agents use a shared secret to authenticate communication. This should be a random string of your choosing and should be kept private. You can generate such string with `openssl rand -hex 32`:
```diff title="docker-compose.yaml"
- version: '3'
-
services:
woodpecker-server:
[...]
diff --git a/docs/versioned_docs/version-2.4/30-administration/00-deployment/20-kubernetes.md b/docs/docs/30-administration/05-deployment-methods/20-kubernetes.md
similarity index 84%
rename from docs/versioned_docs/version-2.4/30-administration/00-deployment/20-kubernetes.md
rename to docs/docs/30-administration/05-deployment-methods/20-kubernetes.md
index f931c3e78..a60c32684 100644
--- a/docs/versioned_docs/version-2.4/30-administration/00-deployment/20-kubernetes.md
+++ b/docs/docs/30-administration/05-deployment-methods/20-kubernetes.md
@@ -3,7 +3,7 @@
We recommended to deploy Woodpecker using the [Woodpecker helm chart](https://github.com/woodpecker-ci/helm).
Have a look at the [`values.yaml`](https://github.com/woodpecker-ci/helm/blob/main/charts/woodpecker/values.yaml) config files for all available settings.
-The chart contains two subcharts, `server` and `agent` which are automatically configured as needed.
+The chart contains two sub-charts, `server` and `agent` which are automatically configured as needed.
The chart started off with two independent charts but was merged into one to simplify the deployment at start of 2023.
A couple of backend-specific config env vars exists which are described in the [kubernetes backend docs](../22-backends/40-kubernetes.md).
diff --git a/docs/docs/30-administration/05-deployment-methods/30-third-party.md b/docs/docs/30-administration/05-deployment-methods/30-third-party.md
new file mode 100644
index 000000000..8eabded39
--- /dev/null
+++ b/docs/docs/30-administration/05-deployment-methods/30-third-party.md
@@ -0,0 +1,12 @@
+# Distribution packages
+
+:::info
+Woodpecker itself is not responsible for creating these packages. Please reach out to the people responsible for packaging Woodpecker for the individual distributions.
+:::
+
+- [NixOS](./40-nixos.md) via the [NixOS module](https://search.nixos.org/options?channel=unstable&size=200&sort=relevance&query=woodpecker)
+- [Alpine (Edge)](https://pkgs.alpinelinux.org/packages?name=woodpecker&branch=edge&repo=&arch=&maintainer=)
+- [Arch Linux](https://archlinux.org/packages/?q=woodpecker)
+- [openSUSE](https://software.opensuse.org/package/woodpecker)
+- [YunoHost](https://apps.yunohost.org/app/woodpecker)
+- [Cloudron](https://www.cloudron.io/store/org.woodpecker_ci.cloudronapp.html)
diff --git a/docs/versioned_docs/version-2.4/30-administration/00-deployment/30-nixos.md b/docs/docs/30-administration/05-deployment-methods/40-nixos.md
similarity index 94%
rename from docs/versioned_docs/version-2.4/30-administration/00-deployment/30-nixos.md
rename to docs/docs/30-administration/05-deployment-methods/40-nixos.md
index 148fbd581..b599b7021 100644
--- a/docs/versioned_docs/version-2.4/30-administration/00-deployment/30-nixos.md
+++ b/docs/docs/30-administration/05-deployment-methods/40-nixos.md
@@ -1,7 +1,7 @@
# NixOS
:::info
-Note that this module is not maintained by the woodpecker-developers.
+Note that this module is not maintained by the Woodpecker developers.
If you experience issues please open a bug report in the [nixpkgs repo](https://github.com/NixOS/nixpkgs/issues/new/choose) where the module is maintained.
:::
@@ -10,6 +10,8 @@ In practice, the settings are specified declaratively in the NixOS configuration
## General Configuration
+
+
```nix
{ config
, ...
@@ -85,4 +87,4 @@ All configuration options can be found via [NixOS Search](https://search.nixos.o
## Tips and tricks
-There are some resources on how to utilize Woodpecker more effectively with NixOS on the [Awesome Woodpecker](../../92-awesome.md) page, like using the runners nix-store in the pipeline
+There are some resources on how to utilize Woodpecker more effectively with NixOS on the [Awesome Woodpecker](../../92-awesome.md) page, like using the runners nix-store in the pipeline.
diff --git a/docs/docs/30-administration/05-deployment-methods/_category_.yaml b/docs/docs/30-administration/05-deployment-methods/_category_.yaml
new file mode 100644
index 000000000..3907838b0
--- /dev/null
+++ b/docs/docs/30-administration/05-deployment-methods/_category_.yaml
@@ -0,0 +1,3 @@
+label: 'Deployment methods'
+collapsible: true
+collapsed: true
diff --git a/docs/versioned_docs/version-2.4/30-administration/30-database.md b/docs/docs/30-administration/10-database.md
similarity index 99%
rename from docs/versioned_docs/version-2.4/30-administration/30-database.md
rename to docs/docs/30-administration/10-database.md
index e3e33ba7d..b1b5aa688 100644
--- a/docs/versioned_docs/version-2.4/30-administration/30-database.md
+++ b/docs/docs/30-administration/10-database.md
@@ -7,8 +7,6 @@ The default database engine of Woodpecker is an embedded SQLite database which r
By default Woodpecker uses a SQLite database stored under `/var/lib/woodpecker/`. If using containers, you can mount a [data volume](https://docs.docker.com/storage/volumes/#create-and-manage-volumes) to persist the SQLite database.
```diff title="docker-compose.yaml"
- version: '3'
-
services:
woodpecker-server:
[...]
diff --git a/docs/docs/30-administration/10-server-config.md b/docs/docs/30-administration/10-server-config.md
index 5be1feed7..02fde63a0 100644
--- a/docs/docs/30-administration/10-server-config.md
+++ b/docs/docs/30-administration/10-server-config.md
@@ -26,14 +26,14 @@ You can **also restrict** registration, by keep registration closed and:
```ini
WOODPECKER_OPEN=false
-WOODPECKER_ADMIN=johnsmith,janedoe
+WOODPECKER_ADMIN=john.smith,jane_doe
```
### Only allow registration of users, who are members of approved organizations
```ini
WOODPECKER_OPEN=true
-WOODPECKER_ORGS=dolores,dogpatch
+WOODPECKER_ORGS=dolores,dog-patch
```
## Administrators
@@ -41,7 +41,7 @@ WOODPECKER_ORGS=dolores,dogpatch
Administrators should also be enumerated in your configuration.
```ini
-WOODPECKER_ADMIN=johnsmith,janedoe
+WOODPECKER_ADMIN=john.smith,jane_doe
```
## Filtering repositories
@@ -51,7 +51,7 @@ Woodpecker operates with the user's OAuth permission. Due to the coarse permissi
Use the `WOODPECKER_REPO_OWNERS` variable to filter which GitHub user's repos should be synced only. You typically want to put here your company's GitHub name.
```ini
-WOODPECKER_REPO_OWNERS=mycompany,mycompanyossgithubuser
+WOODPECKER_REPO_OWNERS=my_company,my_company_oss_github_user
```
## Global registry setting
@@ -63,17 +63,15 @@ Point it to your server's docker config.
WOODPECKER_DOCKER_CONFIG=/root/.docker/config.json
```
-## Handling sensitive data in docker-compose and docker-swarm
+## Handling sensitive data in **docker compose** and **docker swarm**
-To handle sensitive data in docker-compose or docker-swarm configurations there are several options:
+To handle sensitive data in `docker compose` or `docker swarm` configurations there are several options:
-For docker-compose you can use a `.env` file next to your compose configuration to store the secrets outside of the compose file. While this separates configuration from secrets it is still not very secure.
+For docker compose you can use a `.env` file next to your compose configuration to store the secrets outside of the compose file. While this separates configuration from secrets it is still not very secure.
Alternatively use docker-secrets. As it may be difficult to use docker secrets for environment variables Woodpecker allows to read sensible data from files by providing a `*_FILE` option of all sensible configuration variables. Woodpecker will try to read the value directly from this file. Keep in mind that when the original environment variable gets specified at the same time it will override the value read from the file.
```diff title="docker-compose.yaml"
- version: '3'
-
services:
woodpecker-server:
[...]
@@ -133,7 +131,7 @@ The examples below show how to place a banner message in the top navigation bar
### `woodpecker.js`
```javascript
-// place/copy a minified version of jQuery or ZeptoJS here ...
+// place/copy a minified version of your preferred lightweight JavaScript library here ...
!(function () {
'use strict';
function e() {} /*...*/
@@ -197,14 +195,6 @@ Examples:
- `WOODPECKER_HOST=http://example.org/woodpecker`
- `WOODPECKER_HOST=http://example.org:1234/woodpecker`
-### `WOODPECKER_WEBHOOK_HOST`
-
-> Default: value from `WOODPECKER_HOST` config env
-
-Server fully qualified URL of the Webhook-facing hostname and path prefix.
-
-Example: `WOODPECKER_WEBHOOK_HOST=http://woodpecker-server.cicd.svc.cluster.local:8000`
-
### `WOODPECKER_SERVER_ADDR`
> Default: `:8000`
@@ -305,7 +295,7 @@ Example: `org1,org2`
> Default: empty
-Comma-separated list of syncable repo owners. ???
+Repositories by those owners will be allowed to be used in woodpecker.
Example: `user1,user2`
@@ -327,11 +317,13 @@ Always use authentication to clone repositories even if they are public. Needed
List of event names that will be canceled when a new pipeline for the same context (tag, branch) is created.
-### `WOODPECKER_DEFAULT_CLONE_IMAGE`
+### `WOODPECKER_DEFAULT_CLONE_PLUGIN`
> Default is defined in [shared/constant/constant.go](https://github.com/woodpecker-ci/woodpecker/blob/main/shared/constant/constant.go)
-The default docker image to be used when cloning the repo
+The default docker image to be used when cloning the repo.
+
+It is also added to the trusted clone plugin list.
### `WOODPECKER_DEFAULT_PIPELINE_TIMEOUT`
@@ -354,11 +346,20 @@ Context: when someone does log into Woodpecker, a temporary session token is cre
As long as the session is valid (until it expires or log-out),
a user can log into Woodpecker, without re-authentication.
-### `WOODPECKER_ESCALATE`
+### `WOODPECKER_PLUGINS_PRIVILEGED`
+
+Docker images to run in privileged mode. Only change if you are sure what you do!
+
+You should specify the tag of your images too, as this enforces exact matches.
+
+### WOODPECKER_PLUGINS_TRUSTED_CLONE
> Defaults are defined in [shared/constant/constant.go](https://github.com/woodpecker-ci/woodpecker/blob/main/shared/constant/constant.go)
-Docker images to run in privileged mode. Only change if you are sure what you do!
+Plugins witch are trusted to handle the netrc info in clone steps.
+If a clone step use an image not in this list, the netrc will not be injected and an user has to use other methods (e.g. secrets) to clone non public repos.
+
+You should specify the tag of your images too, as this enforces exact matches.
+
```bash
docker image rm $(docker images --filter "dangling=true" -q --no-trunc)
```
diff --git a/docs/docs/30-administration/22-backends/40-kubernetes.md b/docs/docs/30-administration/22-backends/40-kubernetes.md
index 48f4a622d..f2e11ff80 100644
--- a/docs/docs/30-administration/22-backends/40-kubernetes.md
+++ b/docs/docs/30-administration/22-backends/40-kubernetes.md
@@ -107,7 +107,7 @@ steps:
limits:
memory: 256Mi
nodeSelector:
- beta.kubernetes.io/instance-type: p3.8xlarge
+ beta.kubernetes.io/instance-type: Standard_D2_v3
tolerations:
- key: 'key1'
operator: 'Equal'
@@ -156,6 +156,8 @@ Note that the `backend_options.kubernetes.securityContext` object allows you to
By default, the properties will be set at the Pod level. Properties that are only supported on the container level will be set there instead. So, the
configuration shown above will result in something like the following Pod spec:
+
+
```yaml
kind: Pod
spec:
@@ -170,7 +172,9 @@ spec:
[...]
```
-You can also restrict a container's syscalls with [seccomp](https://kubernetes.io/docs/tutorials/security/seccomp/) profile
+
+
+You can also restrict a syscalls of containers with [seccomp](https://kubernetes.io/docs/tutorials/security/seccomp/) profile.
```yaml
backend_options:
@@ -193,7 +197,7 @@ backend_options:
```
:::note
-AppArmor syntax follows [KEP-24](https://github.com/kubernetes/enhancements/blob/fddcbb9cbf3df39ded03bad71228265ac6e5215f/keps/sig-node/24-apparmor/README.md).
+The feature requires Kubernetes v1.30 or above.
:::
### Annotations and labels
@@ -230,7 +234,8 @@ See [this issue](https://github.com/woodpecker-ci/woodpecker/issues/2510) for mo
### `KUBERNETES_SERVICE_HOST` environment variable
-Like the below env vars used for configuration, this can be set in the environment fonfiguration of the agent. It configures the address of the Kubernetes API server to connect to.
+Like the below env vars used for configuration, this can be set in the environment for configuration of the agent.
+It configures the address of the Kubernetes API server to connect to.
If running the agent within Kubernetes, this will already be set and you don't have to add it manually.
@@ -292,7 +297,7 @@ Determines if Pod annotations can be defined from a step's backend options.
Additional node selector to apply to worker pods. Must be a YAML object, e.g. `{"topology.kubernetes.io/region":"eu-central-1"}`.
-### `WOODPECKER_BACKEND_K8S_SECCTX_NONROOT`
+### `WOODPECKER_BACKEND_K8S_SECCTX_NONROOT`
> Default: `false`
diff --git a/docs/docs/30-administration/22-backends/50-custom-backends.md b/docs/docs/30-administration/22-backends/50-custom-backends.md
index 3c771c4ef..a35a4f1ee 100644
--- a/docs/docs/30-administration/22-backends/50-custom-backends.md
+++ b/docs/docs/30-administration/22-backends/50-custom-backends.md
@@ -1,6 +1,6 @@
# Custom backends
-If none of our backends fits your usecases, you can write your own.
+If none of our backends fits your usecase, you can write your own.
Therefore, implement the interface `"go.woodpecker-ci.org/woodpecker/woodpecker/v2/pipeline/backend/types".Backend` and
build a custom agent using your backend with this `main.go`:
diff --git a/docs/versioned_docs/version-2.4/30-administration/70-proxy.md b/docs/docs/30-administration/40-advanced/10-proxy.md
similarity index 93%
rename from docs/versioned_docs/version-2.4/30-administration/70-proxy.md
rename to docs/docs/30-administration/40-advanced/10-proxy.md
index 4aae2fbe1..8771eed44 100644
--- a/docs/versioned_docs/version-2.4/30-administration/70-proxy.md
+++ b/docs/docs/30-administration/40-advanced/10-proxy.md
@@ -4,6 +4,8 @@
This guide provides a brief overview for installing Woodpecker server behind the Apache2 web-server. This is an example configuration:
+
+
```apacheconf
ProxyPreserveHost On
@@ -31,7 +33,7 @@ You must configure Apache to set `X-Forwarded-Proto` when using https.
## Nginx
-This guide provides a basic overview for installing Woodpecker server behind the Nginx web-server. For more advanced configuration options please consult the official Nginx [documentation](https://www.nginx.com/resources/admin-guide/).
+This guide provides a basic overview for installing Woodpecker server behind the Nginx web-server. For more advanced configuration options please consult the official Nginx [documentation](https://docs.nginx.com/nginx/admin-guide).
Example configuration:
@@ -87,13 +89,13 @@ woodpecker.example.com {
}
# expose gRPC
-woodpeckeragent.example.com {
+woodpecker-agent.example.com {
reverse_proxy h2c://woodpecker-server:9000
}
```
:::note
-Above configuration shows how to create reverse-proxies for web and agent communication. If your agent uses SSL do not forget to enable [`WOODPECKER_GRPC_SECURE`](./15-agent-config.md#woodpecker_grpc_secure).
+Above configuration shows how to create reverse-proxies for web and agent communication. If your agent uses SSL do not forget to enable [`WOODPECKER_GRPC_SECURE`](../15-agent-config.md#woodpecker_grpc_secure).
:::
## Tunnelmole
@@ -132,9 +134,9 @@ Set `WOODPECKER_HOST` to the ngrok URL (usually xxx.ngrok.io) and start the serv
To install the Woodpecker server behind a [Traefik](https://traefik.io/) load balancer, you must expose both the `http` and the `gRPC` ports. Here is a comprehensive example, considering you are running Traefik with docker swarm and want to do TLS termination and automatic redirection from http to https.
-```yaml
-version: '3.8'
+
+```yaml
services:
server:
image: woodpeckerci/woodpecker-server:latest
@@ -155,13 +157,13 @@ services:
# web server
- traefik.http.services.woodpecker-service.loadbalancer.server.port=8000
- - traefik.http.routers.woodpecker-secure.rule=Host(`cd.yourdomain.com`)
+ - traefik.http.routers.woodpecker-secure.rule=Host(`cd.your-domain.com`)
- traefik.http.routers.woodpecker-secure.tls=true
- traefik.http.routers.woodpecker-secure.tls.certresolver=letsencrypt
- - traefik.http.routers.woodpecker-secure.entrypoints=websecure
+ - traefik.http.routers.woodpecker-secure.entrypoints=web-secure
- traefik.http.routers.woodpecker-secure.service=woodpecker-service
- - traefik.http.routers.woodpecker.rule=Host(`cd.yourdomain.com`)
+ - traefik.http.routers.woodpecker.rule=Host(`cd.your-domain.com`)
- traefik.http.routers.woodpecker.entrypoints=web
- traefik.http.routers.woodpecker.service=woodpecker-service
@@ -173,13 +175,13 @@ services:
- traefik.http.services.woodpecker-grpc.loadbalancer.server.port=9000
- traefik.http.services.woodpecker-grpc.loadbalancer.server.scheme=h2c
- - traefik.http.routers.woodpecker-grpc-secure.rule=Host(`woodpecker-grpc.yourdomain.com`)
+ - traefik.http.routers.woodpecker-grpc-secure.rule=Host(`woodpecker-grpc.your-domain.com`)
- traefik.http.routers.woodpecker-grpc-secure.tls=true
- traefik.http.routers.woodpecker-grpc-secure.tls.certresolver=letsencrypt
- - traefik.http.routers.woodpecker-grpc-secure.entrypoints=websecure
+ - traefik.http.routers.woodpecker-grpc-secure.entrypoints=web-secure
- traefik.http.routers.woodpecker-grpc-secure.service=woodpecker-grpc
- - traefik.http.routers.woodpecker-grpc.rule=Host(`woodpecker-grpc.yourdomain.com`)
+ - traefik.http.routers.woodpecker-grpc.rule=Host(`woodpecker-grpc.your-domain.com`)
- traefik.http.routers.woodpecker-grpc.entrypoints=web
- traefik.http.routers.woodpecker-grpc.service=woodpecker-grpc
diff --git a/docs/versioned_docs/version-2.4/30-administration/100-external-configuration-api.md b/docs/docs/30-administration/40-advanced/100-external-configuration-api.md
similarity index 83%
rename from docs/versioned_docs/version-2.4/30-administration/100-external-configuration-api.md
rename to docs/docs/30-administration/40-advanced/100-external-configuration-api.md
index f951b1478..a24abd3bd 100644
--- a/docs/versioned_docs/version-2.4/30-administration/100-external-configuration-api.md
+++ b/docs/docs/30-administration/40-advanced/100-external-configuration-api.md
@@ -3,7 +3,7 @@
To provide additional management and preprocessing capabilities for pipeline configurations Woodpecker supports an HTTP API which can be enabled to call an external config service.
Before the run or restart of any pipeline Woodpecker will make a POST request to an external HTTP API sending the current repository, build information and all current config files retrieved from the repository. The external API can then send back new pipeline configurations that will be used immediately or respond with `HTTP 204` to tell the system to use the existing configuration.
-Every request sent by Woodpecker is signed using a [http-signature](https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures) by a private key (ed25519) generated on the first start of the Woodpecker server. You can get the public key for the verification of the http-signature from `http(s)://your-woodpecker-server/api/signature/public-key`.
+Every request sent by Woodpecker is signed using a [http-signature](https://datatracker.ietf.org/doc/html/rfc9421) by a private key (ed25519) generated on the first start of the Woodpecker server. You can get the public key for the verification of the http-signature from `http(s)://your-woodpecker-server/api/signature/public-key`.
A simplistic example configuration service can be found here: [https://github.com/woodpecker-ci/example-config-service](https://github.com/woodpecker-ci/example-config-service)
@@ -26,7 +26,7 @@ WOODPECKER_CONFIG_SERVICE_ENDPOINT=https://example.com/ciconfig
"uid": "",
"user_id": 0,
"namespace": "",
- "name": "woodpecker-testpipe",
+ "name": "woodpecker-test-pipe",
"slug": "",
"scm": "git",
"git_http_url": "",
@@ -54,7 +54,7 @@ WOODPECKER_CONFIG_SERVICE_ENDPOINT=https://example.com/ciconfig
"author_avatar": "https://myforge.com/avatars/d6b3f7787a685fcdf2a44e2c685c7e03",
"author_email": "my@email.com",
"branch": "main",
- "changed_files": ["somefilename.txt"],
+ "changed_files": ["some-file-name.txt"],
"commit": "2fff90f8d288a4640e90f05049fe30e61a14fd50",
"created_at": 0,
"deploy_to": "",
@@ -81,12 +81,11 @@ WOODPECKER_CONFIG_SERVICE_ENDPOINT=https://example.com/ciconfig
"updated_at": 0,
"verified": false
},
- "configs": [
- {
- "name": ".woodpecker.yaml",
- "data": "steps:\n - name: backend\n image: alpine\n commands:\n - echo \"Hello there from Repo (.woodpecker.yaml)\"\n"
- }
- ]
+ "netrc": {
+ "machine": "https://example.com",
+ "login": "user",
+ "password": "password"
+ }
}
```
diff --git a/docs/versioned_docs/version-2.4/30-administration/60-ssl.md b/docs/docs/30-administration/40-advanced/20-ssl.md
similarity index 98%
rename from docs/versioned_docs/version-2.4/30-administration/60-ssl.md
rename to docs/docs/30-administration/40-advanced/20-ssl.md
index 755ba205d..6fda26d3d 100644
--- a/docs/versioned_docs/version-2.4/30-administration/60-ssl.md
+++ b/docs/docs/30-administration/40-advanced/20-ssl.md
@@ -52,8 +52,6 @@ SSL support is provided using the [ListenAndServeTLS](https://golang.org/pkg/net
Update your configuration to expose the following ports:
```diff title="docker-compose.yaml"
- version: '3'
-
services:
woodpecker-server:
[...]
@@ -66,8 +64,6 @@ Update your configuration to expose the following ports:
Update your configuration to mount your certificate and key:
```diff title="docker-compose.yaml"
- version: '3'
-
services:
woodpecker-server:
[...]
@@ -79,8 +75,6 @@ Update your configuration to mount your certificate and key:
Update your configuration to provide the paths of your certificate and key:
```diff title="docker-compose.yaml"
- version: '3'
-
services:
woodpecker-server:
[...]
diff --git a/docs/versioned_docs/version-2.4/30-administration/80-autoscaler.md b/docs/docs/30-administration/40-advanced/30-autoscaler.md
similarity index 87%
rename from docs/versioned_docs/version-2.4/30-administration/80-autoscaler.md
rename to docs/docs/30-administration/40-advanced/30-autoscaler.md
index 6ac581c2e..0ad43a30b 100644
--- a/docs/versioned_docs/version-2.4/30-administration/80-autoscaler.md
+++ b/docs/docs/30-administration/40-advanced/30-autoscaler.md
@@ -6,13 +6,11 @@ Please note that the autoscaler is not feature-complete yet. You can follow the
## Setup
-### docker-compose
+### docker compose
-If you are using docker-compose you can add the following to your `docker-compose.yaml` file:
+If you are using docker compose you can add the following to your `docker-compose.yaml` file:
```yaml
-version: '3'
-
services:
woodpecker-server:
image: woodpeckerci/woodpecker-server:next
@@ -29,8 +27,8 @@ services:
- WOODPECKER_MIN_AGENTS=0
- WOODPECKER_MAX_AGENTS=3
- WOODPECKER_WORKFLOWS_PER_AGENT=2 # the number of workflows each agent can run at the same time
- - WOODEPCKER_GRPC_ADDR=https://grpc.your-woodpecker-server.tld # the grpc address of your woodpecker server, publicly accessible from the agents
- - WOODEPCKER_GRPC_SECURE=true
+ - WOODPECKER_GRPC_ADDR=https://grpc.your-woodpecker-server.tld # the grpc address of your woodpecker server, publicly accessible from the agents
+ - WOODPECKER_GRPC_SECURE=true
- WOODPECKER_AGENT_ENV= # optional environment variables to pass to the agents
- WOODPECKER_PROVIDER=hetznercloud # set the provider, you can find all the available ones down below
- WOODPECKER_HETZNERCLOUD_API_TOKEN=${WOODPECKER_HETZNERCLOUD_API_TOKEN} # your api token for the Hetzner cloud
diff --git a/docs/docs/30-administration/40-advanced/40-advanced.md b/docs/docs/30-administration/40-advanced/40-advanced.md
new file mode 100644
index 000000000..4261bbeea
--- /dev/null
+++ b/docs/docs/30-administration/40-advanced/40-advanced.md
@@ -0,0 +1,25 @@
+# Advanced options
+
+Why should we be happy with a default setup? We should not! Woodpecker offers a lot of advanced options to configure it to your needs.
+
+## Behind a proxy
+
+See the [proxy guide](./10-proxy.md) if you want to see a setup behind Apache, Nginx, Caddy or ngrok.
+
+In the case you need to use Woodpecker with a URL path prefix (like: ), add the root path to [`WOODPECKER_HOST`](../10-server-config.md#woodpecker_host).
+
+## SSL
+
+Woodpecker supports SSL configuration by using Let's encrypt or by using own certificates. See the [SSL guide](./20-ssl.md).
+
+## Metrics
+
+A [Prometheus endpoint](./90-prometheus.md) is exposed by Woodpecker to collect metrics.
+
+## Autoscaling
+
+The [autoscaler](./30-autoscaler.md) can be used to deploy new agents to a cloud provider based on the current workload your server is experiencing.
+
+## Configuration service
+
+Sometime the normal yaml configuration compiler isn't enough. You can use the [configuration service](./100-external-configuration-api.md) to process your configuration files by your own.
diff --git a/docs/versioned_docs/version-2.4/30-administration/90-prometheus.md b/docs/docs/30-administration/40-advanced/90-prometheus.md
similarity index 91%
rename from docs/versioned_docs/version-2.4/30-administration/90-prometheus.md
rename to docs/docs/30-administration/40-advanced/90-prometheus.md
index 2264f3b09..3f974ccb0 100644
--- a/docs/versioned_docs/version-2.4/30-administration/90-prometheus.md
+++ b/docs/docs/30-administration/40-advanced/90-prometheus.md
@@ -52,11 +52,11 @@ List of Prometheus metrics specific to Woodpecker:
# HELP woodpecker_pipeline_count Pipeline count.
# TYPE woodpecker_pipeline_count counter
woodpecker_pipeline_count{branch="main",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 3
-woodpecker_pipeline_count{branch="mkdocs",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 3
+woodpecker_pipeline_count{branch="dev",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 3
# HELP woodpecker_pipeline_time Build time.
# TYPE woodpecker_pipeline_time gauge
woodpecker_pipeline_time{branch="main",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 116
-woodpecker_pipeline_time{branch="mkdocs",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 155
+woodpecker_pipeline_time{branch="dev",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 155
# HELP woodpecker_pipeline_total_count Total number of builds.
# TYPE woodpecker_pipeline_total_count gauge
woodpecker_pipeline_total_count 1025
diff --git a/docs/versioned_docs/version-2.4/30-administration/75-addons/_category_.yaml b/docs/docs/30-administration/40-advanced/_category_.yaml
similarity index 60%
rename from docs/versioned_docs/version-2.4/30-administration/75-addons/_category_.yaml
rename to docs/docs/30-administration/40-advanced/_category_.yaml
index 4cd7380c5..e6c6ba0f7 100644
--- a/docs/versioned_docs/version-2.4/30-administration/75-addons/_category_.yaml
+++ b/docs/docs/30-administration/40-advanced/_category_.yaml
@@ -1,6 +1,6 @@
-label: 'Addons'
+label: 'Advanced'
collapsible: true
collapsed: true
link:
type: 'doc'
- id: 'overview'
+ id: 'advanced'
diff --git a/docs/docs/91-migrations.md b/docs/docs/91-migrations.md
index 841dee3d0..2d1870276 100644
--- a/docs/docs/91-migrations.md
+++ b/docs/docs/91-migrations.md
@@ -2,25 +2,40 @@
Some versions need some changes to the server configuration or the pipeline configuration files.
-
-
## `next`
-- Deprecated `steps.[name].group` in favor of `steps.[name].depends_on` (see [workflow syntax](./20-usage/20-workflow-syntax.md#depends_on) to learn how to set dependencies)
+- Set `/woodpecker` as defautl workdir for the **woodpecker-cli** container
+- 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`
+- 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](./30-administration/10-server-config.md#woodpecker_plugins_privileged) you trust and rely on.
+- `WOODPECKER_DEFAULT_CLONE_IMAGE` got depricated use `WOODPECKER_DEFAULT_CLONE_PLUGIN`
+- Check trusted-clone- and privileged-plugins by image name and tag (if tag is set)
+- Secret filters for plugins now check against tag if specified
+- Removed `WOODPECKER_DEV_OAUTH_HOST` and `WOODPECKER_DEV_GITEA_OAUTH_URL` use `WOODPECKER_EXPERT_FORGE_OAUTH_HOST`
+- 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](./20-usage/20-workflow-syntax.md#depends_on) to learn how to set dependencies)
- Removed `WOODPECKER_ROOT_PATH` and `WOODPECKER_ROOT_URL` config variables. Use `WOODPECKER_HOST` with a path instead
- Pipelines without a config file will now be skipped instead of failing
-- Deprecated `includes` and `excludes` support from **event** filter
-- Deprecated uppercasing all secret env vars, instead, the value of the `secrets` property is used. [Read more](./20-usage/40-secrets.md#use-secrets-in-commands)
-- Deprecated alternative names for secrets, use `environment` with `from_secret`
-- Deprecated slice definition for env vars
-- Deprecated `environment` filter, use `when.evaluate`
-- Use `WOODPECKER_EXPERT_FORGE_OAUTH_HOST` instead of `WOODPECKER_DEV_GITEA_OAUTH_URL` or `WOODPECKER_DEV_OAUTH_HOST`
-- Deprecated `WOODPECKER_WEBHOOK_HOST` in favor of `WOODPECKER_EXPERT_WEBHOOK_HOST`
+- Removed implicitly defined `regcred` image pull secret name. Set it explicitly via `WOODPECKER_BACKEND_K8S_PULL_SECRET_NAMES`
+- Removed `includes` and `excludes` support from **event** filter
+- Removed uppercasing all secret env vars, instead, the value of the `secrets` property is used. [Read more](./20-usage/40-secrets.md#use-secrets-in-commands)
+- Removed alternative names for secrets, use `environment` with `from_secret`
+- Removed slice definition for env vars
+- Removed `environment` filter, use `when.evaluate`
+- Removed `WOODPECKER_WEBHOOK_HOST` in favor of `WOODPECKER_EXPERT_WEBHOOK_HOST`
+- Migrated to rfc9421 for webhook signatures
+- Renamed `start_time`, `end_time`, `created_at`, `started_at`, `finished_at` and `reviewed_at` JSON fields to `started`, `finished`, `created`, `started`, `finished`, `reviewed`
+- 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
+- Replaced `configs` object by `netrc` in external configuration APIs
+- Removed old API routes: `registry/` -> `registries`, `/authorize/token`
+- Replaced `registry` command with `repo registry` in cli
+- Disallow upgrades from 1.x, upgrade to 2.x first
## 2.0.0
@@ -37,7 +52,7 @@ Some versions need some changes to the server configuration or the pipeline conf
## 1.0.0
-- The signature used to verify extension calls (like those used for the [config-extension](./30-administration/100-external-configuration-api.md)) done by the Woodpecker server switched from using a shared-secret HMac to an ed25519 key-pair. Read more about it at the [config-extensions](./30-administration/100-external-configuration-api.md) documentation.
+- The signature used to verify extension calls (like those used for the [config-extension](./30-administration/40-advanced/100-external-configuration-api.md)) done by the Woodpecker server switched from using a shared-secret HMac to an ed25519 key-pair. Read more about it at the [config-extensions](./30-administration/40-advanced/100-external-configuration-api.md) documentation.
- Refactored support for old agent filter labels and expressions. Learn how to use the new [filter](./20-usage/20-workflow-syntax.md#labels)
- Renamed step environment variable `CI_SYSTEM_ARCH` to `CI_SYSTEM_PLATFORM`. Same applies for the cli exec variable.
- Renamed environment variables `CI_BUILD_*` and `CI_PREV_BUILD_*` to `CI_PIPELINE_*` and `CI_PREV_PIPELINE_*`, old ones are still available but deprecated
diff --git a/docs/docs/92-awesome.md b/docs/docs/92-awesome.md
index 920341d33..aac85d036 100644
--- a/docs/docs/92-awesome.md
+++ b/docs/docs/92-awesome.md
@@ -55,12 +55,18 @@ If you have some missing resources, please feel free to [open a pull-request](ht
- [Deploying mdbook to codeberg pages using woodpecker CI](https://www.markpitblado.me/blog/deploying-mdbook-to-codeberg-pages-using-woodpecker-ci/)
- [Deploy a Fly app with Woodpecker CI](https://joeroe.io/2024/01/09/deploy-fly-woodpecker-ci.html)
- [Ansible - using Woodpecker as an alternative to Semaphore](https://pat-s.me/ansible-using-woodpecker-as-an-alternative-to-semaphore/)
+- [Simple selfhosted CI/CD with Woodpecker](https://xyquadrat.ch/blog/simple-ci-with-woodpecker/)
+- [Notes to self on Woodpecker-CI](https://jpmens.net/2023/09/22/notes-to-self-on-woodpecker-ci/)
+- [CI/CD with Woodpecker and Gitea](https://wilw.dev/blog/2023/04/23/woodpecker-ci/)
## Videos
- [Replace Ansible Semaphore with Woodpecker CI](https://www.youtube.com/watch?v=d610YPvCB0E)
- ["unexpected EOF" error when trying to pair Woodpecker CI served through the Caddy with Gitea](https://www.youtube.com/watch?v=n7Hyvt71Np0)
- [CICD Environment in Docker Swarm behind Caddy Server - Part 2 Woodpeckerci](https://www.youtube.com/watch?v=rkbw_k7JvS0)
+- [How to Build & Publish Custom Docker Container using Gitea & Woodpecker behind Caddy Server | TUNEIT](https://www.youtube.com/watch?v=9m7DbgL1mNk)
+- [Radicle Woodpecker CI Integration](https://www.youtube.com/watch?v=Ks1nbYLn4P8)
+- [woodpecker-ci/woodpecker - Gource visualisation](https://www.youtube.com/watch?v=38JuakZ6m5s)
## Plugins
diff --git a/docs/docs/92-development/01-getting-started.md b/docs/docs/92-development/01-getting-started.md
index e1bb1ce0c..4d93227c3 100644
--- a/docs/docs/92-development/01-getting-started.md
+++ b/docs/docs/92-development/01-getting-started.md
@@ -4,12 +4,12 @@ You can develop on your local computer by following the [steps below](#preparati
## Gitpod
-If you want to start development or updating docs as easy as possible, you can use our preconfigured setup for Woodpecker using [Gitpod](https://github.com/gitpod-io/gitpod). Gitpod starts a complete development setup in the cloud containing:
+If you want to start development or updating docs as easy as possible, you can use our pre-configured setup for Woodpecker using [Gitpod](https://github.com/gitpod-io/gitpod). Gitpod starts a complete development setup in the cloud containing:
- An IDE in the browser or bridged to your local VS-Code or Jetbrains
-- A preconfigured [Gitea](https://github.com/go-gitea/gitea) instance as forge
-- A preconfigured Woodpecker server
-- A single preconfigured Woodpecker agent node
+- A pre-configured [Gitea](https://github.com/go-gitea/gitea) instance as forge
+- A pre-configured Woodpecker server
+- A single pre-configured Woodpecker agent node
- Our docs preview server
Start Woodpecker in Gitpod by clicking on the following badge. You can log in with `woodpecker` and `password`.
@@ -46,7 +46,7 @@ To apply it during local development, take a look at [`pre-commit`s documentatio
### Create a `.env` file with your development configuration
-Similar to the environment variables you can set for your production setup of Woodpecker, you can create a `.env` in the root of the Woodpecker project and add any need config to it.
+Similar to the environment variables you can set for your production setup of Woodpecker, you can create a `.env` file in the root of the Woodpecker project and add any needed config to it.
A common config for debugging would look like this:
@@ -54,8 +54,7 @@ A common config for debugging would look like this:
WOODPECKER_OPEN=true
WOODPECKER_ADMIN=your-username
-# if you want to test webhooks with an online forge like GitHub this address needs to be accessible from public server
-WOODPECKER_HOST=http://your-dev-address.com
+WOODPECKER_HOST=http://localhost:8000
# github (sample for a forge config - see /docs/administration/forge/overview for other forges)
WOODPECKER_GITHUB=true
@@ -70,8 +69,8 @@ WOODPECKER_MAX_WORKFLOWS=1
# enable if you want to develop the UI
# WOODPECKER_DEV_WWW_PROXY=http://localhost:8010
-# used so you can login without using a public address
-WOODPECKER_DEV_OAUTH_HOST=http://localhost:8000
+# if you want to test webhooks with an online forge like GitHub this address needs to be set and accessible from public server
+WOODPECKER_EXPERT_WEBHOOK_HOST=http://your-address.com
# disable health-checks while debugging (normally not needed while developing)
WOODPECKER_HEALTHCHECK=false
@@ -82,7 +81,7 @@ WOODPECKER_HEALTHCHECK=false
### Setup OAuth
-Create an OAuth app for your forge as described in the [forges documentation](../30-administration/11-forges/11-overview.md). If you set `WOODPECKER_DEV_OAUTH_HOST=http://localhost:8000` you can use that address with the path as explained for the specific forge to login without the need for a public address. For example for GitHub you would use `http://localhost:8000/authorize` as authorization callback URL.
+Create an OAuth app for your forge as described in the [forges documentation](../30-administration/11-forges/11-overview.md).
## Developing with VS Code
diff --git a/docs/docs/92-development/02-core-ideas.md b/docs/docs/92-development/02-core-ideas.md
index 8e0d6e292..a88470f0a 100644
--- a/docs/docs/92-development/02-core-ideas.md
+++ b/docs/docs/92-development/02-core-ideas.md
@@ -8,7 +8,7 @@
## Addons and extensions
If you are wondering whether your contribution will be accepted to be merged in the Woodpecker core, or whether it's better to write an
-[addon forge](../30-administration/11-forges/100-addon.md), [extension](../30-administration/100-external-configuration-api.md) or an
+[addon forge](../30-administration/11-forges/100-addon.md), [extension](../30-administration/40-advanced/100-external-configuration-api.md) or an
[external custom backend](../30-administration/22-backends/50-custom-backends.md), please check these points:
- Is your change very specific to your setup and unlikely to be used by anyone else?
diff --git a/docs/docs/92-development/03-ui.md b/docs/docs/92-development/03-ui.md
index e8999b0be..6a01584c2 100644
--- a/docs/docs/92-development/03-ui.md
+++ b/docs/docs/92-development/03-ui.md
@@ -36,4 +36,4 @@ The following list contains some tools and frameworks used by the Woodpecker UI.
Woodpecker uses [Vue I18n](https://vue-i18n.intlify.dev/) as translation library. New translations have to be added to `web/src/assets/locales/en.json`. The English source file will be automatically imported into [Weblate](https://translate.woodpecker-ci.org/) (the translation system used by Woodpecker) where all other languages will be translated by the community based on the English source.
You must not provide translations except English in PRs, otherwise weblate could put git into conflicts (when someone has translated in that language file and changes are not into main branch yet)
-For more information about translations see [Translations](./07-translations.md).
+For more information about translations see [Translations](./08-translations.md).
diff --git a/docs/docs/92-development/05-architecture.md b/docs/docs/92-development/05-architecture.md
index ccfd410f3..535ec6a80 100644
--- a/docs/docs/92-development/05-architecture.md
+++ b/docs/docs/92-development/05-architecture.md
@@ -19,23 +19,23 @@
### Server
-| package | meaning | imports |
-| -------------------- | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `server/api/**` | handle web requests from `server/router` | `pipeline`, `../badges`, `../ccmenue`, `../logging`, `../model`, `../pubsub`, `../queue`, `../forge`, `../shared`, `../store`, `shared`, (TODO: mv `server/router/middleware/session`) |
-| `server/badges/**` | generate svg badges for pipelines | `../model` |
-| `server/ccmenu/**` | generate xml ccmenu for pipelines | `../model` |
-| `server/grpc/**` | gRPC server agents can connect to | `pipeline/rpc/**`, `../logging`, `../model`, `../pubsub`, `../queue`, `../forge`, `../pipeline`, `../store` |
-| `server/logging/**` | logging lib for gPRC server to stream logs while running | std |
-| `server/model/**` | structs for store (db) and api (json) | std |
-| `server/plugins/**` | plugins for server | `../model`, `../forge` |
-| `server/pipeline/**` | orchestrate pipelines | `pipeline`, `../model`, `../pubsub`, `../queue`, `../forge`, `../store`, `../plugins` |
-| `server/pubsub/**` | pubsub lib for server to push changes to the WebUI | std |
-| `server/queue/**` | queue lib for server where agents pull new pipelines from via gRPC | `server/model` |
-| `server/forge/**` | forge lib for server to connect and handle forge specific stuff | `shared`, `server/model` |
-| `server/router/**` | handle requests to REST API (and all middleware) and serve UI and WebUI config | `shared`, `../api`, `../model`, `../forge`, `../store`, `../web` |
-| `server/store/**` | handle database | `server/model` |
-| `server/shared/**` | TODO: move and split [#974](https://github.com/woodpecker-ci/woodpecker/issues/974) | |
-| `server/web/**` | server SPA | |
+| package | meaning | imports |
+| -------------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `server/api/**` | handle web requests from `server/router` | `pipeline`, `../badges`, `../ccmenu`, `../logging`, `../model`, `../pubsub`, `../queue`, `../forge`, `../shared`, `../store`, `shared`, (TODO: mv `server/router/middleware/session`) |
+| `server/badges/**` | generate svg badges for pipelines | `../model` |
+| `server/ccmenu/**` | generate xml ccmenu for pipelines | `../model` |
+| `server/grpc/**` | gRPC server agents can connect to | `pipeline/rpc/**`, `../logging`, `../model`, `../pubsub`, `../queue`, `../forge`, `../pipeline`, `../store` |
+| `server/logging/**` | logging lib for gPRC server to stream logs while running | std |
+| `server/model/**` | structs for store (db) and api (json) | std |
+| `server/plugins/**` | plugins for server | `../model`, `../forge` |
+| `server/pipeline/**` | orchestrate pipelines | `pipeline`, `../model`, `../pubsub`, `../queue`, `../forge`, `../store`, `../plugins` |
+| `server/pubsub/**` | pubsub lib for server to push changes to the WebUI | std |
+| `server/queue/**` | queue lib for server where agents pull new pipelines from via gRPC | `server/model` |
+| `server/forge/**` | forge lib for server to connect and handle forge specific stuff | `shared`, `server/model` |
+| `server/router/**` | handle requests to REST API (and all middleware) and serve UI and WebUI config | `shared`, `../api`, `../model`, `../forge`, `../store`, `../web` |
+| `server/store/**` | handle database | `server/model` |
+| `server/shared/**` | TODO: move and split [#974](https://github.com/woodpecker-ci/woodpecker/issues/974) | |
+| `server/web/**` | server SPA | |
- `../` = `server/`
diff --git a/docs/docs/92-development/06-conventions.md b/docs/docs/92-development/06-conventions.md
new file mode 100644
index 000000000..e94a90c43
--- /dev/null
+++ b/docs/docs/92-development/06-conventions.md
@@ -0,0 +1,7 @@
+# Conventions
+
+## Database naming
+
+Database tables are named plural, columns don't have any prefix.
+
+Example: Table name `agent`, columns `id`, `name`.
diff --git a/docs/docs/92-development/06-guides.md b/docs/docs/92-development/07-guides.md
similarity index 100%
rename from docs/docs/92-development/06-guides.md
rename to docs/docs/92-development/07-guides.md
diff --git a/docs/docs/92-development/07-translations.md b/docs/docs/92-development/08-translations.md
similarity index 100%
rename from docs/docs/92-development/07-translations.md
rename to docs/docs/92-development/08-translations.md
diff --git a/docs/docs/92-development/08-swagger.md b/docs/docs/92-development/09-swagger.md
similarity index 94%
rename from docs/docs/92-development/08-swagger.md
rename to docs/docs/92-development/09-swagger.md
index 9a3775c41..5bf303c7b 100644
--- a/docs/docs/92-development/08-swagger.md
+++ b/docs/docs/92-development/09-swagger.md
@@ -7,7 +7,7 @@ and then being using on the community's website documentation.
It's paramount important to keep the gin handler function's godoc documentation up-to-date,
to always have accurate API documentation.
-Whenever you change, add or enhance an API endpoint, please update the godocs.
+Whenever you change, add or enhance an API endpoint, please update the godoc.
You don't require any extra tools on your machine, all Swagger tooling is automatically fetched by standard Go tools.
@@ -41,8 +41,8 @@ These guidelines aim to have consistent wording in the swagger doc:
- first word after `@Summary` and `@Summary` are always uppercase
- `@Summary` has no `.` (dot) at the end of the line
- model structs shall use custom short names, to ease life for API consumers, using `@name`
-- `@Success` object or array declarations shall be short, this means the actual `model.User` struct must have a `@name` annotation, so that the model can be renderend in Swagger
-- when pagination is used, `@Parame page` and `@Parame perPage` must be added manually
+- `@Success` object or array declarations shall be short, this means the actual `model.User` struct must have a `@name` annotation, so that the model can be rendered in Swagger
+- when pagination is used, `@Param page` and `@Param perPage` must be added manually
- `@Param Authorization` is almost always present, there are just a few un-protected endpoints
There are many examples in the `server/api` package, which you can use a blueprint.
diff --git a/docs/docs/92-development/09-testing.md b/docs/docs/92-development/09-testing.md
new file mode 100644
index 000000000..f27f71130
--- /dev/null
+++ b/docs/docs/92-development/09-testing.md
@@ -0,0 +1,85 @@
+# Testing
+
+## Backend
+
+### Unit Tests
+
+[We use default golang unit tests](https://go.dev/doc/tutorial/add-a-test)
+with [`"github.com/stretchr/testify/assert"`](https://pkg.go.dev/github.com/stretchr/testify@v1.9.0/assert) to simplify testing.
+
+### Integration Tests
+
+### Dummy backend
+
+There is a special backend called **`dummy`** which does not execute any commands, but emulates how a typical backend should behave.
+To enable it you need to build the agent or cli with the `test` build tag.
+
+An example pipeline config would be:
+
+```yaml
+when:
+ event: manual
+
+steps:
+ - name: echo
+ image: dummy
+ commands: echo "hello woodpecker"
+ environment:
+ SLEEP: '1s'
+
+services:
+ echo:
+ image: dummy
+ commands: echo "i am a service"
+```
+
+This could be executed via `woodpecker-cli --log-level trace exec --backend-engine dummy example.yaml`:
+
+
+
+```none
+9:18PM DBG pipeline/pipeline.go:94 > executing 2 stages, in order of: CLI=exec
+9:18PM DBG pipeline/pipeline.go:104 > stage CLI=exec StagePos=0 Steps=echo
+9:18PM DBG pipeline/pipeline.go:104 > stage CLI=exec StagePos=1 Steps=echo
+9:18PM TRC pipeline/backend/dummy/dummy.go:75 > create workflow environment taskUUID=01J10P578JQE6E25VV1EQF0745
+9:18PM DBG pipeline/pipeline.go:176 > prepare CLI=exec step=echo
+9:18PM DBG pipeline/pipeline.go:203 > executing CLI=exec step=echo
+9:18PM TRC pipeline/backend/dummy/dummy.go:81 > start step echo taskUUID=01J10P578JQE6E25VV1EQF0745
+9:18PM TRC pipeline/backend/dummy/dummy.go:167 > tail logs of step echo taskUUID=01J10P578JQE6E25VV1EQF0745
+9:18PM DBG pipeline/pipeline.go:209 > complete CLI=exec step=echo
+[echo:L0:0s] StepName: echo
+[echo:L1:0s] StepType: service
+[echo:L2:0s] StepUUID: 01J10P578JQE6E25VV1A2DNQN9
+[echo:L3:0s] StepCommands:
+[echo:L4:0s] ------------------
+[echo:L5:0s] echo ja
+[echo:L6:0s] ------------------
+[echo:L7:0s] 9:18PM DBG pipeline/pipeline.go:176 > prepare CLI=exec step=echo
+9:18PM DBG pipeline/pipeline.go:203 > executing CLI=exec step=echo
+9:18PM TRC pipeline/backend/dummy/dummy.go:81 > start step echo taskUUID=01J10P578JQE6E25VV1EQF0745
+9:18PM TRC pipeline/backend/dummy/dummy.go:167 > tail logs of step echo taskUUID=01J10P578JQE6E25VV1EQF0745
+[echo:L0:0s] StepName: echo
+[echo:L1:0s] StepType: commands
+[echo:L2:0s] StepUUID: 01J10P578JQE6E25VV1DFSXX1Y
+[echo:L3:0s] StepCommands:
+[echo:L4:0s] ------------------
+[echo:L5:0s] echo ja
+[echo:L6:0s] ------------------
+[echo:L7:0s] 9:18PM TRC pipeline/backend/dummy/dummy.go:108 > wait for step echo taskUUID=01J10P578JQE6E25VV1EQF0745
+9:18PM TRC pipeline/backend/dummy/dummy.go:187 > stop step echo taskUUID=01J10P578JQE6E25VV1EQF0745
+9:18PM DBG pipeline/pipeline.go:209 > complete CLI=exec step=echo
+9:18PM TRC pipeline/backend/dummy/dummy.go:208 > delete workflow environment taskUUID=01J10P578JQE6E25VV1EQF0745
+```
+
+
+
+There are also environment variables to alter step behavior:
+
+- `SLEEP: 10` will let the step wait 10 seconds
+- `EXPECT_TYPE` allows to check if a step is a `clone`, `service`, `plugin` or `commands`
+- `STEP_START_FAIL: true` if set will simulate a step to fail before actually being started (e.g. happens when the container image can not be pulled)
+- `STEP_TAIL_FAIL: true` if set will error when we simulate to read from stdout for logs
+- `STEP_EXIT_CODE: 2` if set will be used as exit code, default is 0
+- `STEP_OOM_KILLED: true` simulates a step being killed by memory constrains
+
+You can let the setup of a whole workflow fail by setting it's UUID to `WorkflowSetupShouldFail`.
diff --git a/docs/docusaurus.config.ts b/docs/docusaurus.config.ts
index 5057fa018..7bfb0cc2e 100644
--- a/docs/docusaurus.config.ts
+++ b/docs/docusaurus.config.ts
@@ -5,7 +5,7 @@ import * as path from 'path';
const config: Config = {
title: 'Woodpecker CI',
- tagline: 'Woodpecker is a simple yet powerful CI/CD engine with great extensibility.',
+ tagline: 'Woodpecker is a simple, yet powerful CI/CD engine with great extensibility.',
url: 'https://woodpecker-ci.org',
baseUrl: '/',
onBrokenLinks: 'throw',
@@ -15,6 +15,15 @@ const config: Config = {
organizationName: 'woodpecker-ci',
projectName: 'woodpecker-ci.github.io',
trailingSlash: false,
+ headTags: [
+ {
+ tagName: 'link',
+ attributes: {
+ href: 'https://floss.social/@WoodpeckerCI',
+ rel: 'me',
+ },
+ },
+ ],
themeConfig: {
navbar: {
title: 'Woodpecker',
@@ -25,7 +34,7 @@ const config: Config = {
items: [
{
type: 'doc',
- docId: 'intro',
+ docId: 'intro/index',
activeBaseRegex: 'docs/(?!migrations|awesome)',
position: 'left',
label: 'Docs',
@@ -54,7 +63,6 @@ const config: Config = {
to: '/api',
label: 'API',
},
- { to: 'cookbook', label: 'Cookbook' },
],
},
{
@@ -96,7 +104,7 @@ const config: Config = {
},
{
label: 'Server setup',
- to: '/docs/administration/deployment/overview',
+ to: '/docs/administration/getting-started',
},
],
},
@@ -210,21 +218,6 @@ const config: Config = {
} as any;
},
}),
- [
- '@docusaurus/plugin-content-blog',
- {
- id: 'cookbook-blog',
- /**
- * URL route for the blog section of your site.
- * *DO NOT* include a trailing slash.
- */
- routeBasePath: 'cookbook',
- /**
- * Path to data on filesystem relative to site dir.
- */
- path: './cookbook',
- },
- ],
],
themes: [
path.resolve(__dirname, 'plugins', 'woodpecker-plugins', 'dist'),
@@ -243,25 +236,25 @@ const config: Config = {
sidebarPath: require.resolve('./sidebars.js'),
editUrl: 'https://github.com/woodpecker-ci/woodpecker/edit/main/docs/',
includeCurrentVersion: true,
- lastVersion: '2.6',
+ lastVersion: '2.7',
onlyIncludeVersions:
- process.env.NODE_ENV === 'development' ? ['current', '2.6'] : ['current', '2.6', '2.5', '2.4', '1.0'],
+ process.env.NODE_ENV === 'development' ? ['current', '2.7'] : ['current', '2.7', '2.6', '2.5', '1.0'],
versions: {
current: {
label: 'Next 🚧',
banner: 'unreleased',
},
+ '2.7': {
+ label: '2.7.x',
+ },
'2.6': {
- label: '2.6.x',
+ label: '2.6.x 💀',
+ banner: 'unmaintained',
},
'2.5': {
label: '2.5.x 💀',
banner: 'unmaintained',
},
- '2.4': {
- label: '2.4.x 💀',
- banner: 'unmaintained',
- },
'1.0': {
label: '1.0.x 💀',
banner: 'unmaintained',
@@ -271,6 +264,7 @@ const config: Config = {
blog: {
blogTitle: 'Blog',
blogDescription: 'A blog for release announcements, turorials...',
+ onInlineAuthors: 'ignore',
// postsPerPage: 'ALL',
// blogSidebarCount: 0,
},
diff --git a/docs/package.json b/docs/package.json
index a8a7aeaa3..7b7f17980 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -43,7 +43,7 @@
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.1.0",
- "@docusaurus/tsconfig": "3.4.0",
+ "@docusaurus/tsconfig": "3.5.2",
"@docusaurus/types": "^3.1.0",
"@types/node": "^20.11.30",
"@types/react": "^18.2.67",
@@ -53,7 +53,6 @@
},
"pnpm": {
"overrides": {
- "trim": "^1.0.0",
"got": "^14.0.0"
}
}
diff --git a/docs/plugins/woodpecker-plugins/package.json b/docs/plugins/woodpecker-plugins/package.json
index 993422e88..6e71e12ff 100644
--- a/docs/plugins/woodpecker-plugins/package.json
+++ b/docs/plugins/woodpecker-plugins/package.json
@@ -18,7 +18,7 @@
"axios": "^1.7.2",
"concurrently": "^8.2.2",
"isomorphic-dompurify": "^2.11.0",
- "marked": "^13.0.0",
+ "marked": "^14.0.0",
"tslib": "^2.6.2",
"typescript": "^5.4.5"
},
diff --git a/docs/pnpm-lock.yaml b/docs/pnpm-lock.yaml
index ab55be014..7ebe00841 100644
--- a/docs/pnpm-lock.yaml
+++ b/docs/pnpm-lock.yaml
@@ -5,7 +5,6 @@ settings:
excludeLinksFromLockfile: false
overrides:
- trim: ^1.0.0
got: ^14.0.0
importers:
@@ -14,31 +13,31 @@ importers:
dependencies:
'@docusaurus/core':
specifier: ^3.1.0
- version: 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(debug@4.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
+ version: 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(debug@4.3.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
'@docusaurus/plugin-content-blog':
specifier: ^3.1.0
- version: 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
+ version: 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
'@docusaurus/preset-classic':
specifier: ^3.1.0
- version: 3.4.0(@algolia/client-search@4.23.3)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.14.0)(typescript@5.4.5)
+ version: 3.5.2(@algolia/client-search@4.24.0)(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)(typescript@5.5.4)
'@easyops-cn/docusaurus-search-local':
specifier: ^0.44.0
- version: 0.44.0(@docusaurus/theme-common@3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5))(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
+ version: 0.44.5(@docusaurus/theme-common@3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
'@mdx-js/react':
specifier: ^3.0.0
version: 3.0.1(@types/react@18.3.3)(react@18.3.1)
'@svgr/webpack':
specifier: ^8.1.0
- version: 8.1.0(typescript@5.4.5)
+ version: 8.1.0(typescript@5.5.4)
clsx:
specifier: ^2.1.0
version: 2.1.1
esbuild-loader:
specifier: ^4.1.0
- version: 4.2.0(webpack@5.92.0)
+ version: 4.2.2(webpack@5.93.0)
file-loader:
specifier: ^6.2.0
- version: 6.2.0(webpack@5.92.0)
+ version: 6.2.0(webpack@5.93.0)
prism-react-renderer:
specifier: ^2.3.1
version: 2.3.1(react@18.3.1)
@@ -50,23 +49,23 @@ importers:
version: 18.3.1(react@18.3.1)
redocusaurus:
specifier: ^2.0.2
- version: 2.0.2(@docusaurus/theme-common@3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5))(@docusaurus/utils@3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5))(core-js@3.37.1)(mobx@6.12.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@6.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(webpack@5.92.0)
+ version: 2.1.1(@docusaurus/theme-common@3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/utils@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4))(core-js@3.38.0)(enzyme@3.11.0)(mobx@6.13.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@6.1.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(webpack@5.93.0)
url-loader:
specifier: ^4.1.1
- version: 4.1.1(file-loader@6.2.0(webpack@5.92.0))(webpack@5.92.0)
+ version: 4.1.1(file-loader@6.2.0(webpack@5.93.0))(webpack@5.93.0)
devDependencies:
'@docusaurus/module-type-aliases':
specifier: ^3.1.0
- version: 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ version: 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/tsconfig':
- specifier: 3.4.0
- version: 3.4.0
+ specifier: 3.5.2
+ version: 3.5.2
'@docusaurus/types':
specifier: ^3.1.0
- version: 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ version: 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@types/node':
specifier: ^20.11.30
- version: 20.14.5
+ version: 20.14.15
'@types/react':
specifier: ^18.2.67
version: 18.3.3
@@ -78,7 +77,7 @@ importers:
version: 5.3.3
typescript:
specifier: ^5.4.3
- version: 5.4.5
+ version: 5.5.4
plugins/woodpecker-plugins:
dependencies:
@@ -93,41 +92,41 @@ importers:
version: 18.3.1(react@18.3.1)
yaml:
specifier: ^2.4.2
- version: 2.4.5
+ version: 2.5.0
devDependencies:
'@docusaurus/module-type-aliases':
specifier: ^3.3.2
- version: 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ version: 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@docusaurus/theme-classic':
specifier: ^3.3.2
- version: 3.4.0(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
+ version: 3.5.2(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
'@docusaurus/types':
specifier: ^3.3.2
- version: 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ version: 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@tsconfig/docusaurus':
specifier: ^2.0.3
version: 2.0.3
'@types/node':
specifier: ^20.12.13
- version: 20.14.5
+ version: 20.14.15
axios:
specifier: ^1.7.2
- version: 1.7.2
+ version: 1.7.4
concurrently:
specifier: ^8.2.2
version: 8.2.2
isomorphic-dompurify:
specifier: ^2.11.0
- version: 2.12.0
+ version: 2.14.0
marked:
- specifier: ^13.0.0
- version: 13.0.0
+ specifier: ^14.0.0
+ version: 14.0.0
tslib:
specifier: ^2.6.2
version: 2.6.3
typescript:
specifier: ^5.4.5
- version: 5.4.5
+ version: 5.5.4
packages:
@@ -151,53 +150,53 @@ packages:
'@algolia/client-search': '>= 4.9.1 < 6'
algoliasearch: '>= 4.9.1 < 6'
- '@algolia/cache-browser-local-storage@4.23.3':
- resolution: {integrity: sha512-vRHXYCpPlTDE7i6UOy2xE03zHF2C8MEFjPN2v7fRbqVpcOvAUQK81x3Kc21xyb5aSIpYCjWCZbYZuz8Glyzyyg==}
+ '@algolia/cache-browser-local-storage@4.24.0':
+ resolution: {integrity: sha512-t63W9BnoXVrGy9iYHBgObNXqYXM3tYXCjDSHeNwnsc324r4o5UiVKUiAB4THQ5z9U5hTj6qUvwg/Ez43ZD85ww==}
- '@algolia/cache-common@4.23.3':
- resolution: {integrity: sha512-h9XcNI6lxYStaw32pHpB1TMm0RuxphF+Ik4o7tcQiodEdpKK+wKufY6QXtba7t3k8eseirEMVB83uFFF3Nu54A==}
+ '@algolia/cache-common@4.24.0':
+ resolution: {integrity: sha512-emi+v+DmVLpMGhp0V9q9h5CdkURsNmFC+cOS6uK9ndeJm9J4TiqSvPYVu+THUP8P/S08rxf5x2P+p3CfID0Y4g==}
- '@algolia/cache-in-memory@4.23.3':
- resolution: {integrity: sha512-yvpbuUXg/+0rbcagxNT7un0eo3czx2Uf0y4eiR4z4SD7SiptwYTpbuS0IHxcLHG3lq22ukx1T6Kjtk/rT+mqNg==}
+ '@algolia/cache-in-memory@4.24.0':
+ resolution: {integrity: sha512-gDrt2so19jW26jY3/MkFg5mEypFIPbPoXsQGQWAi6TrCPsNOSEYepBMPlucqWigsmEy/prp5ug2jy/N3PVG/8w==}
- '@algolia/client-account@4.23.3':
- resolution: {integrity: sha512-hpa6S5d7iQmretHHF40QGq6hz0anWEHGlULcTIT9tbUssWUriN9AUXIFQ8Ei4w9azD0hc1rUok9/DeQQobhQMA==}
+ '@algolia/client-account@4.24.0':
+ resolution: {integrity: sha512-adcvyJ3KjPZFDybxlqnf+5KgxJtBjwTPTeyG2aOyoJvx0Y8dUQAEOEVOJ/GBxX0WWNbmaSrhDURMhc+QeevDsA==}
- '@algolia/client-analytics@4.23.3':
- resolution: {integrity: sha512-LBsEARGS9cj8VkTAVEZphjxTjMVCci+zIIiRhpFun9jGDUlS1XmhCW7CTrnaWeIuCQS/2iPyRqSy1nXPjcBLRA==}
+ '@algolia/client-analytics@4.24.0':
+ resolution: {integrity: sha512-y8jOZt1OjwWU4N2qr8G4AxXAzaa8DBvyHTWlHzX/7Me1LX8OayfgHexqrsL4vSBcoMmVw2XnVW9MhL+Y2ZDJXg==}
- '@algolia/client-common@4.23.3':
- resolution: {integrity: sha512-l6EiPxdAlg8CYhroqS5ybfIczsGUIAC47slLPOMDeKSVXYG1n0qGiz4RjAHLw2aD0xzh2EXZ7aRguPfz7UKDKw==}
+ '@algolia/client-common@4.24.0':
+ resolution: {integrity: sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==}
- '@algolia/client-personalization@4.23.3':
- resolution: {integrity: sha512-3E3yF3Ocr1tB/xOZiuC3doHQBQ2zu2MPTYZ0d4lpfWads2WTKG7ZzmGnsHmm63RflvDeLK/UVx7j2b3QuwKQ2g==}
+ '@algolia/client-personalization@4.24.0':
+ resolution: {integrity: sha512-l5FRFm/yngztweU0HdUzz1rC4yoWCFo3IF+dVIVTfEPg906eZg5BOd1k0K6rZx5JzyyoP4LdmOikfkfGsKVE9w==}
- '@algolia/client-search@4.23.3':
- resolution: {integrity: sha512-P4VAKFHqU0wx9O+q29Q8YVuaowaZ5EM77rxfmGnkHUJggh28useXQdopokgwMeYw2XUht49WX5RcTQ40rZIabw==}
+ '@algolia/client-search@4.24.0':
+ resolution: {integrity: sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==}
'@algolia/events@4.0.1':
resolution: {integrity: sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==}
- '@algolia/logger-common@4.23.3':
- resolution: {integrity: sha512-y9kBtmJwiZ9ZZ+1Ek66P0M68mHQzKRxkW5kAAXYN/rdzgDN0d2COsViEFufxJ0pb45K4FRcfC7+33YB4BLrZ+g==}
+ '@algolia/logger-common@4.24.0':
+ resolution: {integrity: sha512-LLUNjkahj9KtKYrQhFKCzMx0BY3RnNP4FEtO+sBybCjJ73E8jNdaKJ/Dd8A/VA4imVHP5tADZ8pn5B8Ga/wTMA==}
- '@algolia/logger-console@4.23.3':
- resolution: {integrity: sha512-8xoiseoWDKuCVnWP8jHthgaeobDLolh00KJAdMe9XPrWPuf1by732jSpgy2BlsLTaT9m32pHI8CRfrOqQzHv3A==}
+ '@algolia/logger-console@4.24.0':
+ resolution: {integrity: sha512-X4C8IoHgHfiUROfoRCV+lzSy+LHMgkoEEU1BbKcsfnV0i0S20zyy0NLww9dwVHUWNfPPxdMU+/wKmLGYf96yTg==}
- '@algolia/recommend@4.23.3':
- resolution: {integrity: sha512-9fK4nXZF0bFkdcLBRDexsnGzVmu4TSYZqxdpgBW2tEyfuSSY54D4qSRkLmNkrrz4YFvdh2GM1gA8vSsnZPR73w==}
+ '@algolia/recommend@4.24.0':
+ resolution: {integrity: sha512-P9kcgerfVBpfYHDfVZDvvdJv0lEoCvzNlOy2nykyt5bK8TyieYyiD0lguIJdRZZYGre03WIAFf14pgE+V+IBlw==}
- '@algolia/requester-browser-xhr@4.23.3':
- resolution: {integrity: sha512-jDWGIQ96BhXbmONAQsasIpTYWslyjkiGu0Quydjlowe+ciqySpiDUrJHERIRfELE5+wFc7hc1Q5hqjGoV7yghw==}
+ '@algolia/requester-browser-xhr@4.24.0':
+ resolution: {integrity: sha512-Z2NxZMb6+nVXSjF13YpjYTdvV3032YTBSGm2vnYvYPA6mMxzM3v5rsCiSspndn9rzIW4Qp1lPHBvuoKJV6jnAA==}
- '@algolia/requester-common@4.23.3':
- resolution: {integrity: sha512-xloIdr/bedtYEGcXCiF2muajyvRhwop4cMZo+K2qzNht0CMzlRkm8YsDdj5IaBhshqfgmBb3rTg4sL4/PpvLYw==}
+ '@algolia/requester-common@4.24.0':
+ resolution: {integrity: sha512-k3CXJ2OVnvgE3HMwcojpvY6d9kgKMPRxs/kVohrwF5WMr2fnqojnycZkxPoEg+bXm8fi5BBfFmOqgYztRtHsQA==}
- '@algolia/requester-node-http@4.23.3':
- resolution: {integrity: sha512-zgu++8Uj03IWDEJM3fuNl34s746JnZOWn1Uz5taV1dFyJhVM/kTNw9Ik7YJWiUNHJQXcaD8IXD1eCb0nq/aByA==}
+ '@algolia/requester-node-http@4.24.0':
+ resolution: {integrity: sha512-JF18yTjNOVYvU/L3UosRcvbPMGT9B+/GQWNWnenIImglzNVGpyzChkXLnrSf6uxwVNO6ESGu6oN8MqcGQcjQJw==}
- '@algolia/transporter@4.23.3':
- resolution: {integrity: sha512-Wjl5gttqnf/gQKJA+dafnD0Y6Yw97yvfY8R9h0dQltX1GXTgNs1zWgvtWW0tHl1EgMdhAyw189uWiZMnL3QebQ==}
+ '@algolia/transporter@4.24.0':
+ resolution: {integrity: sha512-86nI7w6NzWxd1Zp9q3413dRshDqAzSbsQjhcDhPIatEFiZrL1/TjnHL8S7jVKFePlIMzDsZWXAXwXzcok9c5oA==}
'@ampproject/remapping@2.3.0':
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
@@ -207,16 +206,16 @@ packages:
resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==}
engines: {node: '>=6.9.0'}
- '@babel/compat-data@7.24.7':
- resolution: {integrity: sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==}
+ '@babel/compat-data@7.25.2':
+ resolution: {integrity: sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==}
engines: {node: '>=6.9.0'}
- '@babel/core@7.24.7':
- resolution: {integrity: sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==}
+ '@babel/core@7.25.2':
+ resolution: {integrity: sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==}
engines: {node: '>=6.9.0'}
- '@babel/generator@7.24.7':
- resolution: {integrity: sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==}
+ '@babel/generator@7.25.0':
+ resolution: {integrity: sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==}
engines: {node: '>=6.9.0'}
'@babel/helper-annotate-as-pure@7.24.7':
@@ -227,18 +226,18 @@ packages:
resolution: {integrity: sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==}
engines: {node: '>=6.9.0'}
- '@babel/helper-compilation-targets@7.24.7':
- resolution: {integrity: sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==}
+ '@babel/helper-compilation-targets@7.25.2':
+ resolution: {integrity: sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==}
engines: {node: '>=6.9.0'}
- '@babel/helper-create-class-features-plugin@7.24.7':
- resolution: {integrity: sha512-kTkaDl7c9vO80zeX1rJxnuRpEsD5tA81yh11X1gQo+PhSti3JS+7qeZo9U4RHobKRiFPKaGK3svUAeb8D0Q7eg==}
+ '@babel/helper-create-class-features-plugin@7.25.0':
+ resolution: {integrity: sha512-GYM6BxeQsETc9mnct+nIIpf63SAyzvyYN7UB/IlTyd+MBg06afFGp0mIeUqGyWgS2mxad6vqbMrHVlaL3m70sQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
- '@babel/helper-create-regexp-features-plugin@7.24.7':
- resolution: {integrity: sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==}
+ '@babel/helper-create-regexp-features-plugin@7.25.2':
+ resolution: {integrity: sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
@@ -248,28 +247,16 @@ packages:
peerDependencies:
'@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
- '@babel/helper-environment-visitor@7.24.7':
- resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-function-name@7.24.7':
- resolution: {integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-hoist-variables@7.24.7':
- resolution: {integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-member-expression-to-functions@7.24.7':
- resolution: {integrity: sha512-LGeMaf5JN4hAT471eJdBs/GK1DoYIJ5GCtZN/EsL6KUiiDZOvO/eKE11AMZJa2zP4zk4qe9V2O/hxAmkRc8p6w==}
+ '@babel/helper-member-expression-to-functions@7.24.8':
+ resolution: {integrity: sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==}
engines: {node: '>=6.9.0'}
'@babel/helper-module-imports@7.24.7':
resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==}
engines: {node: '>=6.9.0'}
- '@babel/helper-module-transforms@7.24.7':
- resolution: {integrity: sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==}
+ '@babel/helper-module-transforms@7.25.2':
+ resolution: {integrity: sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
@@ -278,18 +265,18 @@ packages:
resolution: {integrity: sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==}
engines: {node: '>=6.9.0'}
- '@babel/helper-plugin-utils@7.24.7':
- resolution: {integrity: sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==}
+ '@babel/helper-plugin-utils@7.24.8':
+ resolution: {integrity: sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==}
engines: {node: '>=6.9.0'}
- '@babel/helper-remap-async-to-generator@7.24.7':
- resolution: {integrity: sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==}
+ '@babel/helper-remap-async-to-generator@7.25.0':
+ resolution: {integrity: sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
- '@babel/helper-replace-supers@7.24.7':
- resolution: {integrity: sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==}
+ '@babel/helper-replace-supers@7.25.0':
+ resolution: {integrity: sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
@@ -302,47 +289,55 @@ packages:
resolution: {integrity: sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==}
engines: {node: '>=6.9.0'}
- '@babel/helper-split-export-declaration@7.24.7':
- resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-string-parser@7.24.7':
- resolution: {integrity: sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==}
+ '@babel/helper-string-parser@7.24.8':
+ resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==}
engines: {node: '>=6.9.0'}
'@babel/helper-validator-identifier@7.24.7':
resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==}
engines: {node: '>=6.9.0'}
- '@babel/helper-validator-option@7.24.7':
- resolution: {integrity: sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==}
+ '@babel/helper-validator-option@7.24.8':
+ resolution: {integrity: sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==}
engines: {node: '>=6.9.0'}
- '@babel/helper-wrap-function@7.24.7':
- resolution: {integrity: sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==}
+ '@babel/helper-wrap-function@7.25.0':
+ resolution: {integrity: sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ==}
engines: {node: '>=6.9.0'}
- '@babel/helpers@7.24.7':
- resolution: {integrity: sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==}
+ '@babel/helpers@7.25.0':
+ resolution: {integrity: sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==}
engines: {node: '>=6.9.0'}
'@babel/highlight@7.24.7':
resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==}
engines: {node: '>=6.9.0'}
- '@babel/parser@7.24.7':
- resolution: {integrity: sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==}
+ '@babel/parser@7.25.3':
+ resolution: {integrity: sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==}
engines: {node: '>=6.0.0'}
hasBin: true
- '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.7':
- resolution: {integrity: sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==}
+ '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.0':
+ resolution: {integrity: sha512-dG0aApncVQwAUJa8tP1VHTnmU67BeIQvKafd3raEx315H54FfkZSz3B/TT+33ZQAjatGJA79gZqTtqL5QZUKXw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
- '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.7':
- resolution: {integrity: sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==}
+ '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.3':
+ resolution: {integrity: sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
+ '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.0':
+ resolution: {integrity: sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
+ '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.0':
+ resolution: {integrity: sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
@@ -353,8 +348,8 @@ packages:
peerDependencies:
'@babel/core': ^7.13.0
- '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.7':
- resolution: {integrity: sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==}
+ '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.0':
+ resolution: {integrity: sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
@@ -479,8 +474,8 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-async-generator-functions@7.24.7':
- resolution: {integrity: sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==}
+ '@babel/plugin-transform-async-generator-functions@7.25.0':
+ resolution: {integrity: sha512-uaIi2FdqzjpAMvVqvB51S42oC2JEVgh0LDsGfZVDysWE8LrJtQC2jvKmOqEYThKyB7bDEb7BP1GYWDm7tABA0Q==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
@@ -497,8 +492,8 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-block-scoping@7.24.7':
- resolution: {integrity: sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==}
+ '@babel/plugin-transform-block-scoping@7.25.0':
+ resolution: {integrity: sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
@@ -515,8 +510,8 @@ packages:
peerDependencies:
'@babel/core': ^7.12.0
- '@babel/plugin-transform-classes@7.24.7':
- resolution: {integrity: sha512-CFbbBigp8ln4FU6Bpy6g7sE8B/WmCmzvivzUC6xDAdWVsjYTXijpuuGJmYkAaoWAzcItGKT3IOAbxRItZ5HTjw==}
+ '@babel/plugin-transform-classes@7.25.0':
+ resolution: {integrity: sha512-xyi6qjr/fYU304fiRwFbekzkqVJZ6A7hOjWZd+89FVcBqPV3S9Wuozz82xdpLspckeaafntbzglaW4pqpzvtSw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
@@ -527,8 +522,8 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-destructuring@7.24.7':
- resolution: {integrity: sha512-19eJO/8kdCQ9zISOf+SEUJM/bAUIsvY3YDnXZTupUCQ8LgrWnsG/gFB9dvXqdXnRXMAM8fvt7b0CBKQHNGy1mw==}
+ '@babel/plugin-transform-destructuring@7.24.8':
+ resolution: {integrity: sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
@@ -545,6 +540,12 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
+ '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.0':
+ resolution: {integrity: sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
'@babel/plugin-transform-dynamic-import@7.24.7':
resolution: {integrity: sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==}
engines: {node: '>=6.9.0'}
@@ -569,8 +570,8 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-function-name@7.24.7':
- resolution: {integrity: sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==}
+ '@babel/plugin-transform-function-name@7.25.1':
+ resolution: {integrity: sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
@@ -581,8 +582,8 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-literals@7.24.7':
- resolution: {integrity: sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==}
+ '@babel/plugin-transform-literals@7.25.2':
+ resolution: {integrity: sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
@@ -605,14 +606,14 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-modules-commonjs@7.24.7':
- resolution: {integrity: sha512-iFI8GDxtevHJ/Z22J5xQpVqFLlMNstcLXh994xifFwxxGslr2ZXXLWgtBeLctOD63UFDArdvN6Tg8RFw+aEmjQ==}
+ '@babel/plugin-transform-modules-commonjs@7.24.8':
+ resolution: {integrity: sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-modules-systemjs@7.24.7':
- resolution: {integrity: sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==}
+ '@babel/plugin-transform-modules-systemjs@7.25.0':
+ resolution: {integrity: sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
@@ -665,8 +666,8 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-optional-chaining@7.24.7':
- resolution: {integrity: sha512-tK+0N9yd4j+x/4hxF3F0e0fu/VdcxU18y5SevtyM/PCFlQvXbR0Zmlo2eBrKtVipGNFzpq56o8WsIIKcJFUCRQ==}
+ '@babel/plugin-transform-optional-chaining@7.24.8':
+ resolution: {integrity: sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
@@ -695,8 +696,8 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-react-constant-elements@7.24.7':
- resolution: {integrity: sha512-7LidzZfUXyfZ8/buRW6qIIHBY8wAZ1OrY9c/wTr8YhZ6vMPo+Uc/CVFLYY1spZrEQlD4w5u8wjqk5NQ3OVqQKA==}
+ '@babel/plugin-transform-react-constant-elements@7.25.1':
+ resolution: {integrity: sha512-SLV/giH/V4SmloZ6Dt40HjTGTAIkxn33TVIHxNGNvo8ezMhrxBkzisj4op1KZYPIOHFLqhv60OHvX+YRu4xbmQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
@@ -713,8 +714,8 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-react-jsx@7.24.7':
- resolution: {integrity: sha512-+Dj06GDZEFRYvclU6k4bme55GKBEWUmByM/eoKuqg4zTNQHiApWRhQph5fxQB2wAEFvRzL1tOEj1RJ19wJrhoA==}
+ '@babel/plugin-transform-react-jsx@7.25.2':
+ resolution: {integrity: sha512-KQsqEAVBpU82NM/B/N9j9WOdphom1SZH3R+2V7INrQUH+V9EBFwZsEJl8eBIVeQE62FxJCc70jzEZwqU7RcVqA==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
@@ -767,14 +768,14 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-typeof-symbol@7.24.7':
- resolution: {integrity: sha512-VtR8hDy7YLB7+Pet9IarXjg/zgCMSF+1mNS/EQEiEaUPoFXCVsHG64SIxcaaI2zJgRiv+YmgaQESUfWAdbjzgg==}
+ '@babel/plugin-transform-typeof-symbol@7.24.8':
+ resolution: {integrity: sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-typescript@7.24.7':
- resolution: {integrity: sha512-iLD3UNkgx2n/HrjBesVbYX6j0yqn/sJktvbtKKgcaLIQ4bTTQ8obAypc1VpyHPD2y4Phh9zHOaAt8e/L14wCpw==}
+ '@babel/plugin-transform-typescript@7.25.2':
+ resolution: {integrity: sha512-lBwRvjSmqiMYe/pS0+1gggjJleUJi7NzjvQ1Fkqtt69hBa/0t1YuW/MLQMAPixfwaQOHUXsd6jeU3Z+vdGv3+A==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
@@ -803,8 +804,14 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0
- '@babel/preset-env@7.24.7':
- resolution: {integrity: sha512-1YZNsc+y6cTvWlDHidMBsQZrZfEFjRIo/BZCT906PMdzOyXtSLTgqGdrpcuTDCXyd11Am5uQULtDIcCfnTc8fQ==}
+ '@babel/preset-env@7.25.2':
+ resolution: {integrity: sha512-Y2Vkwy3ITW4id9c6KXshVV/x5yCGK7VdJmKkzOzNsDZMojRKfSA/033rRbLqlRozmhRXCejxWHLSJOg/wUHfzw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/preset-env@7.25.3':
+ resolution: {integrity: sha512-QsYW7UeAaXvLPX9tdVliMJE7MD7M6MLYVTovRTIwhoYQVFHR1rM4wO8wqAezYi3/BpSD+NzVCZ69R6smWiIi8g==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
@@ -829,26 +836,33 @@ packages:
'@babel/regjsgen@0.8.0':
resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==}
- '@babel/runtime-corejs3@7.24.7':
- resolution: {integrity: sha512-eytSX6JLBY6PVAeQa2bFlDx/7Mmln/gaEpsit5a3WEvjGfiIytEsgAwuIXCPM0xvw0v0cJn3ilq0/TvXrW0kgA==}
+ '@babel/runtime-corejs3@7.25.0':
+ resolution: {integrity: sha512-BOehWE7MgQ8W8Qn0CQnMtg2tHPHPulcS/5AVpFvs2KCK1ET+0WqZqPvnpRpFN81gYoFopdIEJX9Sgjw3ZBccPg==}
engines: {node: '>=6.9.0'}
- '@babel/runtime@7.24.7':
- resolution: {integrity: sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==}
+ '@babel/runtime@7.25.0':
+ resolution: {integrity: sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==}
engines: {node: '>=6.9.0'}
- '@babel/template@7.24.7':
- resolution: {integrity: sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==}
+ '@babel/template@7.25.0':
+ resolution: {integrity: sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==}
engines: {node: '>=6.9.0'}
- '@babel/traverse@7.24.7':
- resolution: {integrity: sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==}
+ '@babel/traverse@7.25.3':
+ resolution: {integrity: sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==}
engines: {node: '>=6.9.0'}
- '@babel/types@7.24.7':
- resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==}
+ '@babel/types@7.25.2':
+ resolution: {integrity: sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==}
engines: {node: '>=6.9.0'}
+ '@cfaester/enzyme-adapter-react-18@0.8.0':
+ resolution: {integrity: sha512-3Z3ThTUouHwz8oIyhTYQljEMNRFtlVyc3VOOHCbxs47U6cnXs8K9ygi/c1tv49s7MBlTXeIcuN+Ttd9aPtILFQ==}
+ peerDependencies:
+ enzyme: ^3.11.0
+ react: '>=18'
+ react-dom: '>=18'
+
'@colors/colors@1.5.0':
resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
engines: {node: '>=0.1.90'}
@@ -857,11 +871,11 @@ packages:
resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==}
engines: {node: '>=10.0.0'}
- '@docsearch/css@3.6.0':
- resolution: {integrity: sha512-+sbxb71sWre+PwDK7X2T8+bhS6clcVMLwBPznX45Qu6opJcgRjAp7gYSDzVFp187J+feSj5dNBN1mJoi6ckkUQ==}
+ '@docsearch/css@3.6.1':
+ resolution: {integrity: sha512-VtVb5DS+0hRIprU2CO6ZQjK2Zg4QU5HrDM1+ix6rT0umsYvFvatMAnf97NHZlVWDaaLlx7GRfR/7FikANiM2Fg==}
- '@docsearch/react@3.6.0':
- resolution: {integrity: sha512-HUFut4ztcVNmqy9gp/wxNbC7pTOHhgVVkHVGCACTuLhUKUhKAF9KYHJtMiLUJxEqiFLQiuri1fWF8zqwM/cu1w==}
+ '@docsearch/react@3.6.1':
+ resolution: {integrity: sha512-qXZkEPvybVhSXj0K7U3bXc233tk5e8PfhoZ6MhPOiik/qUQxYC+Dn9DnoS7CxHQQhHfCvTiN0eY9M12oRghEXw==}
peerDependencies:
'@types/react': '>= 16.8.0 < 19.0.0'
react: '>= 16.8.0 < 19.0.0'
@@ -877,93 +891,95 @@ packages:
search-insights:
optional: true
- '@docusaurus/core@3.4.0':
- resolution: {integrity: sha512-g+0wwmN2UJsBqy2fQRQ6fhXruoEa62JDeEa5d8IdTJlMoaDaEDfHh7WjwGRn4opuTQWpjAwP/fbcgyHKlE+64w==}
+ '@docusaurus/core@3.5.2':
+ resolution: {integrity: sha512-4Z1WkhCSkX4KO0Fw5m/Vuc7Q3NxBG53NE5u59Rs96fWkMPZVSrzEPP16/Nk6cWb/shK7xXPndTmalJtw7twL/w==}
engines: {node: '>=18.0'}
hasBin: true
peerDependencies:
+ '@mdx-js/react': ^3.0.0
react: ^18.0.0
react-dom: ^18.0.0
- '@docusaurus/cssnano-preset@3.4.0':
- resolution: {integrity: sha512-qwLFSz6v/pZHy/UP32IrprmH5ORce86BGtN0eBtG75PpzQJAzp9gefspox+s8IEOr0oZKuQ/nhzZ3xwyc3jYJQ==}
+ '@docusaurus/cssnano-preset@3.5.2':
+ resolution: {integrity: sha512-D3KiQXOMA8+O0tqORBrTOEQyQxNIfPm9jEaJoALjjSjc2M/ZAWcUfPQEnwr2JB2TadHw2gqWgpZckQmrVWkytA==}
engines: {node: '>=18.0'}
- '@docusaurus/logger@3.4.0':
- resolution: {integrity: sha512-bZwkX+9SJ8lB9kVRkXw+xvHYSMGG4bpYHKGXeXFvyVc79NMeeBSGgzd4TQLHH+DYeOJoCdl8flrFJVxlZ0wo/Q==}
+ '@docusaurus/logger@3.5.2':
+ resolution: {integrity: sha512-LHC540SGkeLfyT3RHK3gAMK6aS5TRqOD4R72BEU/DE2M/TY8WwEUAMY576UUc/oNJXv8pGhBmQB6N9p3pt8LQw==}
engines: {node: '>=18.0'}
- '@docusaurus/mdx-loader@3.4.0':
- resolution: {integrity: sha512-kSSbrrk4nTjf4d+wtBA9H+FGauf2gCax89kV8SUSJu3qaTdSIKdWERlngsiHaCFgZ7laTJ8a67UFf+xlFPtuTw==}
+ '@docusaurus/mdx-loader@3.5.2':
+ resolution: {integrity: sha512-ku3xO9vZdwpiMIVd8BzWV0DCqGEbCP5zs1iHfKX50vw6jX8vQo0ylYo1YJMZyz6e+JFJ17HYHT5FzVidz2IflA==}
engines: {node: '>=18.0'}
peerDependencies:
react: ^18.0.0
react-dom: ^18.0.0
- '@docusaurus/module-type-aliases@3.4.0':
- resolution: {integrity: sha512-A1AyS8WF5Bkjnb8s+guTDuYmUiwJzNrtchebBHpc0gz0PyHJNMaybUlSrmJjHVcGrya0LKI4YcR3lBDQfXRYLw==}
+ '@docusaurus/module-type-aliases@3.5.2':
+ resolution: {integrity: sha512-Z+Xu3+2rvKef/YKTMxZHsEXp1y92ac0ngjDiExRdqGTmEKtCUpkbNYH8v5eXo5Ls+dnW88n6WTa+Q54kLOkwPg==}
peerDependencies:
react: '*'
react-dom: '*'
- '@docusaurus/plugin-content-blog@3.4.0':
- resolution: {integrity: sha512-vv6ZAj78ibR5Jh7XBUT4ndIjmlAxkijM3Sx5MAAzC1gyv0vupDQNhzuFg1USQmQVj3P5I6bquk12etPV3LJ+Xw==}
+ '@docusaurus/plugin-content-blog@3.5.2':
+ resolution: {integrity: sha512-R7ghWnMvjSf+aeNDH0K4fjyQnt5L0KzUEnUhmf1e3jZrv3wogeytZNN6n7X8yHcMsuZHPOrctQhXWnmxu+IRRg==}
+ engines: {node: '>=18.0'}
+ peerDependencies:
+ '@docusaurus/plugin-content-docs': '*'
+ react: ^18.0.0
+ react-dom: ^18.0.0
+
+ '@docusaurus/plugin-content-docs@3.5.2':
+ resolution: {integrity: sha512-Bt+OXn/CPtVqM3Di44vHjE7rPCEsRCB/DMo2qoOuozB9f7+lsdrHvD0QCHdBs0uhz6deYJDppAr2VgqybKPlVQ==}
engines: {node: '>=18.0'}
peerDependencies:
react: ^18.0.0
react-dom: ^18.0.0
- '@docusaurus/plugin-content-docs@3.4.0':
- resolution: {integrity: sha512-HkUCZffhBo7ocYheD9oZvMcDloRnGhBMOZRyVcAQRFmZPmNqSyISlXA1tQCIxW+r478fty97XXAGjNYzBjpCsg==}
+ '@docusaurus/plugin-content-pages@3.5.2':
+ resolution: {integrity: sha512-WzhHjNpoQAUz/ueO10cnundRz+VUtkjFhhaQ9jApyv1a46FPURO4cef89pyNIOMny1fjDz/NUN2z6Yi+5WUrCw==}
engines: {node: '>=18.0'}
peerDependencies:
react: ^18.0.0
react-dom: ^18.0.0
- '@docusaurus/plugin-content-pages@3.4.0':
- resolution: {integrity: sha512-h2+VN/0JjpR8fIkDEAoadNjfR3oLzB+v1qSXbIAKjQ46JAHx3X22n9nqS+BWSQnTnp1AjkjSvZyJMekmcwxzxg==}
+ '@docusaurus/plugin-debug@3.5.2':
+ resolution: {integrity: sha512-kBK6GlN0itCkrmHuCS6aX1wmoWc5wpd5KJlqQ1FyrF0cLDnvsYSnh7+ftdwzt7G6lGBho8lrVwkkL9/iQvaSOA==}
engines: {node: '>=18.0'}
peerDependencies:
react: ^18.0.0
react-dom: ^18.0.0
- '@docusaurus/plugin-debug@3.4.0':
- resolution: {integrity: sha512-uV7FDUNXGyDSD3PwUaf5YijX91T5/H9SX4ErEcshzwgzWwBtK37nUWPU3ZLJfeTavX3fycTOqk9TglpOLaWkCg==}
+ '@docusaurus/plugin-google-analytics@3.5.2':
+ resolution: {integrity: sha512-rjEkJH/tJ8OXRE9bwhV2mb/WP93V441rD6XnM6MIluu7rk8qg38iSxS43ga2V2Q/2ib53PcqbDEJDG/yWQRJhQ==}
engines: {node: '>=18.0'}
peerDependencies:
react: ^18.0.0
react-dom: ^18.0.0
- '@docusaurus/plugin-google-analytics@3.4.0':
- resolution: {integrity: sha512-mCArluxEGi3cmYHqsgpGGt3IyLCrFBxPsxNZ56Mpur0xSlInnIHoeLDH7FvVVcPJRPSQ9/MfRqLsainRw+BojA==}
+ '@docusaurus/plugin-google-gtag@3.5.2':
+ resolution: {integrity: sha512-lm8XL3xLkTPHFKKjLjEEAHUrW0SZBSHBE1I+i/tmYMBsjCcUB5UJ52geS5PSiOCFVR74tbPGcPHEV/gaaxFeSA==}
engines: {node: '>=18.0'}
peerDependencies:
react: ^18.0.0
react-dom: ^18.0.0
- '@docusaurus/plugin-google-gtag@3.4.0':
- resolution: {integrity: sha512-Dsgg6PLAqzZw5wZ4QjUYc8Z2KqJqXxHxq3vIoyoBWiLEEfigIs7wHR+oiWUQy3Zk9MIk6JTYj7tMoQU0Jm3nqA==}
+ '@docusaurus/plugin-google-tag-manager@3.5.2':
+ resolution: {integrity: sha512-QkpX68PMOMu10Mvgvr5CfZAzZQFx8WLlOiUQ/Qmmcl6mjGK6H21WLT5x7xDmcpCoKA/3CegsqIqBR+nA137lQg==}
engines: {node: '>=18.0'}
peerDependencies:
react: ^18.0.0
react-dom: ^18.0.0
- '@docusaurus/plugin-google-tag-manager@3.4.0':
- resolution: {integrity: sha512-O9tX1BTwxIhgXpOLpFDueYA9DWk69WCbDRrjYoMQtFHSkTyE7RhNgyjSPREUWJb9i+YUg3OrsvrBYRl64FCPCQ==}
+ '@docusaurus/plugin-sitemap@3.5.2':
+ resolution: {integrity: sha512-DnlqYyRAdQ4NHY28TfHuVk414ft2uruP4QWCH//jzpHjqvKyXjj2fmDtI8RPUBh9K8iZKFMHRnLtzJKySPWvFA==}
engines: {node: '>=18.0'}
peerDependencies:
react: ^18.0.0
react-dom: ^18.0.0
- '@docusaurus/plugin-sitemap@3.4.0':
- resolution: {integrity: sha512-+0VDvx9SmNrFNgwPoeoCha+tRoAjopwT0+pYO1xAbyLcewXSemq+eLxEa46Q1/aoOaJQ0qqHELuQM7iS2gp33Q==}
- engines: {node: '>=18.0'}
- peerDependencies:
- react: ^18.0.0
- react-dom: ^18.0.0
-
- '@docusaurus/preset-classic@3.4.0':
- resolution: {integrity: sha512-Ohj6KB7siKqZaQhNJVMBBUzT3Nnp6eTKqO+FXO3qu/n1hJl3YLwVKTWBg28LF7MWrKu46UuYavwMRxud0VyqHg==}
+ '@docusaurus/preset-classic@3.5.2':
+ resolution: {integrity: sha512-3ihfXQ95aOHiLB5uCu+9PRy2gZCeSZoDcqpnDvf3B+sTrMvMTr8qRUzBvWkoIqc82yG5prCboRjk1SVILKx6sg==}
engines: {node: '>=18.0'}
peerDependencies:
react: ^18.0.0
@@ -974,42 +990,43 @@ packages:
peerDependencies:
react: '*'
- '@docusaurus/theme-classic@3.4.0':
- resolution: {integrity: sha512-0IPtmxsBYv2adr1GnZRdMkEQt1YW6tpzrUPj02YxNpvJ5+ju4E13J5tB4nfdaen/tfR1hmpSPlTFPvTf4kwy8Q==}
+ '@docusaurus/theme-classic@3.5.2':
+ resolution: {integrity: sha512-XRpinSix3NBv95Rk7xeMF9k4safMkwnpSgThn0UNQNumKvmcIYjfkwfh2BhwYh/BxMXQHJ/PdmNh22TQFpIaYg==}
engines: {node: '>=18.0'}
peerDependencies:
react: ^18.0.0
react-dom: ^18.0.0
- '@docusaurus/theme-common@3.4.0':
- resolution: {integrity: sha512-0A27alXuv7ZdCg28oPE8nH/Iz73/IUejVaCazqu9elS4ypjiLhK3KfzdSQBnL/g7YfHSlymZKdiOHEo8fJ0qMA==}
+ '@docusaurus/theme-common@3.5.2':
+ resolution: {integrity: sha512-QXqlm9S6x9Ibwjs7I2yEDgsCocp708DrCrgHgKwg2n2AY0YQ6IjU0gAK35lHRLOvAoJUfCKpQAwUykB0R7+Eew==}
+ engines: {node: '>=18.0'}
+ peerDependencies:
+ '@docusaurus/plugin-content-docs': '*'
+ react: ^18.0.0
+ react-dom: ^18.0.0
+
+ '@docusaurus/theme-search-algolia@3.5.2':
+ resolution: {integrity: sha512-qW53kp3VzMnEqZGjakaV90sst3iN1o32PH+nawv1uepROO8aEGxptcq2R5rsv7aBShSRbZwIobdvSYKsZ5pqvA==}
engines: {node: '>=18.0'}
peerDependencies:
react: ^18.0.0
react-dom: ^18.0.0
- '@docusaurus/theme-search-algolia@3.4.0':
- resolution: {integrity: sha512-aiHFx7OCw4Wck1z6IoShVdUWIjntC8FHCw9c5dR8r3q4Ynh+zkS8y2eFFunN/DL6RXPzpnvKCg3vhLQYJDmT9Q==}
+ '@docusaurus/theme-translations@3.5.2':
+ resolution: {integrity: sha512-GPZLcu4aT1EmqSTmbdpVrDENGR2yObFEX8ssEFYTCiAIVc0EihNSdOIBTazUvgNqwvnoU1A8vIs1xyzc3LITTw==}
engines: {node: '>=18.0'}
+
+ '@docusaurus/tsconfig@3.5.2':
+ resolution: {integrity: sha512-rQ7toURCFnWAIn8ubcquDs0ewhPwviMzxh6WpRjBW7sJVCXb6yzwUaY3HMNa0VXCFw+qkIbFywrMTf+Pb4uHWQ==}
+
+ '@docusaurus/types@3.5.2':
+ resolution: {integrity: sha512-N6GntLXoLVUwkZw7zCxwy9QiuEXIcTVzA9AkmNw16oc0AP3SXLrMmDMMBIfgqwuKWa6Ox6epHol9kMtJqekACw==}
peerDependencies:
react: ^18.0.0
react-dom: ^18.0.0
- '@docusaurus/theme-translations@3.4.0':
- resolution: {integrity: sha512-zSxCSpmQCCdQU5Q4CnX/ID8CSUUI3fvmq4hU/GNP/XoAWtXo9SAVnM3TzpU8Gb//H3WCsT8mJcTfyOk3d9ftNg==}
- engines: {node: '>=18.0'}
-
- '@docusaurus/tsconfig@3.4.0':
- resolution: {integrity: sha512-0qENiJ+TRaeTzcg4olrnh0BQ7eCxTgbYWBnWUeQDc84UYkt/T3pDNnm3SiQkqPb+YQ1qtYFlC0RriAElclo8Dg==}
-
- '@docusaurus/types@3.4.0':
- resolution: {integrity: sha512-4jcDO8kXi5Cf9TcyikB/yKmz14f2RZ2qTRerbHAsS+5InE9ZgSLBNLsewtFTcTOXSVcbU3FoGOzcNWAmU1TR0A==}
- peerDependencies:
- react: ^18.0.0
- react-dom: ^18.0.0
-
- '@docusaurus/utils-common@3.4.0':
- resolution: {integrity: sha512-NVx54Wr4rCEKsjOH5QEVvxIqVvm+9kh7q8aYTU5WzUU9/Hctd6aTrcZ3G0Id4zYJ+AeaG5K5qHA4CY5Kcm2iyQ==}
+ '@docusaurus/utils-common@3.5.2':
+ resolution: {integrity: sha512-i0AZjHiRgJU6d7faQngIhuHKNrszpL/SHQPgF1zH4H+Ij6E9NBYGy6pkcGWToIv7IVPbs+pQLh1P3whn0gWXVg==}
engines: {node: '>=18.0'}
peerDependencies:
'@docusaurus/types': '*'
@@ -1017,12 +1034,12 @@ packages:
'@docusaurus/types':
optional: true
- '@docusaurus/utils-validation@3.4.0':
- resolution: {integrity: sha512-hYQ9fM+AXYVTWxJOT1EuNaRnrR2WGpRdLDQG07O8UOpsvCPWUVOeo26Rbm0JWY2sGLfzAb+tvJ62yF+8F+TV0g==}
+ '@docusaurus/utils-validation@3.5.2':
+ resolution: {integrity: sha512-m+Foq7augzXqB6HufdS139PFxDC5d5q2QKZy8q0qYYvGdI6nnlNsGH4cIGsgBnV7smz+mopl3g4asbSDvMV0jA==}
engines: {node: '>=18.0'}
- '@docusaurus/utils@3.4.0':
- resolution: {integrity: sha512-fRwnu3L3nnWaXOgs88BVBmG1yGjcQqZNHG+vInhEa2Sz2oQB+ZjbEMO5Rh9ePFpZ0YDiDUhpaVjwmS+AU2F14g==}
+ '@docusaurus/utils@3.5.2':
+ resolution: {integrity: sha512-33QvcNFh+Gv+C2dP9Y9xWEzMgf3JzrpL2nW9PopidiohS1nDcyknKRx2DWaFvyVTTYIkkABVSr073VTj/NITNA==}
engines: {node: '>=18.0'}
peerDependencies:
'@docusaurus/types': '*'
@@ -1033,8 +1050,8 @@ packages:
'@easyops-cn/autocomplete.js@0.38.1':
resolution: {integrity: sha512-drg76jS6syilOUmVNkyo1c7ZEBPcPuK+aJA7AksM5ZIIbV57DMHCywiCr+uHyv8BE5jUTU98j/H7gVrkHrWW3Q==}
- '@easyops-cn/docusaurus-search-local@0.44.0':
- resolution: {integrity: sha512-sgLpvkRtYuEGvd4peYQW2oInI4JkcQfxo7HgEnkhcxn9kxDY5laA8DiCx9qMKAkM9cMed9e8IsLk5gBeDh8Rqw==}
+ '@easyops-cn/docusaurus-search-local@0.44.5':
+ resolution: {integrity: sha512-jT3wuYVzRoeB1gea+2iDtOMme0fD2h3M8HDVgs3garITO6vRxvEraFRVlYkfjLN9BkmzjMlz9nn7MI4qIx8utw==}
engines: {node: '>=12'}
peerDependencies:
'@docusaurus/theme-common': ^2 || ^3
@@ -1229,8 +1246,8 @@ packages:
'@jridgewell/source-map@0.3.6':
resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==}
- '@jridgewell/sourcemap-codec@1.4.15':
- resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
+ '@jridgewell/sourcemap-codec@1.5.0':
+ resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
'@jridgewell/trace-mapping@0.3.25':
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
@@ -1357,8 +1374,8 @@ packages:
resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==}
engines: {node: '>=12.22.0'}
- '@pnpm/npm-conf@2.2.2':
- resolution: {integrity: sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==}
+ '@pnpm/npm-conf@2.3.1':
+ resolution: {integrity: sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==}
engines: {node: '>=12'}
'@polka/url@1.0.0-next.25':
@@ -1367,8 +1384,11 @@ packages:
'@redocly/ajv@8.11.0':
resolution: {integrity: sha512-9GWx27t7xWhDIR02PA18nzBdLcKQRgc46xNQvjFkrYk4UOmvKhJ/dawwiX0cCOeetN5LcaaiqQbVOWYK62SGHw==}
- '@redocly/openapi-core@1.10.3':
- resolution: {integrity: sha512-4SnIWh8r3EM1ylcoHIJSnQnuvqRTpQMnf2RU3BfVdcCBa0A1uEyH6XSxgcO5ehxfQGuGGpUXJ+vPh32PUaQDkA==}
+ '@redocly/config@0.6.3':
+ resolution: {integrity: sha512-hGWJgCsXRw0Ow4rplqRlUQifZvoSwZipkYnt11e3SeH1Eb23VUIDBcRuaQOUqy1wn0eevXkU2GzzQ8fbKdQ7Mg==}
+
+ '@redocly/openapi-core@1.16.0':
+ resolution: {integrity: sha512-z06h+svyqbUcdAaePq8LPSwTPlm6Ig7j2VlL8skPBYnJvyaQ2IN7x/JkOvRL4ta+wcOCBdAex5JWnZbKaNktJg==}
engines: {node: '>=14.19.0', npm: '>=7.0.0'}
'@sec-ant/readable-stream@0.4.1':
@@ -1390,9 +1410,9 @@ packages:
resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==}
engines: {node: '>=10'}
- '@sindresorhus/is@6.3.1':
- resolution: {integrity: sha512-FX4MfcifwJyFOI2lPoX7PQxCqx8BG1HCho7WdiXwpEQx1Ycij0JxkfYtGK7yqNScrZGSlt6RE6sw8QYoH7eKnQ==}
- engines: {node: '>=16'}
+ '@sindresorhus/is@7.0.0':
+ resolution: {integrity: sha512-WDTlVTyvFivSOuyvMeedzg2hdoBLZ3f1uNVuEida2Rl9BrfjrIRjWA/VZIrMRLvSwJYCAlCRA3usDt1THytxWQ==}
+ engines: {node: '>=18'}
'@slorber/remark-comment@1.0.0':
resolution: {integrity: sha512-RCE24n7jsOj1M0UPvIQCHTe7fI0sFL4S2nwKVWwHyVr/wI/H8GosgsJGyhnsZoGFnD/P2hLf1mSbrrgSLN93NA==}
@@ -1513,8 +1533,8 @@ packages:
'@types/eslint-scope@3.7.7':
resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
- '@types/eslint@8.56.10':
- resolution: {integrity: sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==}
+ '@types/eslint@9.6.0':
+ resolution: {integrity: sha512-gi6WQJ7cHRgZxtkQEoyHMppPjq9Kxo5Tjn2prSKDSmZrCz8TZ3jSRCeTJm+WoM+oB0WG37bRqLzaaU3q7JypGg==}
'@types/estree-jsx@1.0.5':
resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==}
@@ -1522,8 +1542,8 @@ packages:
'@types/estree@1.0.5':
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
- '@types/express-serve-static-core@4.19.3':
- resolution: {integrity: sha512-KOzM7MhcBFlmnlr/fzISFF5vGWVSvN6fTd4T+ExOt08bA/dA5kpSzY52nMsI1KDFmUREpJelPYyuslLRSjjgCg==}
+ '@types/express-serve-static-core@4.19.5':
+ resolution: {integrity: sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==}
'@types/express@4.17.21':
resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==}
@@ -1546,8 +1566,8 @@ packages:
'@types/http-errors@2.0.4':
resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
- '@types/http-proxy@1.17.14':
- resolution: {integrity: sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==}
+ '@types/http-proxy@1.17.15':
+ resolution: {integrity: sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==}
'@types/istanbul-lib-coverage@2.0.6':
resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
@@ -1579,8 +1599,8 @@ packages:
'@types/node@17.0.45':
resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==}
- '@types/node@20.14.5':
- resolution: {integrity: sha512-aoRR+fJkZT2l0aGOJhuA8frnCSoNX6W7U2mpNq63+BxBIj5BQFt8rHy627kijCmm63ijdSdwvGgpUsU6MBsZZA==}
+ '@types/node@20.14.15':
+ resolution: {integrity: sha512-Fz1xDMCF/B00/tYSVMlmK7hVeLh7jE5f3B7X1/hmV0MJBwE27KlS7EvD/Yp+z1lm8mVhwV5w+n8jOZG8AfTlKw==}
'@types/parse-json@4.0.2':
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
@@ -1636,20 +1656,20 @@ packages:
'@types/trusted-types@2.0.7':
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
- '@types/unist@2.0.10':
- resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==}
+ '@types/unist@2.0.11':
+ resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==}
- '@types/unist@3.0.2':
- resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==}
+ '@types/unist@3.0.3':
+ resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
- '@types/ws@8.5.10':
- resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==}
+ '@types/ws@8.5.12':
+ resolution: {integrity: sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==}
'@types/yargs-parser@21.0.3':
resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
- '@types/yargs@17.0.32':
- resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==}
+ '@types/yargs@17.0.33':
+ resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==}
'@ungap/structured-clone@1.2.0':
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
@@ -1723,8 +1743,8 @@ packages:
resolution: {integrity: sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==}
engines: {node: '>=0.4.0'}
- acorn@8.12.0:
- resolution: {integrity: sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==}
+ acorn@8.12.1:
+ resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==}
engines: {node: '>=0.4.0'}
hasBin: true
@@ -1761,16 +1781,16 @@ packages:
ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
- ajv@8.16.0:
- resolution: {integrity: sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==}
+ ajv@8.17.1:
+ resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
- algoliasearch-helper@3.21.0:
- resolution: {integrity: sha512-hjVOrL15I3Y3K8xG0icwG1/tWE+MocqBrhW6uVBWpU+/kVEMK0BnM2xdssj6mZM61eJ4iRxHR0djEI3ENOpR8w==}
+ algoliasearch-helper@3.22.3:
+ resolution: {integrity: sha512-2eoEz8mG4KHE+DzfrBTrCmDPxVXv7aZZWPojAJFtARpxxMO6lkos1dJ+XDCXdPvq7q3tpYWRi6xXmVQikejtpA==}
peerDependencies:
algoliasearch: '>= 3.1 < 6'
- algoliasearch@4.23.3:
- resolution: {integrity: sha512-Le/3YgNvjW9zxIQMRhUHuhiUjAlKY/zsdZpfq4dlLqg6mEm0nL6yk+7f2hDOtLpxsgE4jSzDmvHL7nXdBp5feg==}
+ algoliasearch@4.24.0:
+ resolution: {integrity: sha512-bf0QV/9jVejssFBmz2HQLxUadxk574t4iwjCKp5E7NBzwKkrDEhKPISIIjAU/p6K5qDx3qoeh4+26zWN1jmw3g==}
ansi-align@3.0.1:
resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==}
@@ -1813,6 +1833,10 @@ packages:
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+ array-buffer-byte-length@1.0.1:
+ resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==}
+ engines: {node: '>= 0.4'}
+
array-flatten@1.1.1:
resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
@@ -1820,6 +1844,18 @@ packages:
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
engines: {node: '>=8'}
+ array.prototype.filter@1.0.4:
+ resolution: {integrity: sha512-r+mCJ7zXgXElgR4IRC+fkvNCeoaavWBs6EdCso5Tbcf+iEMKzBU/His60lt34WEZ9vlb8wDkZvQGcVI5GwkfoQ==}
+ engines: {node: '>= 0.4'}
+
+ array.prototype.flat@1.3.2:
+ resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==}
+ engines: {node: '>= 0.4'}
+
+ arraybuffer.prototype.slice@1.0.3:
+ resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==}
+ engines: {node: '>= 0.4'}
+
astring@1.8.6:
resolution: {integrity: sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==}
hasBin: true
@@ -1831,15 +1867,19 @@ packages:
resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
engines: {node: '>= 4.0.0'}
- autoprefixer@10.4.19:
- resolution: {integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==}
+ autoprefixer@10.4.20:
+ resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==}
engines: {node: ^10 || ^12 || >=14}
hasBin: true
peerDependencies:
postcss: ^8.1.0
- axios@1.7.2:
- resolution: {integrity: sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==}
+ available-typed-arrays@1.0.7:
+ resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
+ engines: {node: '>= 0.4'}
+
+ axios@1.7.4:
+ resolution: {integrity: sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==}
babel-loader@9.1.3:
resolution: {integrity: sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==}
@@ -1861,6 +1901,11 @@ packages:
peerDependencies:
'@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
+ babel-plugin-polyfill-corejs3@0.10.6:
+ resolution: {integrity: sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==}
+ peerDependencies:
+ '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
+
babel-plugin-polyfill-regenerator@0.6.2:
resolution: {integrity: sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==}
peerDependencies:
@@ -1910,8 +1955,13 @@ packages:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'}
- browserslist@4.23.1:
- resolution: {integrity: sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==}
+ browserslist@4.23.2:
+ resolution: {integrity: sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+
+ browserslist@4.23.3:
+ resolution: {integrity: sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
@@ -1962,8 +2012,8 @@ packages:
caniuse-api@3.0.0:
resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==}
- caniuse-lite@1.0.30001636:
- resolution: {integrity: sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==}
+ caniuse-lite@1.0.30001651:
+ resolution: {integrity: sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==}
ccount@2.0.1:
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
@@ -1999,6 +2049,10 @@ packages:
cheerio-select@2.1.0:
resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==}
+ cheerio@1.0.0:
+ resolution: {integrity: sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==}
+ engines: {node: '>=18.17'}
+
cheerio@1.0.0-rc.12:
resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==}
engines: {node: '>= 6'}
@@ -2173,11 +2227,14 @@ packages:
core-js-compat@3.37.1:
resolution: {integrity: sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==}
- core-js-pure@3.37.1:
- resolution: {integrity: sha512-J/r5JTHSmzTxbiYYrzXg9w1VpqrYt+gexenBE9pugeyhwPZTAEJddyiReJWsLO6uNQ8xJZFbod6XC7KKwatCiA==}
+ core-js-compat@3.38.0:
+ resolution: {integrity: sha512-75LAicdLa4OJVwFxFbQR3NdnZjNgX6ILpVcVzcC4T2smerB5lELMrJQQQoWV6TiuC/vlaFqgU2tKQx9w5s0e0A==}
- core-js@3.37.1:
- resolution: {integrity: sha512-Xn6qmxrQZyB0FFY8E3bgRXei3lWDJHhvI+u0q9TKIYM49G8pAr0FgnnrFRAmsbptZL1yxRADVXn+x5AGsbBfyw==}
+ core-js-pure@3.38.0:
+ resolution: {integrity: sha512-8balb/HAXo06aHP58mZMtXgD8vcnXz9tUDePgqBgJgKdmTlMt+jw3ujqniuBDQXMvTzxnMpxHFeuSM3g1jWQuQ==}
+
+ core-js@3.38.0:
+ resolution: {integrity: sha512-XPpwqEodRljce9KswjZShh95qJ1URisBeKCjUdq27YdenkslVe7OO0ZJhlYXAChW7OhXaRLl8AAba7IBfoIHug==}
core-util-is@1.0.3:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
@@ -2315,6 +2372,18 @@ packages:
resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==}
engines: {node: '>=18'}
+ data-view-buffer@1.0.1:
+ resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==}
+ engines: {node: '>= 0.4'}
+
+ data-view-byte-length@1.0.1:
+ resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==}
+ engines: {node: '>= 0.4'}
+
+ data-view-byte-offset@1.0.0:
+ resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==}
+ engines: {node: '>= 0.4'}
+
date-fns@2.30.0:
resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==}
engines: {node: '>=0.11'}
@@ -2330,8 +2399,8 @@ packages:
supports-color:
optional: true
- debug@4.3.5:
- resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==}
+ debug@4.3.6:
+ resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==}
engines: {node: '>=6.0'}
peerDependencies:
supports-color: '*'
@@ -2424,18 +2493,21 @@ packages:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'}
+ discontinuous-range@1.0.0:
+ resolution: {integrity: sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==}
+
dns-packet@5.6.1:
resolution: {integrity: sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==}
engines: {node: '>=6'}
- docusaurus-plugin-redoc@2.0.2:
- resolution: {integrity: sha512-J4pfu+dvwm1D4qWA6O8FT6EYSw9R1mv9fIXCqKh7aHYD+OU19hj/vQQUdjIbAwTcOkBg+eUYVXvdopwTvUXNcQ==}
+ docusaurus-plugin-redoc@2.1.1:
+ resolution: {integrity: sha512-gf9HbFAKPZu17rbx+3C6vIpfMMTuvUFG8rRKeuHro1B5wUutBSjE5/VjB1owVGjIJQ74OgVKJvgczqUjhcQcjQ==}
engines: {node: '>=18'}
peerDependencies:
'@docusaurus/utils': ^3.0.0
- docusaurus-theme-redoc@2.0.2:
- resolution: {integrity: sha512-qa8svxKCipIvokNGctoQRP3Vz+HTF2Mnwg6xzY/W/LR5TYEIu3nuSvouLLR58uBrHKGzGpto5CEPDq0SvVvDlA==}
+ docusaurus-theme-redoc@2.1.1:
+ resolution: {integrity: sha512-a9yuYyGVhj7NgBYiqJyjLEkJg/yTdsqg9Rn/cG8YXMIFwxIpn4tanIplUqwisK2PS81ZxOv7SfSgvGm/FSi/wA==}
engines: {node: '>=18'}
peerDependencies:
'@docusaurus/theme-common': ^3.0.0
@@ -2461,11 +2533,8 @@ packages:
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
engines: {node: '>= 4'}
- dompurify@2.5.5:
- resolution: {integrity: sha512-FgbqnEPiv5Vdtwt6Mxl7XSylttCC03cqP5ldNT2z+Kj0nLxPHJH4+1Cyf5Jasxhw93Rl4Oo11qRoUV72fmya2Q==}
-
- dompurify@3.1.5:
- resolution: {integrity: sha512-lwG+n5h8QNpxtyrJW/gJWckL+1/DQiYMX8f7t8Z2AZTPw1esVrqjI63i7Zc2Gz0aKzLVMYC1V1PL/ky+aY/NgA==}
+ dompurify@3.1.6:
+ resolution: {integrity: sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==}
domutils@2.8.0:
resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==}
@@ -2489,8 +2558,11 @@ packages:
ee-first@1.1.1:
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
- electron-to-chromium@1.4.805:
- resolution: {integrity: sha512-8W4UJwX/w9T0QSzINJckTKG6CYpAUTqsaWcWIsdud3I1FYJcMgW9QqT1/4CBff/pP/TihWh13OmiyY8neto6vw==}
+ electron-to-chromium@1.5.3:
+ resolution: {integrity: sha512-QNdYSS5i8D9axWp/6XIezRObRHqaav/ur9z1VzCDUCH1XIFOr9WQk5xmgunhsTpjjgDy3oLxO/WMOVZlpUQrlA==}
+
+ electron-to-chromium@1.5.8:
+ resolution: {integrity: sha512-4Nx0gP2tPNBLTrFxBMHpkQbtn2hidPVr/+/FTtcCiBYTucqc70zRyVZiOLj17Ui3wTO7SQ1/N+hkHYzJjBzt6A==}
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
@@ -2505,15 +2577,18 @@ packages:
resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==}
engines: {node: '>= 4'}
- emoticon@4.0.1:
- resolution: {integrity: sha512-dqx7eA9YaqyvYtUhJwT4rC1HIp82j5ybS1/vQ42ur+jBe17dJMwZE4+gvL1XadSFfxaPFFGt3Xsw+Y8akThDlw==}
+ emoticon@4.1.0:
+ resolution: {integrity: sha512-VWZfnxqwNcc51hIy/sbOdEem6D+cVtpPzEEtVAFdaas30+1dgkyaOQ4sQ6Bp0tOMqWO1v+HQfYaoodOkdhK6SQ==}
encodeurl@1.0.2:
resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
engines: {node: '>= 0.8'}
- enhanced-resolve@5.17.0:
- resolution: {integrity: sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==}
+ encoding-sniffer@0.2.0:
+ resolution: {integrity: sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==}
+
+ enhanced-resolve@5.17.1:
+ resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==}
engines: {node: '>=10.13.0'}
entities@2.2.0:
@@ -2523,9 +2598,22 @@ packages:
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
engines: {node: '>=0.12'}
+ enzyme-shallow-equal@1.0.7:
+ resolution: {integrity: sha512-/um0GFqUXnpM9SvKtje+9Tjoz3f1fpBC3eXRFrNs8kpYn69JljciYP7KZTqM/YQbUY9KUjvKB4jo/q+L6WGGvg==}
+
+ enzyme@3.11.0:
+ resolution: {integrity: sha512-Dw8/Gs4vRjxY6/6i9wU0V+utmQO9kvh9XLnz3LIudviOnVYDEe2ec+0k+NQoMamn1VrjKgCUOWj5jG/5M5M0Qw==}
+
error-ex@1.3.2:
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
+ es-abstract@1.23.3:
+ resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==}
+ engines: {node: '>= 0.4'}
+
+ es-array-method-boxes-properly@1.0.0:
+ resolution: {integrity: sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==}
+
es-define-property@1.0.0:
resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==}
engines: {node: '>= 0.4'}
@@ -2534,14 +2622,29 @@ packages:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
- es-module-lexer@1.5.3:
- resolution: {integrity: sha512-i1gCgmR9dCl6Vil6UKPI/trA69s08g/syhiDK9TG0Nf1RJjjFI+AzoWW7sPufzkgYAn861skuCwJa0pIIHYxvg==}
+ es-module-lexer@1.5.4:
+ resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==}
+
+ es-object-atoms@1.0.0:
+ resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==}
+ engines: {node: '>= 0.4'}
+
+ es-set-tostringtag@2.0.3:
+ resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==}
+ engines: {node: '>= 0.4'}
+
+ es-shim-unscopables@1.0.2:
+ resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==}
+
+ es-to-primitive@1.2.1:
+ resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
+ engines: {node: '>= 0.4'}
es6-promise@3.3.1:
resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==}
- esbuild-loader@4.2.0:
- resolution: {integrity: sha512-BhwHchuDknxIa69AqOPeZh2fIFqj2AzZKC1E3RBRvXSuyk5drsqMrwsgYZJufX41yrauLYjDM3KBmruoGl1NWQ==}
+ esbuild-loader@4.2.2:
+ resolution: {integrity: sha512-Mdq/A1L8p37hkibp8jGFwuQTDSWhDmlueAefsrCPRwNWThEOlQmIglV7Gd6GE2mO5bt7ksfxKOMwkuY7jjVTXg==}
peerDependencies:
webpack: ^4.40.0 || ^5.0.0
@@ -2606,8 +2709,8 @@ packages:
estree-util-to-js@2.0.0:
resolution: {integrity: sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==}
- estree-util-value-to-estree@3.1.1:
- resolution: {integrity: sha512-5mvUrF2suuv5f5cGDnDphIy4/gW86z82kl5qG6mM9z04SEQI4FB5Apmaw/TGEf3l55nLtMs5s51dmhUzvAHQCA==}
+ estree-util-value-to-estree@3.1.2:
+ resolution: {integrity: sha512-S0gW2+XZkmsx00tU2uJ4L9hUT7IFabbml9pHh2WQqFmAbxit++YGZne0sKJbNwkj9Wvg9E4uqWl4nCIFQMmfag==}
estree-util-visit@2.0.0:
resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==}
@@ -2634,6 +2737,9 @@ packages:
eventemitter3@4.0.7:
resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
+ eventemitter3@5.0.1:
+ resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
+
events@3.3.0:
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
engines: {node: '>=0.8.x'}
@@ -2666,6 +2772,9 @@ packages:
fast-safe-stringify@2.1.1:
resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
+ fast-uri@3.0.1:
+ resolution: {integrity: sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==}
+
fast-url-parser@1.1.3:
resolution: {integrity: sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==}
@@ -2730,6 +2839,9 @@ packages:
debug:
optional: true
+ for-each@0.3.3:
+ resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
+
foreach@2.0.6:
resolution: {integrity: sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==}
@@ -2796,6 +2908,13 @@ packages:
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+ function.prototype.name@1.1.6:
+ resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==}
+ engines: {node: '>= 0.4'}
+
+ functions-have-names@1.2.3:
+ resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
+
fuse.js@7.0.0:
resolution: {integrity: sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q==}
engines: {node: '>=10'}
@@ -2819,16 +2938,16 @@ packages:
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
engines: {node: '>=10'}
- get-stream@8.0.1:
- resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==}
- engines: {node: '>=16'}
-
get-stream@9.0.1:
resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==}
engines: {node: '>=18'}
- get-tsconfig@4.7.5:
- resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==}
+ get-symbol-description@1.0.2:
+ resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==}
+ engines: {node: '>= 0.4'}
+
+ get-tsconfig@4.7.6:
+ resolution: {integrity: sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==}
github-slugger@1.5.0:
resolution: {integrity: sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==}
@@ -2864,6 +2983,10 @@ packages:
resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
engines: {node: '>=4'}
+ globalthis@1.0.4:
+ resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
+ engines: {node: '>= 0.4'}
+
globby@11.1.0:
resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
engines: {node: '>=10'}
@@ -2875,8 +2998,8 @@ packages:
gopd@1.0.1:
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
- got@14.4.1:
- resolution: {integrity: sha512-IvDJbJBUeexX74xNQuMIVgCRRuNOm5wuK+OC3Dc2pnSoh1AOmgc7JVj7WC+cJ4u0aPcO9KZ2frTXcqK4W/5qTQ==}
+ got@14.4.2:
+ resolution: {integrity: sha512-+Te/qEZ6hr7i+f0FNgXx/6WQteSM/QqueGvxeYQQFm0GDfoxLVJ/oiwUKYMTeioColWUTdewZ06hmrBjw6F7tw==}
engines: {node: '>=20'}
graceful-fs@4.2.10:
@@ -2896,6 +3019,9 @@ packages:
handle-thing@2.0.1:
resolution: {integrity: sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==}
+ has-bigints@1.0.2:
+ resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
+
has-flag@3.0.0:
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
engines: {node: '>=4'}
@@ -2915,10 +3041,18 @@ packages:
resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
engines: {node: '>= 0.4'}
+ has-tostringtag@1.0.2:
+ resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
+ engines: {node: '>= 0.4'}
+
has-yarn@3.0.0:
resolution: {integrity: sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ has@1.0.4:
+ resolution: {integrity: sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==}
+ engines: {node: '>= 0.4.0'}
+
hasown@2.0.2:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
@@ -2960,6 +3094,9 @@ packages:
hpack.js@2.1.6:
resolution: {integrity: sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==}
+ html-element-map@1.3.1:
+ resolution: {integrity: sha512-6XMlxrAFX4UEEGxctfFnmrFaaZFNf9i5fNuV5wZ3WWQ4FVaNP1aX1LkX9j2mfEx1NpjeE/rL3nmgEn23GdFmrg==}
+
html-encoding-sniffer@4.0.0:
resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==}
engines: {node: '>=18'}
@@ -3005,6 +3142,9 @@ packages:
htmlparser2@8.0.2:
resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
+ htmlparser2@9.1.0:
+ resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==}
+
http-cache-semantics@4.1.1:
resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
@@ -3046,8 +3186,8 @@ packages:
resolution: {integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==}
engines: {node: '>=10.19.0'}
- https-proxy-agent@7.0.4:
- resolution: {integrity: sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==}
+ https-proxy-agent@7.0.5:
+ resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==}
engines: {node: '>= 14'}
human-signals@2.1.0:
@@ -3068,8 +3208,8 @@ packages:
peerDependencies:
postcss: ^8.1.0
- ignore@5.3.1:
- resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==}
+ ignore@5.3.2:
+ resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
image-size@1.1.1:
@@ -3099,8 +3239,8 @@ packages:
resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
engines: {node: '>=8'}
- infima@0.2.0-alpha.43:
- resolution: {integrity: sha512-2uw57LvUqW0rK/SWYnd/2rRfxNA5DDNOh33jxF7fy46VWoNhGxiUQyVZHbBMjQ33mQem0cjdDVwgWVAmlRfgyQ==}
+ infima@0.2.0-alpha.44:
+ resolution: {integrity: sha512-tuRkUSO/lB3rEhLJk25atwAjgLuzq070+pOW8XcvpHky/YbENnRRdPd85IBkyeTgttmOy5ah+yHYsK1HhUd4lQ==}
engines: {node: '>=12'}
inflight@1.0.6:
@@ -3126,6 +3266,10 @@ packages:
inline-style-parser@0.2.3:
resolution: {integrity: sha512-qlD8YNDqyTKTyuITrDOffsl6Tdhv+UC4hcdAVuQsK4IMQ99nSgd1MIA/Q+jQYoh9r3hVUXhYh7urSRmXPkW04g==}
+ internal-slot@1.0.7:
+ resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==}
+ engines: {node: '>= 0.4'}
+
interpret@1.4.0:
resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==}
engines: {node: '>= 0.10'}
@@ -3147,19 +3291,43 @@ packages:
is-alphanumerical@2.0.1:
resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==}
+ is-array-buffer@3.0.4:
+ resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==}
+ engines: {node: '>= 0.4'}
+
is-arrayish@0.2.1:
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
+ is-bigint@1.0.4:
+ resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
+
is-binary-path@2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'}
+ is-boolean-object@1.1.2:
+ resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==}
+ engines: {node: '>= 0.4'}
+
+ is-callable@1.2.7:
+ resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
+ engines: {node: '>= 0.4'}
+
is-ci@3.0.1:
resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==}
hasBin: true
- is-core-module@2.13.1:
- resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==}
+ is-core-module@2.15.0:
+ resolution: {integrity: sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==}
+ engines: {node: '>= 0.4'}
+
+ is-data-view@1.0.1:
+ resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==}
+ engines: {node: '>= 0.4'}
+
+ is-date-object@1.0.5:
+ resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
+ engines: {node: '>= 0.4'}
is-decimal@2.0.1:
resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==}
@@ -3192,10 +3360,18 @@ packages:
resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==}
engines: {node: '>=10'}
+ is-negative-zero@2.0.3:
+ resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==}
+ engines: {node: '>= 0.4'}
+
is-npm@6.0.0:
resolution: {integrity: sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ is-number-object@1.0.7:
+ resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==}
+ engines: {node: '>= 0.4'}
+
is-number@7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
@@ -3234,6 +3410,10 @@ packages:
is-reference@3.0.2:
resolution: {integrity: sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==}
+ is-regex@1.1.4:
+ resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
+ engines: {node: '>= 0.4'}
+
is-regexp@1.0.0:
resolution: {integrity: sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==}
engines: {node: '>=0.10.0'}
@@ -3242,6 +3422,10 @@ packages:
resolution: {integrity: sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==}
engines: {node: '>=6'}
+ is-shared-array-buffer@1.0.3:
+ resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==}
+ engines: {node: '>= 0.4'}
+
is-stream@2.0.1:
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
engines: {node: '>=8'}
@@ -3250,9 +3434,27 @@ packages:
resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==}
engines: {node: '>=18'}
+ is-string@1.0.7:
+ resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
+ engines: {node: '>= 0.4'}
+
+ is-subset@0.1.1:
+ resolution: {integrity: sha512-6Ybun0IkarhmEqxXCNw/C0bna6Zb/TkfUX9UbwJtK6ObwAVCxmAP308WWTHviM/zAqXk05cdhYsUsZeGQh99iw==}
+
+ is-symbol@1.0.4:
+ resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==}
+ engines: {node: '>= 0.4'}
+
+ is-typed-array@1.1.13:
+ resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==}
+ engines: {node: '>= 0.4'}
+
is-typedarray@1.0.0:
resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==}
+ is-weakref@1.0.2:
+ resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
+
is-wsl@2.2.0:
resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==}
engines: {node: '>=8'}
@@ -3267,6 +3469,9 @@ packages:
isarray@1.0.0:
resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
+ isarray@2.0.5:
+ resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
+
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
@@ -3274,8 +3479,8 @@ packages:
resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==}
engines: {node: '>=0.10.0'}
- isomorphic-dompurify@2.12.0:
- resolution: {integrity: sha512-jJm6VgJ9toBLqNUHuLudn+2Q3NBBaoPbsh5SzzO2dp9Zq9+p6fEg4Ffuq9RZsofb8OnqE6FJVVq3MRDLlmBHpA==}
+ isomorphic-dompurify@2.14.0:
+ resolution: {integrity: sha512-7xyjuzBf3P/HBt0PbOpmv5LuV38TmfvidBFvgyuSWVMLwCGDITBPHWsBZ/L1a8DpcGz5PEintBeGdlrKzUqt5A==}
engines: {node: '>=18'}
jest-util@29.7.0:
@@ -3294,8 +3499,8 @@ packages:
resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==}
hasBin: true
- joi@17.13.1:
- resolution: {integrity: sha512-vaBlIKCyo4FCUtCm7Eu4QZd/q02bWcxfUO6YSXAZOWF6gzcLBeba8kwotUdYJjDLW8Cz8RywsSOqiNJZW0mNvg==}
+ joi@17.13.3:
+ resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==}
js-levenshtein@1.1.6:
resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==}
@@ -3312,8 +3517,8 @@ packages:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
- jsdom@24.1.0:
- resolution: {integrity: sha512-6gpM7pRXCwIOKxX47cgOyvyQDN/Eh0f1MeKySBV2xGdKtqJBLj8P25eY3EVCWo2mglDDzozR2r2MW4T+JiNUZA==}
+ jsdom@24.1.1:
+ resolution: {integrity: sha512-5O1wWV99Jhq4DV7rCLIoZ/UIhyQeDR7wHVyZAHAshbrvZsLs+Xzz7gtwnlJTJDjleiTKh54F4dXrX70vJQTyJQ==}
engines: {node: '>=18'}
peerDependencies:
canvas: ^2.11.2
@@ -3371,8 +3576,8 @@ packages:
resolution: {integrity: sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==}
engines: {node: '>=14.16'}
- launch-editor@2.7.0:
- resolution: {integrity: sha512-KAc66u6LxWL8MifQ94oG3YGKYWDwz/Gi0T15lN//GaQoZe08vQGFJxrXkPAeu50UXgvJPPaRKVGuP1TRUm/aHQ==}
+ launch-editor@2.8.1:
+ resolution: {integrity: sha512-elBx2l/tp9z99X5H/qev8uyDywVh0VXAwEbjk8kJhnc5grOFkGh7aW6q55me9xnYbss261XtnUrysZ+XvGbhQA==}
leven@3.1.0:
resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
@@ -3412,6 +3617,12 @@ packages:
lodash.debounce@4.0.8:
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
+ lodash.escape@4.0.1:
+ resolution: {integrity: sha512-nXEOnb/jK9g0DYMr1/Xvq6l5xMD7GDG55+GSYIYmS0G4tBk/hURD4JR9WCavs04t33WmJx9kCyp9vJ+mr4BOUw==}
+
+ lodash.flattendeep@4.4.0:
+ resolution: {integrity: sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==}
+
lodash.isequal@4.5.0:
resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
@@ -3457,8 +3668,8 @@ packages:
markdown-table@3.0.3:
resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==}
- marked@13.0.0:
- resolution: {integrity: sha512-VTeDCd9txf4KLLljUZ0nljE/Incb9SrWuueE44QVuU0pkOdh4sfCeW1Z6lPcxyDRSVY6rm8db/0OPaN75RNUmw==}
+ marked@14.0.0:
+ resolution: {integrity: sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==}
engines: {node: '>= 18'}
hasBin: true
@@ -3552,29 +3763,29 @@ packages:
micromark-core-commonmark@2.0.1:
resolution: {integrity: sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==}
- micromark-extension-directive@3.0.0:
- resolution: {integrity: sha512-61OI07qpQrERc+0wEysLHMvoiO3s2R56x5u7glHq2Yqq6EHbH4dW25G9GfDdGCDYqA21KE6DWgNSzxSwHc2hSg==}
+ micromark-extension-directive@3.0.1:
+ resolution: {integrity: sha512-VGV2uxUzhEZmaP7NSFo2vtq7M2nUD+WfmYQD+d8i/1nHbzE+rMy9uzTvUybBbNiVbrhOZibg3gbyoARGqgDWyg==}
micromark-extension-frontmatter@2.0.0:
resolution: {integrity: sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==}
- micromark-extension-gfm-autolink-literal@2.0.0:
- resolution: {integrity: sha512-rTHfnpt/Q7dEAK1Y5ii0W8bhfJlVJFnJMHIPisfPK3gpVNuOP0VnRl96+YJ3RYWV/P4gFeQoGKNlT3RhuvpqAg==}
+ micromark-extension-gfm-autolink-literal@2.1.0:
+ resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==}
- micromark-extension-gfm-footnote@2.0.0:
- resolution: {integrity: sha512-6Rzu0CYRKDv3BfLAUnZsSlzx3ak6HAoI85KTiijuKIz5UxZxbUI+pD6oHgw+6UtQuiRwnGRhzMmPRv4smcz0fg==}
+ micromark-extension-gfm-footnote@2.1.0:
+ resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==}
- micromark-extension-gfm-strikethrough@2.0.0:
- resolution: {integrity: sha512-c3BR1ClMp5fxxmwP6AoOY2fXO9U8uFMKs4ADD66ahLTNcwzSCyRVU4k7LPV5Nxo/VJiR4TdzxRQY2v3qIUceCw==}
+ micromark-extension-gfm-strikethrough@2.1.0:
+ resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==}
- micromark-extension-gfm-table@2.0.0:
- resolution: {integrity: sha512-PoHlhypg1ItIucOaHmKE8fbin3vTLpDOUg8KAr8gRCF1MOZI9Nquq2i/44wFvviM4WuxJzc3demT8Y3dkfvYrw==}
+ micromark-extension-gfm-table@2.1.0:
+ resolution: {integrity: sha512-Ub2ncQv+fwD70/l4ou27b4YzfNaCJOvyX4HxXU15m7mpYY+rjuWzsLIPZHJL253Z643RpbcP1oeIJlQ/SKW67g==}
micromark-extension-gfm-tagfilter@2.0.0:
resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==}
- micromark-extension-gfm-task-list-item@2.0.1:
- resolution: {integrity: sha512-cY5PzGcnULaN5O7T+cOzfMoHjBW7j+T9D2sucA5d/KbsBTPcYdebm9zUd9zzdgJGCwahV+/W78Z3nbulBYVbTw==}
+ micromark-extension-gfm-task-list-item@2.1.0:
+ resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==}
micromark-extension-gfm@3.0.0:
resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==}
@@ -3684,6 +3895,10 @@ packages:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
+ mime-db@1.53.0:
+ resolution: {integrity: sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==}
+ engines: {node: '>= 0.6'}
+
mime-types@2.1.18:
resolution: {integrity: sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==}
engines: {node: '>= 0.6'}
@@ -3728,10 +3943,10 @@ packages:
minimist@1.2.8:
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
- mobx-react-lite@3.4.3:
- resolution: {integrity: sha512-NkJREyFTSUXR772Qaai51BnE1voWx56LOL80xG7qkZr6vo8vEaLF3sz1JNUVh+rxmUzxYaqOhfuxTfqUh0FXUg==}
+ mobx-react-lite@4.0.7:
+ resolution: {integrity: sha512-RjwdseshK9Mg8On5tyJZHtGD+J78ZnCnRaxeQDSiciKVQDUbfZcXhmld0VMxAwvcTnPEHZySGGewm467Fcpreg==}
peerDependencies:
- mobx: ^6.1.0
+ mobx: ^6.9.0
react: ^16.8.0 || ^17 || ^18
react-dom: '*'
react-native: '*'
@@ -3741,10 +3956,10 @@ packages:
react-native:
optional: true
- mobx-react@7.6.0:
- resolution: {integrity: sha512-+HQUNuh7AoQ9ZnU6c4rvbiVVl+wEkb9WqYsVDzGLng+Dqj1XntHu79PvEWKtSMoMj67vFp/ZPXcElosuJO8ckA==}
+ mobx-react@9.1.1:
+ resolution: {integrity: sha512-gVV7AdSrAAxqXOJ2bAbGa5TkPqvITSzaPiiEkzpW4rRsMhSec7C2NBCJYILADHKp2tzOAIETGRsIY0UaCV5aEw==}
peerDependencies:
- mobx: ^6.1.0
+ mobx: ^6.9.0
react: ^16.8.0 || ^17 || ^18
react-dom: '*'
react-native: '*'
@@ -3754,8 +3969,11 @@ packages:
react-native:
optional: true
- mobx@6.12.4:
- resolution: {integrity: sha512-uIymg89x+HmItX1p3MG+d09irn2k63J6biftZ5Ok+UpNojS1I3NJPLfcmJT9ANnUltNlHi+HQqrVyxiAN8ISYg==}
+ mobx@6.13.1:
+ resolution: {integrity: sha512-ekLRxgjWJr8hVxj9ZKuClPwM/iHckx3euIJ3Np7zLVNtqJvfbbq7l370W/98C8EabdQ1pB5Jd3BbDWxJPNnaOg==}
+
+ moo@0.5.2:
+ resolution: {integrity: sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==}
mrmime@2.0.0:
resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==}
@@ -3779,6 +3997,10 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
+ nearley@2.20.1:
+ resolution: {integrity: sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==}
+ hasBin: true
+
negotiator@0.6.3:
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
engines: {node: '>= 0.6'}
@@ -3813,8 +4035,8 @@ packages:
node-readfiles@0.2.0:
resolution: {integrity: sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA==}
- node-releases@2.0.14:
- resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
+ node-releases@2.0.18:
+ resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==}
normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
@@ -3838,8 +4060,8 @@ packages:
nth-check@2.1.1:
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
- nwsapi@2.2.10:
- resolution: {integrity: sha512-QK0sRs7MKv0tKe1+5uZIQk/C8XGza4DAnztJG8iD+TpJIORARrCxczA738awHrZoHeTjSSoHqao2teO0dC/gFQ==}
+ nwsapi@2.2.12:
+ resolution: {integrity: sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==}
oas-kit-common@1.0.8:
resolution: {integrity: sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==}
@@ -3861,8 +4083,13 @@ packages:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
- object-inspect@1.13.1:
- resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
+ object-inspect@1.13.2:
+ resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==}
+ engines: {node: '>= 0.4'}
+
+ object-is@1.1.6:
+ resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==}
+ engines: {node: '>= 0.4'}
object-keys@1.1.1:
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
@@ -3872,6 +4099,14 @@ packages:
resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==}
engines: {node: '>= 0.4'}
+ object.entries@1.1.8:
+ resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==}
+ engines: {node: '>= 0.4'}
+
+ object.values@1.2.0:
+ resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==}
+ engines: {node: '>= 0.4'}
+
obuf@1.1.2:
resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==}
@@ -3965,6 +4200,9 @@ packages:
parse5-htmlparser2-tree-adapter@7.0.0:
resolution: {integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==}
+ parse5-parser-stream@7.1.2:
+ resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==}
+
parse5@7.1.2:
resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==}
@@ -4020,6 +4258,9 @@ packages:
perfect-scrollbar@1.5.5:
resolution: {integrity: sha512-dzalfutyP3e/FOpdlhVryN4AJ5XDVauVWxybSkLZmakFE2sS3y3pc4JnSprw8tGmHvkaG5Edr5T7LBTZ+WWU2g==}
+ performance-now@2.1.0:
+ resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
+
periscopic@3.1.0:
resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==}
@@ -4046,6 +4287,10 @@ packages:
resolution: {integrity: sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==}
engines: {node: '>=10'}
+ possible-typed-array-names@1.0.0:
+ resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==}
+ engines: {node: '>= 0.4'}
+
postcss-calc@9.0.1:
resolution: {integrity: sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==}
engines: {node: ^14 || ^16 || >=18.0}
@@ -4245,8 +4490,8 @@ packages:
peerDependencies:
postcss: ^8.4.31
- postcss-selector-parser@6.1.0:
- resolution: {integrity: sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==}
+ postcss-selector-parser@6.1.2:
+ resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==}
engines: {node: '>=4'}
postcss-sort-media-queries@5.2.0:
@@ -4280,6 +4525,10 @@ packages:
resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==}
engines: {node: ^10 || ^12 || >=14}
+ postcss@8.4.41:
+ resolution: {integrity: sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==}
+ engines: {node: ^10 || ^12 || >=14}
+
pretty-error@4.0.0:
resolution: {integrity: sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==}
@@ -4350,6 +4599,16 @@ packages:
resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
engines: {node: '>=10'}
+ raf@3.4.1:
+ resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==}
+
+ railroad-diagrams@1.0.0:
+ resolution: {integrity: sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==}
+
+ randexp@0.4.6:
+ resolution: {integrity: sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==}
+ engines: {node: '>=0.12'}
+
randombytes@2.1.0:
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
@@ -4404,6 +4663,9 @@ packages:
react-is@16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
+ react-is@18.3.1:
+ resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
+
react-json-view-lite@1.4.0:
resolution: {integrity: sha512-wh6F6uJyYAmQ4fK0e8dSQMEWuvTs2Wr3el3sLD9bambX1+pSWUVXIz1RFaoy3TI1mZ0FqdpKq9YgbgTTgyrmXA==}
engines: {node: '>=14'}
@@ -4433,10 +4695,15 @@ packages:
peerDependencies:
react: '>=15'
- react-tabs@4.3.0:
- resolution: {integrity: sha512-2GfoG+f41kiBIIyd3gF+/GRCCYtamC8/2zlAcD8cqQmqI9Q+YVz7fJLHMmU9pXDVYYHpJeCgUSBJju85vu5q8Q==}
+ react-shallow-renderer@16.15.0:
+ resolution: {integrity: sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==}
peerDependencies:
- react: ^16.8.0 || ^17.0.0-0 || ^18.0.0
+ react: ^16.0.0 || ^17.0.0 || ^18.0.0
+
+ react-tabs@6.0.2:
+ resolution: {integrity: sha512-aQXTKolnM28k3KguGDBSAbJvcowOQr23A+CUJdzJtOSDOtTwzEaJA+1U4KwhNL9+Obe+jFS7geuvA7ICQPXOnQ==}
+ peerDependencies:
+ react: ^18.0.0
react@18.3.1:
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
@@ -4464,8 +4731,8 @@ packages:
resolution: {integrity: sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==}
engines: {node: '>=6.0.0'}
- redoc@2.1.3:
- resolution: {integrity: sha512-d7F9qLLxaiFW4GC03VkwlX9wuRIpx9aiIIf3o6mzMnqPfhxrn2IRKGndrkJeVdItgCfmg9jXZiFEowm60f1meQ==}
+ redoc@2.1.5:
+ resolution: {integrity: sha512-POSbVg+7WLf+/5/c6GWLxL7+9t2D+1WlZdLN0a6qaCQc+ih3XYzteRBkXEN5kjrYrRNjdspfxTZkDLN5WV3Tzg==}
engines: {node: '>=6.9', npm: '>=3.0.0'}
peerDependencies:
core-js: ^3.1.4
@@ -4474,8 +4741,8 @@ packages:
react-dom: ^16.8.4 || ^17.0.0 || ^18.0.0
styled-components: ^4.1.1 || ^5.1.1 || ^6.0.5
- redocusaurus@2.0.2:
- resolution: {integrity: sha512-o71XY24IkqCWVUF39UpVbklvKilbI5LfqPPeD5yhuaME87agsIHpRNdvifdPIK0oAQog4RMjDM+qMRqKUB414A==}
+ redocusaurus@2.1.1:
+ resolution: {integrity: sha512-uaiuSsty0TcYuibabEw72DzN5JL6eF9KTIR5dL61qP7smFwIY8THEsNogzKTfcKCb6MJ8ug4vohrnrANn3K3cg==}
engines: {node: '>=14'}
peerDependencies:
'@docusaurus/theme-common': ^3.0.0
@@ -4497,6 +4764,10 @@ packages:
regenerator-transform@0.15.2:
resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==}
+ regexp.prototype.flags@1.5.2:
+ resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==}
+ engines: {node: '>= 0.4'}
+
regexpu-core@5.3.2:
resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==}
engines: {node: '>=4'}
@@ -4583,6 +4854,10 @@ packages:
resolution: {integrity: sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==}
engines: {node: '>=14.16'}
+ ret@0.1.15:
+ resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==}
+ engines: {node: '>=0.12'}
+
retry@0.13.1:
resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==}
engines: {node: '>= 4'}
@@ -4602,11 +4877,14 @@ packages:
rrweb-cssom@0.7.1:
resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==}
+ rst-selector-parser@2.2.3:
+ resolution: {integrity: sha512-nDG1rZeP6oFTLN6yNDV/uiAvs1+FS/KlrEwh7+y7dpuApDBy6bI2HTBcc0/V8lv9OTqfyD34eF7au2pm8aBbhA==}
+
rtl-detect@1.1.2:
resolution: {integrity: sha512-PGMBq03+TTG/p/cRB7HCLKJ1MgDIi07+QU1faSjiYRfmY5UsAttV9Hs08jDAHVwcOwmVLcSJkpwyfXszVjWfIQ==}
- rtlcss@4.1.1:
- resolution: {integrity: sha512-/oVHgBtnPNcggP2aVXQjSy6N1mMAfHg4GSag0QtZBlD5bdDgAHwr4pydqJGd+SUCu9260+Pjqbjwtvu7EMH1KQ==}
+ rtlcss@4.2.0:
+ resolution: {integrity: sha512-AV+V3oOVvCrqyH5Q/6RuT1IDH1Xy5kJTkEWTWZPN5rdQ3HCFOd8SrbC7c6N5Y8bPpCfZSR6yYbUATXslvfvu5g==}
engines: {node: '>=12.0.0'}
hasBin: true
@@ -4616,12 +4894,20 @@ packages:
rxjs@7.8.1:
resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
+ safe-array-concat@1.1.2:
+ resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==}
+ engines: {node: '>=0.4'}
+
safe-buffer@5.1.2:
resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
safe-buffer@5.2.1:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+ safe-regex-test@1.0.3:
+ resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==}
+ engines: {node: '>= 0.4'}
+
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
@@ -4647,8 +4933,8 @@ packages:
resolution: {integrity: sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==}
engines: {node: '>= 12.13.0'}
- search-insights@2.14.0:
- resolution: {integrity: sha512-OLN6MsPMCghDOqlCtsIsYgtsC0pnwVTyT9Mu6A3ewOj1DxvzZF6COrn2g86E/c05xbktB0XN04m/t1Z+n+fTGw==}
+ search-insights@2.15.0:
+ resolution: {integrity: sha512-ch2sPCUDD4sbPQdknVl9ALSi9H7VyoeVbsxznYz6QV55jJ8CI3EtwpO1i84keN4+hF5IeHWIeGvc08530JkVXQ==}
section-matter@1.0.0:
resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==}
@@ -4669,8 +4955,8 @@ packages:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
- semver@7.6.2:
- resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==}
+ semver@7.6.3:
+ resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==}
engines: {node: '>=10'}
hasBin: true
@@ -4696,6 +4982,10 @@ packages:
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
engines: {node: '>= 0.4'}
+ set-function-name@2.0.2:
+ resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==}
+ engines: {node: '>= 0.4'}
+
setprototypeof@1.1.0:
resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==}
@@ -4848,6 +5138,17 @@ packages:
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
engines: {node: '>=12'}
+ string.prototype.trim@1.2.9:
+ resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==}
+ engines: {node: '>= 0.4'}
+
+ string.prototype.trimend@1.0.8:
+ resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==}
+
+ string.prototype.trimstart@1.0.8:
+ resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
+ engines: {node: '>= 0.4'}
+
string_decoder@1.1.1:
resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
@@ -4891,8 +5192,8 @@ packages:
style-to-object@1.0.6:
resolution: {integrity: sha512-khxq+Qm3xEyZfKd/y9L3oIWQimxuc4STrQKtQn8aSDRHb8mFgpukgX1hdzfrMEW6JCjyJ8p89x+IUMVnCBI1PA==}
- styled-components@6.1.11:
- resolution: {integrity: sha512-Ui0jXPzbp1phYij90h12ksljKGqF8ncGx+pjrNPsSPhbUUjWT2tD1FwGo2LF6USCnbrsIhNngDfodhxbegfEOA==}
+ styled-components@6.1.12:
+ resolution: {integrity: sha512-n/O4PzRPhbYI0k1vKKayfti3C/IGcPf+DqcrOB7O/ab9x4u/zjqraneT5N45+sIe87cxrCApXM8Bna7NYxwoTA==}
engines: {node: '>= 16'}
peerDependencies:
react: '>= 16.8.0'
@@ -4962,8 +5263,8 @@ packages:
uglify-js:
optional: true
- terser@5.31.1:
- resolution: {integrity: sha512-37upzU1+viGvuFtBo9NPufCb9dwM0+l9hMxYyWfBA+fbwrPqNJAhbZ6W47bBFnZHKHTUBnMvi87434qq+qnxOg==}
+ terser@5.31.6:
+ resolution: {integrity: sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==}
engines: {node: '>=10'}
hasBin: true
@@ -5030,25 +5331,48 @@ packages:
resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==}
engines: {node: '>=12.20'}
- type-fest@4.20.1:
- resolution: {integrity: sha512-R6wDsVsoS9xYOpy8vgeBlqpdOyzJ12HNfQhC/aAKWM3YoCV9TtunJzh/QpkMgeDhkoynDcw5f1y+qF9yc/HHyg==}
+ type-fest@4.24.0:
+ resolution: {integrity: sha512-spAaHzc6qre0TlZQQ2aA/nGMe+2Z/wyGk5Z+Ru2VUfdNwT6kWO6TjevOlpebsATEG1EIQ2sOiDszud3lO5mt/Q==}
engines: {node: '>=16'}
type-is@1.6.18:
resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
engines: {node: '>= 0.6'}
+ typed-array-buffer@1.0.2:
+ resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==}
+ engines: {node: '>= 0.4'}
+
+ typed-array-byte-length@1.0.1:
+ resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==}
+ engines: {node: '>= 0.4'}
+
+ typed-array-byte-offset@1.0.2:
+ resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==}
+ engines: {node: '>= 0.4'}
+
+ typed-array-length@1.0.6:
+ resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==}
+ engines: {node: '>= 0.4'}
+
typedarray-to-buffer@3.1.5:
resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==}
- typescript@5.4.5:
- resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==}
+ typescript@5.5.4:
+ resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==}
engines: {node: '>=14.17'}
hasBin: true
+ unbox-primitive@1.0.2:
+ resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
+
undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
+ undici@6.19.7:
+ resolution: {integrity: sha512-HR3W/bMGPSr90i8AAp2C4DM3wChFdJPLrWYpIS++LxS8K+W535qftjt+4MyjNYHeWabMj1nvtmLIi7l++iq91A==}
+ engines: {node: '>=18.17'}
+
unicode-canonical-property-names-ecmascript@2.0.0:
resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==}
engines: {node: '>=4'}
@@ -5069,8 +5393,8 @@ packages:
resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==}
engines: {node: '>=4'}
- unified@11.0.4:
- resolution: {integrity: sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==}
+ unified@11.0.5:
+ resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
unique-string@3.0.0:
resolution: {integrity: sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==}
@@ -5109,8 +5433,8 @@ packages:
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
engines: {node: '>= 0.8'}
- update-browserslist-db@1.0.16:
- resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==}
+ update-browserslist-db@1.1.0:
+ resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==}
hasBin: true
peerDependencies:
browserslist: '>= 4.21.0'
@@ -5138,6 +5462,11 @@ packages:
url-template@2.0.8:
resolution: {integrity: sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==}
+ use-sync-external-store@1.2.2:
+ resolution: {integrity: sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
@@ -5163,21 +5492,21 @@ packages:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'}
- vfile-location@5.0.2:
- resolution: {integrity: sha512-NXPYyxyBSH7zB5U6+3uDdd6Nybz6o6/od9rk8bp9H8GR3L+cm/fC0uUTbqBmUTnMCUDslAGBOIKNfvvb+gGlDg==}
+ vfile-location@5.0.3:
+ resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==}
vfile-message@4.0.2:
resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==}
- vfile@6.0.1:
- resolution: {integrity: sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==}
+ vfile@6.0.2:
+ resolution: {integrity: sha512-zND7NlS8rJYb/sPqkb13ZvbbUoExdbi4w3SfRrMq6R3FvnLQmmfpajJNITuuYm6AZ5uao9vy4BAos3EXBPf2rg==}
w3c-xmlserializer@5.0.0:
resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
engines: {node: '>=18'}
- watchpack@2.4.1:
- resolution: {integrity: sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==}
+ watchpack@2.4.2:
+ resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==}
engines: {node: '>=10.13.0'}
wbuf@1.7.3:
@@ -5228,8 +5557,8 @@ packages:
resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==}
engines: {node: '>=10.13.0'}
- webpack@5.92.0:
- resolution: {integrity: sha512-Bsw2X39MYIgxouNATyVpCNVWBCuUwDgWtN78g6lSdPJRLaQ/PUVm/oXcaRAyY/sMFoKFQrsPeqvTizWtq7QPCA==}
+ webpack@5.93.0:
+ resolution: {integrity: sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA==}
engines: {node: '>=10.13.0'}
hasBin: true
peerDependencies:
@@ -5267,6 +5596,13 @@ packages:
whatwg-url@5.0.0:
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
+ which-boxed-primitive@1.0.2:
+ resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
+
+ which-typed-array@1.1.15:
+ resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==}
+ engines: {node: '>= 0.4'}
+
which@1.3.1:
resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
hasBin: true
@@ -5309,8 +5645,8 @@ packages:
utf-8-validate:
optional: true
- ws@8.17.1:
- resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==}
+ ws@8.18.0:
+ resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
@@ -5350,8 +5686,8 @@ packages:
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
engines: {node: '>= 6'}
- yaml@2.4.5:
- resolution: {integrity: sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==}
+ yaml@2.5.0:
+ resolution: {integrity: sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==}
engines: {node: '>= 14'}
hasBin: true
@@ -5367,8 +5703,8 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
- yocto-queue@1.0.0:
- resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==}
+ yocto-queue@1.1.1:
+ resolution: {integrity: sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==}
engines: {node: '>=12.20'}
zwitch@2.0.4:
@@ -5376,111 +5712,111 @@ packages:
snapshots:
- '@algolia/autocomplete-core@1.9.3(@algolia/client-search@4.23.3)(algoliasearch@4.23.3)(search-insights@2.14.0)':
+ '@algolia/autocomplete-core@1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)(search-insights@2.15.0)':
dependencies:
- '@algolia/autocomplete-plugin-algolia-insights': 1.9.3(@algolia/client-search@4.23.3)(algoliasearch@4.23.3)(search-insights@2.14.0)
- '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.23.3)(algoliasearch@4.23.3)
+ '@algolia/autocomplete-plugin-algolia-insights': 1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)(search-insights@2.15.0)
+ '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)
transitivePeerDependencies:
- '@algolia/client-search'
- algoliasearch
- search-insights
- '@algolia/autocomplete-plugin-algolia-insights@1.9.3(@algolia/client-search@4.23.3)(algoliasearch@4.23.3)(search-insights@2.14.0)':
+ '@algolia/autocomplete-plugin-algolia-insights@1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)(search-insights@2.15.0)':
dependencies:
- '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.23.3)(algoliasearch@4.23.3)
- search-insights: 2.14.0
+ '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)
+ search-insights: 2.15.0
transitivePeerDependencies:
- '@algolia/client-search'
- algoliasearch
- '@algolia/autocomplete-preset-algolia@1.9.3(@algolia/client-search@4.23.3)(algoliasearch@4.23.3)':
+ '@algolia/autocomplete-preset-algolia@1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)':
dependencies:
- '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.23.3)(algoliasearch@4.23.3)
- '@algolia/client-search': 4.23.3
- algoliasearch: 4.23.3
+ '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)
+ '@algolia/client-search': 4.24.0
+ algoliasearch: 4.24.0
- '@algolia/autocomplete-shared@1.9.3(@algolia/client-search@4.23.3)(algoliasearch@4.23.3)':
+ '@algolia/autocomplete-shared@1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)':
dependencies:
- '@algolia/client-search': 4.23.3
- algoliasearch: 4.23.3
+ '@algolia/client-search': 4.24.0
+ algoliasearch: 4.24.0
- '@algolia/cache-browser-local-storage@4.23.3':
+ '@algolia/cache-browser-local-storage@4.24.0':
dependencies:
- '@algolia/cache-common': 4.23.3
+ '@algolia/cache-common': 4.24.0
- '@algolia/cache-common@4.23.3': {}
+ '@algolia/cache-common@4.24.0': {}
- '@algolia/cache-in-memory@4.23.3':
+ '@algolia/cache-in-memory@4.24.0':
dependencies:
- '@algolia/cache-common': 4.23.3
+ '@algolia/cache-common': 4.24.0
- '@algolia/client-account@4.23.3':
+ '@algolia/client-account@4.24.0':
dependencies:
- '@algolia/client-common': 4.23.3
- '@algolia/client-search': 4.23.3
- '@algolia/transporter': 4.23.3
+ '@algolia/client-common': 4.24.0
+ '@algolia/client-search': 4.24.0
+ '@algolia/transporter': 4.24.0
- '@algolia/client-analytics@4.23.3':
+ '@algolia/client-analytics@4.24.0':
dependencies:
- '@algolia/client-common': 4.23.3
- '@algolia/client-search': 4.23.3
- '@algolia/requester-common': 4.23.3
- '@algolia/transporter': 4.23.3
+ '@algolia/client-common': 4.24.0
+ '@algolia/client-search': 4.24.0
+ '@algolia/requester-common': 4.24.0
+ '@algolia/transporter': 4.24.0
- '@algolia/client-common@4.23.3':
+ '@algolia/client-common@4.24.0':
dependencies:
- '@algolia/requester-common': 4.23.3
- '@algolia/transporter': 4.23.3
+ '@algolia/requester-common': 4.24.0
+ '@algolia/transporter': 4.24.0
- '@algolia/client-personalization@4.23.3':
+ '@algolia/client-personalization@4.24.0':
dependencies:
- '@algolia/client-common': 4.23.3
- '@algolia/requester-common': 4.23.3
- '@algolia/transporter': 4.23.3
+ '@algolia/client-common': 4.24.0
+ '@algolia/requester-common': 4.24.0
+ '@algolia/transporter': 4.24.0
- '@algolia/client-search@4.23.3':
+ '@algolia/client-search@4.24.0':
dependencies:
- '@algolia/client-common': 4.23.3
- '@algolia/requester-common': 4.23.3
- '@algolia/transporter': 4.23.3
+ '@algolia/client-common': 4.24.0
+ '@algolia/requester-common': 4.24.0
+ '@algolia/transporter': 4.24.0
'@algolia/events@4.0.1': {}
- '@algolia/logger-common@4.23.3': {}
+ '@algolia/logger-common@4.24.0': {}
- '@algolia/logger-console@4.23.3':
+ '@algolia/logger-console@4.24.0':
dependencies:
- '@algolia/logger-common': 4.23.3
+ '@algolia/logger-common': 4.24.0
- '@algolia/recommend@4.23.3':
+ '@algolia/recommend@4.24.0':
dependencies:
- '@algolia/cache-browser-local-storage': 4.23.3
- '@algolia/cache-common': 4.23.3
- '@algolia/cache-in-memory': 4.23.3
- '@algolia/client-common': 4.23.3
- '@algolia/client-search': 4.23.3
- '@algolia/logger-common': 4.23.3
- '@algolia/logger-console': 4.23.3
- '@algolia/requester-browser-xhr': 4.23.3
- '@algolia/requester-common': 4.23.3
- '@algolia/requester-node-http': 4.23.3
- '@algolia/transporter': 4.23.3
+ '@algolia/cache-browser-local-storage': 4.24.0
+ '@algolia/cache-common': 4.24.0
+ '@algolia/cache-in-memory': 4.24.0
+ '@algolia/client-common': 4.24.0
+ '@algolia/client-search': 4.24.0
+ '@algolia/logger-common': 4.24.0
+ '@algolia/logger-console': 4.24.0
+ '@algolia/requester-browser-xhr': 4.24.0
+ '@algolia/requester-common': 4.24.0
+ '@algolia/requester-node-http': 4.24.0
+ '@algolia/transporter': 4.24.0
- '@algolia/requester-browser-xhr@4.23.3':
+ '@algolia/requester-browser-xhr@4.24.0':
dependencies:
- '@algolia/requester-common': 4.23.3
+ '@algolia/requester-common': 4.24.0
- '@algolia/requester-common@4.23.3': {}
+ '@algolia/requester-common@4.24.0': {}
- '@algolia/requester-node-http@4.23.3':
+ '@algolia/requester-node-http@4.24.0':
dependencies:
- '@algolia/requester-common': 4.23.3
+ '@algolia/requester-common': 4.24.0
- '@algolia/transporter@4.23.3':
+ '@algolia/transporter@4.24.0':
dependencies:
- '@algolia/cache-common': 4.23.3
- '@algolia/logger-common': 4.23.3
- '@algolia/requester-common': 4.23.3
+ '@algolia/cache-common': 4.24.0
+ '@algolia/logger-common': 4.24.0
+ '@algolia/requester-common': 4.24.0
'@ampproject/remapping@2.3.0':
dependencies:
@@ -5492,186 +5828,165 @@ snapshots:
'@babel/highlight': 7.24.7
picocolors: 1.0.1
- '@babel/compat-data@7.24.7': {}
+ '@babel/compat-data@7.25.2': {}
- '@babel/core@7.24.7':
+ '@babel/core@7.25.2':
dependencies:
'@ampproject/remapping': 2.3.0
'@babel/code-frame': 7.24.7
- '@babel/generator': 7.24.7
- '@babel/helper-compilation-targets': 7.24.7
- '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7)
- '@babel/helpers': 7.24.7
- '@babel/parser': 7.24.7
- '@babel/template': 7.24.7
- '@babel/traverse': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/generator': 7.25.0
+ '@babel/helper-compilation-targets': 7.25.2
+ '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2)
+ '@babel/helpers': 7.25.0
+ '@babel/parser': 7.25.3
+ '@babel/template': 7.25.0
+ '@babel/traverse': 7.25.3
+ '@babel/types': 7.25.2
convert-source-map: 2.0.0
- debug: 4.3.5
+ debug: 4.3.6
gensync: 1.0.0-beta.2
json5: 2.2.3
- semver: 6.3.1
+ semver: 7.6.3
transitivePeerDependencies:
- supports-color
- '@babel/generator@7.24.7':
+ '@babel/generator@7.25.0':
dependencies:
- '@babel/types': 7.24.7
+ '@babel/types': 7.25.2
'@jridgewell/gen-mapping': 0.3.5
'@jridgewell/trace-mapping': 0.3.25
jsesc: 2.5.2
'@babel/helper-annotate-as-pure@7.24.7':
dependencies:
- '@babel/types': 7.24.7
+ '@babel/types': 7.25.2
'@babel/helper-builder-binary-assignment-operator-visitor@7.24.7':
dependencies:
- '@babel/traverse': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/traverse': 7.25.3
+ '@babel/types': 7.25.2
transitivePeerDependencies:
- supports-color
- '@babel/helper-compilation-targets@7.24.7':
+ '@babel/helper-compilation-targets@7.25.2':
dependencies:
- '@babel/compat-data': 7.24.7
- '@babel/helper-validator-option': 7.24.7
- browserslist: 4.23.1
+ '@babel/compat-data': 7.25.2
+ '@babel/helper-validator-option': 7.24.8
+ browserslist: 4.23.2
lru-cache: 5.1.1
semver: 6.3.1
- '@babel/helper-create-class-features-plugin@7.24.7(@babel/core@7.24.7)':
+ '@babel/helper-create-class-features-plugin@7.25.0(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
+ '@babel/core': 7.25.2
'@babel/helper-annotate-as-pure': 7.24.7
- '@babel/helper-environment-visitor': 7.24.7
- '@babel/helper-function-name': 7.24.7
- '@babel/helper-member-expression-to-functions': 7.24.7
+ '@babel/helper-member-expression-to-functions': 7.24.8
'@babel/helper-optimise-call-expression': 7.24.7
- '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.7)
+ '@babel/helper-replace-supers': 7.25.0(@babel/core@7.25.2)
'@babel/helper-skip-transparent-expression-wrappers': 7.24.7
- '@babel/helper-split-export-declaration': 7.24.7
+ '@babel/traverse': 7.25.3
semver: 6.3.1
transitivePeerDependencies:
- supports-color
- '@babel/helper-create-regexp-features-plugin@7.24.7(@babel/core@7.24.7)':
+ '@babel/helper-create-regexp-features-plugin@7.25.2(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
+ '@babel/core': 7.25.2
'@babel/helper-annotate-as-pure': 7.24.7
regexpu-core: 5.3.2
semver: 6.3.1
- '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.24.7)':
+ '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-compilation-targets': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
- debug: 4.3.5
+ '@babel/core': 7.25.2
+ '@babel/helper-compilation-targets': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+ debug: 4.3.6
lodash.debounce: 4.0.8
resolve: 1.22.8
transitivePeerDependencies:
- supports-color
- '@babel/helper-environment-visitor@7.24.7':
+ '@babel/helper-member-expression-to-functions@7.24.8':
dependencies:
- '@babel/types': 7.24.7
-
- '@babel/helper-function-name@7.24.7':
- dependencies:
- '@babel/template': 7.24.7
- '@babel/types': 7.24.7
-
- '@babel/helper-hoist-variables@7.24.7':
- dependencies:
- '@babel/types': 7.24.7
-
- '@babel/helper-member-expression-to-functions@7.24.7':
- dependencies:
- '@babel/traverse': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/traverse': 7.25.3
+ '@babel/types': 7.25.2
transitivePeerDependencies:
- supports-color
'@babel/helper-module-imports@7.24.7':
dependencies:
- '@babel/traverse': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/traverse': 7.25.3
+ '@babel/types': 7.25.2
transitivePeerDependencies:
- supports-color
- '@babel/helper-module-transforms@7.24.7(@babel/core@7.24.7)':
+ '@babel/helper-module-transforms@7.25.2(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-environment-visitor': 7.24.7
+ '@babel/core': 7.25.2
'@babel/helper-module-imports': 7.24.7
'@babel/helper-simple-access': 7.24.7
- '@babel/helper-split-export-declaration': 7.24.7
'@babel/helper-validator-identifier': 7.24.7
+ '@babel/traverse': 7.25.3
transitivePeerDependencies:
- supports-color
'@babel/helper-optimise-call-expression@7.24.7':
dependencies:
- '@babel/types': 7.24.7
+ '@babel/types': 7.25.2
- '@babel/helper-plugin-utils@7.24.7': {}
+ '@babel/helper-plugin-utils@7.24.8': {}
- '@babel/helper-remap-async-to-generator@7.24.7(@babel/core@7.24.7)':
+ '@babel/helper-remap-async-to-generator@7.25.0(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
+ '@babel/core': 7.25.2
'@babel/helper-annotate-as-pure': 7.24.7
- '@babel/helper-environment-visitor': 7.24.7
- '@babel/helper-wrap-function': 7.24.7
+ '@babel/helper-wrap-function': 7.25.0
+ '@babel/traverse': 7.25.3
transitivePeerDependencies:
- supports-color
- '@babel/helper-replace-supers@7.24.7(@babel/core@7.24.7)':
+ '@babel/helper-replace-supers@7.25.0(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-environment-visitor': 7.24.7
- '@babel/helper-member-expression-to-functions': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-member-expression-to-functions': 7.24.8
'@babel/helper-optimise-call-expression': 7.24.7
+ '@babel/traverse': 7.25.3
transitivePeerDependencies:
- supports-color
'@babel/helper-simple-access@7.24.7':
dependencies:
- '@babel/traverse': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/traverse': 7.25.3
+ '@babel/types': 7.25.2
transitivePeerDependencies:
- supports-color
'@babel/helper-skip-transparent-expression-wrappers@7.24.7':
dependencies:
- '@babel/traverse': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/traverse': 7.25.3
+ '@babel/types': 7.25.2
transitivePeerDependencies:
- supports-color
- '@babel/helper-split-export-declaration@7.24.7':
- dependencies:
- '@babel/types': 7.24.7
-
- '@babel/helper-string-parser@7.24.7': {}
+ '@babel/helper-string-parser@7.24.8': {}
'@babel/helper-validator-identifier@7.24.7': {}
- '@babel/helper-validator-option@7.24.7': {}
+ '@babel/helper-validator-option@7.24.8': {}
- '@babel/helper-wrap-function@7.24.7':
+ '@babel/helper-wrap-function@7.25.0':
dependencies:
- '@babel/helper-function-name': 7.24.7
- '@babel/template': 7.24.7
- '@babel/traverse': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/template': 7.25.0
+ '@babel/traverse': 7.25.3
+ '@babel/types': 7.25.2
transitivePeerDependencies:
- supports-color
- '@babel/helpers@7.24.7':
+ '@babel/helpers@7.25.0':
dependencies:
- '@babel/template': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/template': 7.25.0
+ '@babel/types': 7.25.2
'@babel/highlight@7.24.7':
dependencies:
@@ -5680,716 +5995,840 @@ snapshots:
js-tokens: 4.0.0
picocolors: 1.0.1
- '@babel/parser@7.24.7':
+ '@babel/parser@7.25.3':
dependencies:
- '@babel/types': 7.24.7
+ '@babel/types': 7.25.2
- '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.0(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-environment-visitor': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/traverse': 7.25.3
+ transitivePeerDependencies:
+ - supports-color
- '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.3(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/traverse': 7.25.3
+ transitivePeerDependencies:
+ - supports-color
- '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.0(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.0(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.7(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
'@babel/helper-skip-transparent-expression-wrappers': 7.24.7
- '@babel/plugin-transform-optional-chaining': 7.24.7(@babel/core@7.24.7)
+ '@babel/plugin-transform-optional-chaining': 7.24.8(@babel/core@7.25.2)
transitivePeerDependencies:
- supports-color
- '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.0(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-environment-visitor': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
-
- '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-import-assertions@7.24.7(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-import-attributes@7.24.7(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-typescript@7.24.7(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7)
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-transform-arrow-functions@7.24.7(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-transform-async-generator-functions@7.24.7(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-environment-visitor': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
- '@babel/helper-remap-async-to-generator': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.7)
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/traverse': 7.25.3
transitivePeerDependencies:
- supports-color
- '@babel/plugin-transform-async-to-generator@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
+ '@babel/core': 7.25.2
+
+ '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-syntax-import-assertions@7.24.7(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-syntax-import-attributes@7.24.7(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-syntax-typescript@7.24.7(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2)
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-transform-arrow-functions@7.24.7(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-transform-async-generator-functions@7.25.0(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/helper-remap-async-to-generator': 7.25.0(@babel/core@7.25.2)
+ '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.25.2)
+ '@babel/traverse': 7.25.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/plugin-transform-async-to-generator@7.24.7(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
'@babel/helper-module-imports': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
- '@babel/helper-remap-async-to-generator': 7.24.7(@babel/core@7.24.7)
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/helper-remap-async-to-generator': 7.25.0(@babel/core@7.25.2)
transitivePeerDependencies:
- supports-color
- '@babel/plugin-transform-block-scoped-functions@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-block-scoped-functions@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
- '@babel/plugin-transform-block-scoping@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-block-scoping@7.25.0(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
- '@babel/plugin-transform-class-properties@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-class-properties@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7)
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-create-class-features-plugin': 7.25.0(@babel/core@7.25.2)
+ '@babel/helper-plugin-utils': 7.24.8
transitivePeerDependencies:
- supports-color
- '@babel/plugin-transform-class-static-block@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-class-static-block@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7)
- '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.7)
+ '@babel/core': 7.25.2
+ '@babel/helper-create-class-features-plugin': 7.25.0(@babel/core@7.25.2)
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.25.2)
transitivePeerDependencies:
- supports-color
- '@babel/plugin-transform-classes@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-classes@7.25.0(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
+ '@babel/core': 7.25.2
'@babel/helper-annotate-as-pure': 7.24.7
- '@babel/helper-compilation-targets': 7.24.7
- '@babel/helper-environment-visitor': 7.24.7
- '@babel/helper-function-name': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
- '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.7)
- '@babel/helper-split-export-declaration': 7.24.7
+ '@babel/helper-compilation-targets': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/helper-replace-supers': 7.25.0(@babel/core@7.25.2)
+ '@babel/traverse': 7.25.3
globals: 11.12.0
transitivePeerDependencies:
- supports-color
- '@babel/plugin-transform-computed-properties@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-computed-properties@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
- '@babel/template': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/template': 7.25.0
- '@babel/plugin-transform-destructuring@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-destructuring@7.24.8(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
- '@babel/plugin-transform-dotall-regex@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-dotall-regex@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7)
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2)
+ '@babel/helper-plugin-utils': 7.24.8
- '@babel/plugin-transform-duplicate-keys@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-duplicate-keys@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
- '@babel/plugin-transform-dynamic-import@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.0(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.7)
+ '@babel/core': 7.25.2
+ '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2)
+ '@babel/helper-plugin-utils': 7.24.8
- '@babel/plugin-transform-exponentiation-operator@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-dynamic-import@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.25.2)
+
+ '@babel/plugin-transform-exponentiation-operator@7.24.7(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
'@babel/helper-builder-binary-assignment-operator-visitor': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.8
transitivePeerDependencies:
- supports-color
- '@babel/plugin-transform-export-namespace-from@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-export-namespace-from@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.7)
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.25.2)
- '@babel/plugin-transform-for-of@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-for-of@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
'@babel/helper-skip-transparent-expression-wrappers': 7.24.7
transitivePeerDependencies:
- supports-color
- '@babel/plugin-transform-function-name@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-function-name@7.25.1(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-compilation-targets': 7.24.7
- '@babel/helper-function-name': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-transform-json-strings@7.24.7(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.7)
-
- '@babel/plugin-transform-literals@7.24.7(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-transform-logical-assignment-operators@7.24.7(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.7)
-
- '@babel/plugin-transform-member-expression-literals@7.24.7(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
-
- '@babel/plugin-transform-modules-amd@7.24.7(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7)
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-compilation-targets': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/traverse': 7.25.3
transitivePeerDependencies:
- supports-color
- '@babel/plugin-transform-modules-commonjs@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-json-strings@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7)
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.25.2)
+
+ '@babel/plugin-transform-literals@7.25.2(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-transform-logical-assignment-operators@7.24.7(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.25.2)
+
+ '@babel/plugin-transform-member-expression-literals@7.24.7(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+
+ '@babel/plugin-transform-modules-amd@7.24.7(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2)
+ '@babel/helper-plugin-utils': 7.24.8
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/plugin-transform-modules-commonjs@7.24.8(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2)
+ '@babel/helper-plugin-utils': 7.24.8
'@babel/helper-simple-access': 7.24.7
transitivePeerDependencies:
- supports-color
- '@babel/plugin-transform-modules-systemjs@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-modules-systemjs@7.25.0(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-hoist-variables': 7.24.7
- '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7)
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2)
+ '@babel/helper-plugin-utils': 7.24.8
'@babel/helper-validator-identifier': 7.24.7
+ '@babel/traverse': 7.25.3
transitivePeerDependencies:
- supports-color
- '@babel/plugin-transform-modules-umd@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-modules-umd@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7)
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2)
+ '@babel/helper-plugin-utils': 7.24.8
transitivePeerDependencies:
- supports-color
- '@babel/plugin-transform-named-capturing-groups-regex@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-named-capturing-groups-regex@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7)
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2)
+ '@babel/helper-plugin-utils': 7.24.8
- '@babel/plugin-transform-new-target@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-new-target@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
- '@babel/plugin-transform-nullish-coalescing-operator@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-nullish-coalescing-operator@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.7)
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2)
- '@babel/plugin-transform-numeric-separator@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-numeric-separator@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.7)
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2)
- '@babel/plugin-transform-object-rest-spread@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-object-rest-spread@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-compilation-targets': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.7)
- '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.24.7)
+ '@babel/core': 7.25.2
+ '@babel/helper-compilation-targets': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2)
+ '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.25.2)
- '@babel/plugin-transform-object-super@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-object-super@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
- '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.7)
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/helper-replace-supers': 7.25.0(@babel/core@7.25.2)
transitivePeerDependencies:
- supports-color
- '@babel/plugin-transform-optional-catch-binding@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-optional-catch-binding@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.7)
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2)
- '@babel/plugin-transform-optional-chaining@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-optional-chaining@7.24.8(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
'@babel/helper-skip-transparent-expression-wrappers': 7.24.7
- '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.7)
+ '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.25.2)
transitivePeerDependencies:
- supports-color
- '@babel/plugin-transform-parameters@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-parameters@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
- '@babel/plugin-transform-private-methods@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-private-methods@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7)
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-create-class-features-plugin': 7.25.0(@babel/core@7.25.2)
+ '@babel/helper-plugin-utils': 7.24.8
transitivePeerDependencies:
- supports-color
- '@babel/plugin-transform-private-property-in-object@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-private-property-in-object@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
+ '@babel/core': 7.25.2
'@babel/helper-annotate-as-pure': 7.24.7
- '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7)
- '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.7)
+ '@babel/helper-create-class-features-plugin': 7.25.0(@babel/core@7.25.2)
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.25.2)
transitivePeerDependencies:
- supports-color
- '@babel/plugin-transform-property-literals@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-property-literals@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
- '@babel/plugin-transform-react-constant-elements@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-react-constant-elements@7.25.1(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
- '@babel/plugin-transform-react-display-name@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-react-display-name@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
- '@babel/plugin-transform-react-jsx-development@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-react-jsx-development@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/plugin-transform-react-jsx': 7.24.7(@babel/core@7.24.7)
+ '@babel/core': 7.25.2
+ '@babel/plugin-transform-react-jsx': 7.25.2(@babel/core@7.25.2)
transitivePeerDependencies:
- supports-color
- '@babel/plugin-transform-react-jsx@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
+ '@babel/core': 7.25.2
'@babel/helper-annotate-as-pure': 7.24.7
'@babel/helper-module-imports': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.24.7)
- '@babel/types': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.25.2)
+ '@babel/types': 7.25.2
transitivePeerDependencies:
- supports-color
- '@babel/plugin-transform-react-pure-annotations@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-react-pure-annotations@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
+ '@babel/core': 7.25.2
'@babel/helper-annotate-as-pure': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/helper-plugin-utils': 7.24.8
- '@babel/plugin-transform-regenerator@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-regenerator@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
regenerator-transform: 0.15.2
- '@babel/plugin-transform-reserved-words@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-reserved-words@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
- '@babel/plugin-transform-runtime@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-runtime@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
+ '@babel/core': 7.25.2
'@babel/helper-module-imports': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
- babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.24.7)
- babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.7)
- babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.24.7)
+ '@babel/helper-plugin-utils': 7.24.8
+ babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.25.2)
+ babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.25.2)
+ babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.25.2)
semver: 6.3.1
transitivePeerDependencies:
- supports-color
- '@babel/plugin-transform-shorthand-properties@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-shorthand-properties@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
- '@babel/plugin-transform-spread@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-spread@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
'@babel/helper-skip-transparent-expression-wrappers': 7.24.7
transitivePeerDependencies:
- supports-color
- '@babel/plugin-transform-sticky-regex@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-sticky-regex@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
- '@babel/plugin-transform-template-literals@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-template-literals@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
- '@babel/plugin-transform-typeof-symbol@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-typeof-symbol@7.24.8(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
- '@babel/plugin-transform-typescript@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-typescript@7.25.2(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
+ '@babel/core': 7.25.2
'@babel/helper-annotate-as-pure': 7.24.7
- '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7)
- '@babel/helper-plugin-utils': 7.24.7
- '@babel/plugin-syntax-typescript': 7.24.7(@babel/core@7.24.7)
+ '@babel/helper-create-class-features-plugin': 7.25.0(@babel/core@7.25.2)
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/helper-skip-transparent-expression-wrappers': 7.24.7
+ '@babel/plugin-syntax-typescript': 7.24.7(@babel/core@7.25.2)
transitivePeerDependencies:
- supports-color
- '@babel/plugin-transform-unicode-escapes@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-unicode-escapes@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
- '@babel/plugin-transform-unicode-property-regex@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-unicode-property-regex@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7)
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2)
+ '@babel/helper-plugin-utils': 7.24.8
- '@babel/plugin-transform-unicode-regex@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-unicode-regex@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7)
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2)
+ '@babel/helper-plugin-utils': 7.24.8
- '@babel/plugin-transform-unicode-sets-regex@7.24.7(@babel/core@7.24.7)':
+ '@babel/plugin-transform-unicode-sets-regex@7.24.7(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7)
- '@babel/helper-plugin-utils': 7.24.7
+ '@babel/core': 7.25.2
+ '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2)
+ '@babel/helper-plugin-utils': 7.24.8
- '@babel/preset-env@7.24.7(@babel/core@7.24.7)':
+ '@babel/preset-env@7.25.2(@babel/core@7.25.2)':
dependencies:
- '@babel/compat-data': 7.24.7
- '@babel/core': 7.24.7
- '@babel/helper-compilation-targets': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
- '@babel/helper-validator-option': 7.24.7
- '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.7)
- '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.7)
- '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.7)
- '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.7)
- '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.7)
- '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.7)
- '@babel/plugin-syntax-import-assertions': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-syntax-import-attributes': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.7)
- '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.7)
- '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.7)
- '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.7)
- '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.7)
- '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.7)
- '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.7)
- '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.7)
- '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.7)
- '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.7)
- '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.24.7)
- '@babel/plugin-transform-arrow-functions': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-async-generator-functions': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-async-to-generator': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-block-scoped-functions': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-block-scoping': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-class-properties': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-class-static-block': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-classes': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-computed-properties': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-destructuring': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-dotall-regex': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-duplicate-keys': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-dynamic-import': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-exponentiation-operator': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-export-namespace-from': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-for-of': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-function-name': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-json-strings': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-literals': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-logical-assignment-operators': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-member-expression-literals': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-modules-amd': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-modules-commonjs': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-modules-systemjs': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-modules-umd': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-named-capturing-groups-regex': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-new-target': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-nullish-coalescing-operator': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-numeric-separator': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-object-rest-spread': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-object-super': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-optional-catch-binding': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-optional-chaining': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-private-methods': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-private-property-in-object': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-property-literals': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-regenerator': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-reserved-words': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-shorthand-properties': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-spread': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-sticky-regex': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-template-literals': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-typeof-symbol': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-unicode-escapes': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-unicode-property-regex': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-unicode-regex': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-unicode-sets-regex': 7.24.7(@babel/core@7.24.7)
- '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.24.7)
- babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.24.7)
- babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.7)
- babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.24.7)
+ '@babel/compat-data': 7.25.2
+ '@babel/core': 7.25.2
+ '@babel/helper-compilation-targets': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/helper-validator-option': 7.24.8
+ '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.25.0(@babel/core@7.25.2)
+ '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.25.0(@babel/core@7.25.2)
+ '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.25.0(@babel/core@7.25.2)
+ '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.25.0(@babel/core@7.25.2)
+ '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.25.2)
+ '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.25.2)
+ '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.25.2)
+ '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.25.2)
+ '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.25.2)
+ '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.25.2)
+ '@babel/plugin-syntax-import-assertions': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-syntax-import-attributes': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.25.2)
+ '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.25.2)
+ '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.25.2)
+ '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2)
+ '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2)
+ '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2)
+ '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2)
+ '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.25.2)
+ '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.25.2)
+ '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.25.2)
+ '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.25.2)
+ '@babel/plugin-transform-arrow-functions': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-async-generator-functions': 7.25.0(@babel/core@7.25.2)
+ '@babel/plugin-transform-async-to-generator': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-block-scoped-functions': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-block-scoping': 7.25.0(@babel/core@7.25.2)
+ '@babel/plugin-transform-class-properties': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-class-static-block': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-classes': 7.25.0(@babel/core@7.25.2)
+ '@babel/plugin-transform-computed-properties': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-destructuring': 7.24.8(@babel/core@7.25.2)
+ '@babel/plugin-transform-dotall-regex': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-duplicate-keys': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.25.0(@babel/core@7.25.2)
+ '@babel/plugin-transform-dynamic-import': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-exponentiation-operator': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-export-namespace-from': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-for-of': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-function-name': 7.25.1(@babel/core@7.25.2)
+ '@babel/plugin-transform-json-strings': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-literals': 7.25.2(@babel/core@7.25.2)
+ '@babel/plugin-transform-logical-assignment-operators': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-member-expression-literals': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-modules-amd': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-modules-commonjs': 7.24.8(@babel/core@7.25.2)
+ '@babel/plugin-transform-modules-systemjs': 7.25.0(@babel/core@7.25.2)
+ '@babel/plugin-transform-modules-umd': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-named-capturing-groups-regex': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-new-target': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-nullish-coalescing-operator': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-numeric-separator': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-object-rest-spread': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-object-super': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-optional-catch-binding': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-optional-chaining': 7.24.8(@babel/core@7.25.2)
+ '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-private-methods': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-private-property-in-object': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-property-literals': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-regenerator': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-reserved-words': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-shorthand-properties': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-spread': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-sticky-regex': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-template-literals': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-typeof-symbol': 7.24.8(@babel/core@7.25.2)
+ '@babel/plugin-transform-unicode-escapes': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-unicode-property-regex': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-unicode-regex': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-unicode-sets-regex': 7.24.7(@babel/core@7.25.2)
+ '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.25.2)
+ babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.25.2)
+ babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.25.2)
+ babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.25.2)
core-js-compat: 3.37.1
semver: 6.3.1
transitivePeerDependencies:
- supports-color
- '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.7)':
+ '@babel/preset-env@7.25.3(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
- '@babel/types': 7.24.7
- esutils: 2.0.3
-
- '@babel/preset-react@7.24.7(@babel/core@7.24.7)':
- dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
- '@babel/helper-validator-option': 7.24.7
- '@babel/plugin-transform-react-display-name': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-react-jsx': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-react-jsx-development': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-react-pure-annotations': 7.24.7(@babel/core@7.24.7)
+ '@babel/compat-data': 7.25.2
+ '@babel/core': 7.25.2
+ '@babel/helper-compilation-targets': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/helper-validator-option': 7.24.8
+ '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.25.3(@babel/core@7.25.2)
+ '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.25.0(@babel/core@7.25.2)
+ '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.25.0(@babel/core@7.25.2)
+ '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.25.0(@babel/core@7.25.2)
+ '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.25.2)
+ '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.25.2)
+ '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.25.2)
+ '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.25.2)
+ '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.25.2)
+ '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.25.2)
+ '@babel/plugin-syntax-import-assertions': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-syntax-import-attributes': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.25.2)
+ '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.25.2)
+ '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.25.2)
+ '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2)
+ '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2)
+ '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2)
+ '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2)
+ '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.25.2)
+ '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.25.2)
+ '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.25.2)
+ '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.25.2)
+ '@babel/plugin-transform-arrow-functions': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-async-generator-functions': 7.25.0(@babel/core@7.25.2)
+ '@babel/plugin-transform-async-to-generator': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-block-scoped-functions': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-block-scoping': 7.25.0(@babel/core@7.25.2)
+ '@babel/plugin-transform-class-properties': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-class-static-block': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-classes': 7.25.0(@babel/core@7.25.2)
+ '@babel/plugin-transform-computed-properties': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-destructuring': 7.24.8(@babel/core@7.25.2)
+ '@babel/plugin-transform-dotall-regex': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-duplicate-keys': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.25.0(@babel/core@7.25.2)
+ '@babel/plugin-transform-dynamic-import': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-exponentiation-operator': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-export-namespace-from': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-for-of': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-function-name': 7.25.1(@babel/core@7.25.2)
+ '@babel/plugin-transform-json-strings': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-literals': 7.25.2(@babel/core@7.25.2)
+ '@babel/plugin-transform-logical-assignment-operators': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-member-expression-literals': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-modules-amd': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-modules-commonjs': 7.24.8(@babel/core@7.25.2)
+ '@babel/plugin-transform-modules-systemjs': 7.25.0(@babel/core@7.25.2)
+ '@babel/plugin-transform-modules-umd': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-named-capturing-groups-regex': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-new-target': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-nullish-coalescing-operator': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-numeric-separator': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-object-rest-spread': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-object-super': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-optional-catch-binding': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-optional-chaining': 7.24.8(@babel/core@7.25.2)
+ '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-private-methods': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-private-property-in-object': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-property-literals': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-regenerator': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-reserved-words': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-shorthand-properties': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-spread': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-sticky-regex': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-template-literals': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-typeof-symbol': 7.24.8(@babel/core@7.25.2)
+ '@babel/plugin-transform-unicode-escapes': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-unicode-property-regex': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-unicode-regex': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-unicode-sets-regex': 7.24.7(@babel/core@7.25.2)
+ '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.25.2)
+ babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.25.2)
+ babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.25.2)
+ babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.25.2)
+ core-js-compat: 3.38.0
+ semver: 6.3.1
transitivePeerDependencies:
- supports-color
- '@babel/preset-typescript@7.24.7(@babel/core@7.24.7)':
+ '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-plugin-utils': 7.24.7
- '@babel/helper-validator-option': 7.24.7
- '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-modules-commonjs': 7.24.7(@babel/core@7.24.7)
- '@babel/plugin-transform-typescript': 7.24.7(@babel/core@7.24.7)
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/types': 7.25.2
+ esutils: 2.0.3
+
+ '@babel/preset-react@7.24.7(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/helper-validator-option': 7.24.8
+ '@babel/plugin-transform-react-display-name': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-react-jsx': 7.25.2(@babel/core@7.25.2)
+ '@babel/plugin-transform-react-jsx-development': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-react-pure-annotations': 7.24.7(@babel/core@7.25.2)
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/preset-typescript@7.24.7(@babel/core@7.25.2)':
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-plugin-utils': 7.24.8
+ '@babel/helper-validator-option': 7.24.8
+ '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.25.2)
+ '@babel/plugin-transform-modules-commonjs': 7.24.8(@babel/core@7.25.2)
+ '@babel/plugin-transform-typescript': 7.25.2(@babel/core@7.25.2)
transitivePeerDependencies:
- supports-color
'@babel/regjsgen@0.8.0': {}
- '@babel/runtime-corejs3@7.24.7':
+ '@babel/runtime-corejs3@7.25.0':
dependencies:
- core-js-pure: 3.37.1
+ core-js-pure: 3.38.0
regenerator-runtime: 0.14.1
- '@babel/runtime@7.24.7':
+ '@babel/runtime@7.25.0':
dependencies:
regenerator-runtime: 0.14.1
- '@babel/template@7.24.7':
+ '@babel/template@7.25.0':
dependencies:
'@babel/code-frame': 7.24.7
- '@babel/parser': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/parser': 7.25.3
+ '@babel/types': 7.25.2
- '@babel/traverse@7.24.7':
+ '@babel/traverse@7.25.3':
dependencies:
'@babel/code-frame': 7.24.7
- '@babel/generator': 7.24.7
- '@babel/helper-environment-visitor': 7.24.7
- '@babel/helper-function-name': 7.24.7
- '@babel/helper-hoist-variables': 7.24.7
- '@babel/helper-split-export-declaration': 7.24.7
- '@babel/parser': 7.24.7
- '@babel/types': 7.24.7
- debug: 4.3.5
+ '@babel/generator': 7.25.0
+ '@babel/parser': 7.25.3
+ '@babel/template': 7.25.0
+ '@babel/types': 7.25.2
+ debug: 4.3.6
globals: 11.12.0
transitivePeerDependencies:
- supports-color
- '@babel/types@7.24.7':
+ '@babel/types@7.25.2':
dependencies:
- '@babel/helper-string-parser': 7.24.7
+ '@babel/helper-string-parser': 7.24.8
'@babel/helper-validator-identifier': 7.24.7
to-fast-properties: 2.0.0
+ '@cfaester/enzyme-adapter-react-18@0.8.0(enzyme@3.11.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ dependencies:
+ enzyme: 3.11.0
+ enzyme-shallow-equal: 1.0.7
+ function.prototype.name: 1.1.6
+ has: 1.0.4
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+ react-is: 18.3.1
+ react-shallow-renderer: 16.15.0(react@18.3.1)
+
'@colors/colors@1.5.0':
optional: true
'@discoveryjs/json-ext@0.5.7': {}
- '@docsearch/css@3.6.0': {}
+ '@docsearch/css@3.6.1': {}
- '@docsearch/react@3.6.0(@algolia/client-search@4.23.3)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.14.0)':
+ '@docsearch/react@3.6.1(@algolia/client-search@4.24.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)':
dependencies:
- '@algolia/autocomplete-core': 1.9.3(@algolia/client-search@4.23.3)(algoliasearch@4.23.3)(search-insights@2.14.0)
- '@algolia/autocomplete-preset-algolia': 1.9.3(@algolia/client-search@4.23.3)(algoliasearch@4.23.3)
- '@docsearch/css': 3.6.0
- algoliasearch: 4.23.3
+ '@algolia/autocomplete-core': 1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)(search-insights@2.15.0)
+ '@algolia/autocomplete-preset-algolia': 1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)
+ '@docsearch/css': 3.6.1
+ algoliasearch: 4.24.0
optionalDependencies:
'@types/react': 18.3.3
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- search-insights: 2.14.0
+ search-insights: 2.15.0
transitivePeerDependencies:
- '@algolia/client-search'
- '@docusaurus/core@3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(debug@4.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)':
+ '@docusaurus/core@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(debug@4.3.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/generator': 7.24.7
- '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.7)
- '@babel/plugin-transform-runtime': 7.24.7(@babel/core@7.24.7)
- '@babel/preset-env': 7.24.7(@babel/core@7.24.7)
- '@babel/preset-react': 7.24.7(@babel/core@7.24.7)
- '@babel/preset-typescript': 7.24.7(@babel/core@7.24.7)
- '@babel/runtime': 7.24.7
- '@babel/runtime-corejs3': 7.24.7
- '@babel/traverse': 7.24.7
- '@docusaurus/cssnano-preset': 3.4.0
- '@docusaurus/logger': 3.4.0
- '@docusaurus/mdx-loader': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/utils': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
- '@docusaurus/utils-common': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
- '@docusaurus/utils-validation': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
- autoprefixer: 10.4.19(postcss@8.4.38)
- babel-loader: 9.1.3(@babel/core@7.24.7)(webpack@5.92.0)
+ '@babel/core': 7.25.2
+ '@babel/generator': 7.25.0
+ '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.25.2)
+ '@babel/plugin-transform-runtime': 7.24.7(@babel/core@7.25.2)
+ '@babel/preset-env': 7.25.3(@babel/core@7.25.2)
+ '@babel/preset-react': 7.24.7(@babel/core@7.25.2)
+ '@babel/preset-typescript': 7.24.7(@babel/core@7.25.2)
+ '@babel/runtime': 7.25.0
+ '@babel/runtime-corejs3': 7.25.0
+ '@babel/traverse': 7.25.3
+ '@docusaurus/cssnano-preset': 3.5.2
+ '@docusaurus/logger': 3.5.2
+ '@docusaurus/mdx-loader': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
+ '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
+ '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
+ '@mdx-js/react': 3.0.1(@types/react@18.3.3)(react@18.3.1)
+ autoprefixer: 10.4.20(postcss@8.4.41)
+ babel-loader: 9.1.3(@babel/core@7.25.2)(webpack@5.93.0)
babel-plugin-dynamic-import-node: 2.3.3
boxen: 6.2.1
chalk: 4.1.2
@@ -6398,50 +6837,50 @@ snapshots:
cli-table3: 0.6.5
combine-promises: 1.2.0
commander: 5.1.0
- copy-webpack-plugin: 11.0.0(webpack@5.92.0)
- core-js: 3.37.1
- css-loader: 6.11.0(webpack@5.92.0)
- css-minimizer-webpack-plugin: 5.0.1(clean-css@5.3.3)(webpack@5.92.0)
- cssnano: 6.1.2(postcss@8.4.38)
+ copy-webpack-plugin: 11.0.0(webpack@5.93.0)
+ core-js: 3.38.0
+ css-loader: 6.11.0(webpack@5.93.0)
+ css-minimizer-webpack-plugin: 5.0.1(clean-css@5.3.3)(webpack@5.93.0)
+ cssnano: 6.1.2(postcss@8.4.41)
del: 6.1.1
detect-port: 1.6.1
escape-html: 1.0.3
eta: 2.2.0
eval: 0.1.8
- file-loader: 6.2.0(webpack@5.92.0)
+ file-loader: 6.2.0(webpack@5.93.0)
fs-extra: 11.2.0
html-minifier-terser: 7.2.0
html-tags: 3.3.1
- html-webpack-plugin: 5.6.0(webpack@5.92.0)
+ html-webpack-plugin: 5.6.0(webpack@5.93.0)
leven: 3.1.0
lodash: 4.17.21
- mini-css-extract-plugin: 2.9.0(webpack@5.92.0)
+ mini-css-extract-plugin: 2.9.0(webpack@5.93.0)
p-map: 4.0.0
- postcss: 8.4.38
- postcss-loader: 7.3.4(postcss@8.4.38)(typescript@5.4.5)(webpack@5.92.0)
+ postcss: 8.4.41
+ postcss-loader: 7.3.4(postcss@8.4.41)(typescript@5.5.4)(webpack@5.93.0)
prompts: 2.4.2
react: 18.3.1
- react-dev-utils: 12.0.1(typescript@5.4.5)(webpack@5.92.0)
+ react-dev-utils: 12.0.1(typescript@5.5.4)(webpack@5.93.0)
react-dom: 18.3.1(react@18.3.1)
react-helmet-async: 1.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react-loadable: '@docusaurus/react-loadable@6.0.0(react@18.3.1)'
- react-loadable-ssr-addon-v5-slorber: 1.0.1(@docusaurus/react-loadable@6.0.0(react@18.3.1))(webpack@5.92.0)
+ react-loadable-ssr-addon-v5-slorber: 1.0.1(@docusaurus/react-loadable@6.0.0(react@18.3.1))(webpack@5.93.0)
react-router: 5.3.4(react@18.3.1)
react-router-config: 5.1.1(react-router@5.3.4(react@18.3.1))(react@18.3.1)
react-router-dom: 5.3.4(react@18.3.1)
rtl-detect: 1.1.2
- semver: 7.6.2
+ semver: 7.6.3
serve-handler: 6.1.5
shelljs: 0.8.5
- terser-webpack-plugin: 5.3.10(webpack@5.92.0)
+ terser-webpack-plugin: 5.3.10(webpack@5.93.0)
tslib: 2.6.3
update-notifier: 6.0.2
- url-loader: 4.1.1(file-loader@6.2.0(webpack@5.92.0))(webpack@5.92.0)
- webpack: 5.92.0
+ url-loader: 4.1.1(file-loader@6.2.0(webpack@5.93.0))(webpack@5.93.0)
+ webpack: 5.93.0
webpack-bundle-analyzer: 4.10.2
- webpack-dev-server: 4.15.2(debug@4.3.5)(webpack@5.92.0)
+ webpack-dev-server: 4.15.2(debug@4.3.6)(webpack@5.93.0)
webpack-merge: 5.10.0
- webpackbar: 5.0.2(webpack@5.92.0)
+ webpackbar: 5.0.2(webpack@5.93.0)
transitivePeerDependencies:
- '@docusaurus/types'
- '@parcel/css'
@@ -6461,28 +6900,28 @@ snapshots:
- vue-template-compiler
- webpack-cli
- '@docusaurus/cssnano-preset@3.4.0':
+ '@docusaurus/cssnano-preset@3.5.2':
dependencies:
- cssnano-preset-advanced: 6.1.2(postcss@8.4.38)
- postcss: 8.4.38
- postcss-sort-media-queries: 5.2.0(postcss@8.4.38)
+ cssnano-preset-advanced: 6.1.2(postcss@8.4.41)
+ postcss: 8.4.41
+ postcss-sort-media-queries: 5.2.0(postcss@8.4.41)
tslib: 2.6.3
- '@docusaurus/logger@3.4.0':
+ '@docusaurus/logger@3.5.2':
dependencies:
chalk: 4.1.2
tslib: 2.6.3
- '@docusaurus/mdx-loader@3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)':
+ '@docusaurus/mdx-loader@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)':
dependencies:
- '@docusaurus/logger': 3.4.0
- '@docusaurus/utils': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
- '@docusaurus/utils-validation': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
+ '@docusaurus/logger': 3.5.2
+ '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
+ '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
'@mdx-js/mdx': 3.0.1
'@slorber/remark-comment': 1.0.0
escape-html: 1.0.3
- estree-util-value-to-estree: 3.1.1
- file-loader: 6.2.0(webpack@5.92.0)
+ estree-util-value-to-estree: 3.1.2
+ file-loader: 6.2.0(webpack@5.93.0)
fs-extra: 11.2.0
image-size: 1.1.1
mdast-util-mdx: 3.0.0
@@ -6496,11 +6935,11 @@ snapshots:
remark-gfm: 4.0.0
stringify-object: 3.3.0
tslib: 2.6.3
- unified: 11.0.4
+ unified: 11.0.5
unist-util-visit: 5.0.0
- url-loader: 4.1.1(file-loader@6.2.0(webpack@5.92.0))(webpack@5.92.0)
- vfile: 6.0.1
- webpack: 5.92.0
+ url-loader: 4.1.1(file-loader@6.2.0(webpack@5.93.0))(webpack@5.93.0)
+ vfile: 6.0.2
+ webpack: 5.93.0
transitivePeerDependencies:
- '@docusaurus/types'
- '@swc/core'
@@ -6510,9 +6949,9 @@ snapshots:
- uglify-js
- webpack-cli
- '@docusaurus/module-type-aliases@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@docusaurus/module-type-aliases@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@docusaurus/types': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@types/history': 4.7.11
'@types/react': 18.3.3
'@types/react-router-config': 5.0.11
@@ -6528,15 +6967,17 @@ snapshots:
- uglify-js
- webpack-cli
- '@docusaurus/plugin-content-blog@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)':
+ '@docusaurus/plugin-content-blog@3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)':
dependencies:
- '@docusaurus/core': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(debug@4.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/logger': 3.4.0
- '@docusaurus/mdx-loader': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/types': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@docusaurus/utils': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
- '@docusaurus/utils-common': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
- '@docusaurus/utils-validation': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
+ '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(debug@4.3.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/logger': 3.5.2
+ '@docusaurus/mdx-loader': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/plugin-content-docs': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/theme-common': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
+ '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
+ '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
cheerio: 1.0.0-rc.12
feed: 4.2.2
fs-extra: 11.2.0
@@ -6548,8 +6989,9 @@ snapshots:
tslib: 2.6.3
unist-util-visit: 5.0.0
utility-types: 3.11.0
- webpack: 5.92.0
+ webpack: 5.93.0
transitivePeerDependencies:
+ - '@mdx-js/react'
- '@parcel/css'
- '@rspack/core'
- '@swc/core'
@@ -6567,16 +7009,17 @@ snapshots:
- vue-template-compiler
- webpack-cli
- '@docusaurus/plugin-content-docs@3.4.0(debug@4.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)':
+ '@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(debug@4.3.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)':
dependencies:
- '@docusaurus/core': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(debug@4.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/logger': 3.4.0
- '@docusaurus/mdx-loader': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/module-type-aliases': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@docusaurus/types': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@docusaurus/utils': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
- '@docusaurus/utils-common': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
- '@docusaurus/utils-validation': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
+ '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(debug@4.3.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/logger': 3.5.2
+ '@docusaurus/mdx-loader': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/module-type-aliases': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@docusaurus/theme-common': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(debug@4.3.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
+ '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
+ '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
'@types/react-router-config': 5.0.11
combine-promises: 1.2.0
fs-extra: 11.2.0
@@ -6586,8 +7029,9 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
tslib: 2.6.3
utility-types: 3.11.0
- webpack: 5.92.0
+ webpack: 5.93.0
transitivePeerDependencies:
+ - '@mdx-js/react'
- '@parcel/css'
- '@rspack/core'
- '@swc/core'
@@ -6605,19 +7049,60 @@ snapshots:
- vue-template-compiler
- webpack-cli
- '@docusaurus/plugin-content-pages@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)':
+ '@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)':
dependencies:
- '@docusaurus/core': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(debug@4.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/mdx-loader': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/types': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@docusaurus/utils': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
- '@docusaurus/utils-validation': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
+ '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(debug@4.3.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/logger': 3.5.2
+ '@docusaurus/mdx-loader': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/module-type-aliases': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@docusaurus/theme-common': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
+ '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
+ '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
+ '@types/react-router-config': 5.0.11
+ combine-promises: 1.2.0
+ fs-extra: 11.2.0
+ js-yaml: 4.1.0
+ lodash: 4.17.21
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+ tslib: 2.6.3
+ utility-types: 3.11.0
+ webpack: 5.93.0
+ transitivePeerDependencies:
+ - '@mdx-js/react'
+ - '@parcel/css'
+ - '@rspack/core'
+ - '@swc/core'
+ - '@swc/css'
+ - bufferutil
+ - csso
+ - debug
+ - esbuild
+ - eslint
+ - lightningcss
+ - supports-color
+ - typescript
+ - uglify-js
+ - utf-8-validate
+ - vue-template-compiler
+ - webpack-cli
+
+ '@docusaurus/plugin-content-pages@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)':
+ dependencies:
+ '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(debug@4.3.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/mdx-loader': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
+ '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
fs-extra: 11.2.0
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
tslib: 2.6.3
- webpack: 5.92.0
+ webpack: 5.93.0
transitivePeerDependencies:
+ - '@mdx-js/react'
- '@parcel/css'
- '@rspack/core'
- '@swc/core'
@@ -6635,17 +7120,18 @@ snapshots:
- vue-template-compiler
- webpack-cli
- '@docusaurus/plugin-debug@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)':
+ '@docusaurus/plugin-debug@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)':
dependencies:
- '@docusaurus/core': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(debug@4.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/types': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@docusaurus/utils': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
+ '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(debug@4.3.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
fs-extra: 11.2.0
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
react-json-view-lite: 1.4.0(react@18.3.1)
tslib: 2.6.3
transitivePeerDependencies:
+ - '@mdx-js/react'
- '@parcel/css'
- '@rspack/core'
- '@swc/core'
@@ -6663,15 +7149,16 @@ snapshots:
- vue-template-compiler
- webpack-cli
- '@docusaurus/plugin-google-analytics@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)':
+ '@docusaurus/plugin-google-analytics@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)':
dependencies:
- '@docusaurus/core': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(debug@4.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/types': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@docusaurus/utils-validation': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
+ '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(debug@4.3.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
tslib: 2.6.3
transitivePeerDependencies:
+ - '@mdx-js/react'
- '@parcel/css'
- '@rspack/core'
- '@swc/core'
@@ -6689,16 +7176,17 @@ snapshots:
- vue-template-compiler
- webpack-cli
- '@docusaurus/plugin-google-gtag@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)':
+ '@docusaurus/plugin-google-gtag@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)':
dependencies:
- '@docusaurus/core': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(debug@4.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/types': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@docusaurus/utils-validation': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
+ '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(debug@4.3.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
'@types/gtag.js': 0.0.12
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
tslib: 2.6.3
transitivePeerDependencies:
+ - '@mdx-js/react'
- '@parcel/css'
- '@rspack/core'
- '@swc/core'
@@ -6716,15 +7204,16 @@ snapshots:
- vue-template-compiler
- webpack-cli
- '@docusaurus/plugin-google-tag-manager@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)':
+ '@docusaurus/plugin-google-tag-manager@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)':
dependencies:
- '@docusaurus/core': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(debug@4.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/types': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@docusaurus/utils-validation': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
+ '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(debug@4.3.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
tslib: 2.6.3
transitivePeerDependencies:
+ - '@mdx-js/react'
- '@parcel/css'
- '@rspack/core'
- '@swc/core'
@@ -6742,20 +7231,21 @@ snapshots:
- vue-template-compiler
- webpack-cli
- '@docusaurus/plugin-sitemap@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)':
+ '@docusaurus/plugin-sitemap@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)':
dependencies:
- '@docusaurus/core': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(debug@4.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/logger': 3.4.0
- '@docusaurus/types': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@docusaurus/utils': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
- '@docusaurus/utils-common': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
- '@docusaurus/utils-validation': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
+ '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(debug@4.3.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/logger': 3.5.2
+ '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
+ '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
+ '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
fs-extra: 11.2.0
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
sitemap: 7.1.2
tslib: 2.6.3
transitivePeerDependencies:
+ - '@mdx-js/react'
- '@parcel/css'
- '@rspack/core'
- '@swc/core'
@@ -6773,25 +7263,26 @@ snapshots:
- vue-template-compiler
- webpack-cli
- '@docusaurus/preset-classic@3.4.0(@algolia/client-search@4.23.3)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.14.0)(typescript@5.4.5)':
+ '@docusaurus/preset-classic@3.5.2(@algolia/client-search@4.24.0)(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)(typescript@5.5.4)':
dependencies:
- '@docusaurus/core': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(debug@4.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/plugin-content-blog': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/plugin-content-docs': 3.4.0(debug@4.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/plugin-content-pages': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/plugin-debug': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/plugin-google-analytics': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/plugin-google-gtag': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/plugin-google-tag-manager': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/plugin-sitemap': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/theme-classic': 3.4.0(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/theme-common': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/theme-search-algolia': 3.4.0(@algolia/client-search@4.23.3)(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.14.0)(typescript@5.4.5)
- '@docusaurus/types': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(debug@4.3.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/plugin-content-blog': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/plugin-content-docs': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/plugin-content-pages': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/plugin-debug': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/plugin-google-analytics': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/plugin-google-gtag': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/plugin-google-tag-manager': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/plugin-sitemap': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/theme-classic': 3.5.2(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/theme-common': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/theme-search-algolia': 3.5.2(@algolia/client-search@4.24.0)(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)(typescript@5.5.4)
+ '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
transitivePeerDependencies:
- '@algolia/client-search'
+ - '@mdx-js/react'
- '@parcel/css'
- '@rspack/core'
- '@swc/core'
@@ -6816,33 +7307,33 @@ snapshots:
'@types/react': 18.3.3
react: 18.3.1
- '@docusaurus/theme-classic@3.4.0(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)':
+ '@docusaurus/theme-classic@3.5.2(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)':
dependencies:
- '@docusaurus/core': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(debug@4.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/mdx-loader': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/module-type-aliases': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@docusaurus/plugin-content-blog': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/plugin-content-docs': 3.4.0(debug@4.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/plugin-content-pages': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/theme-common': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/theme-translations': 3.4.0
- '@docusaurus/types': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@docusaurus/utils': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
- '@docusaurus/utils-common': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
- '@docusaurus/utils-validation': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
+ '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(debug@4.3.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/mdx-loader': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/module-type-aliases': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@docusaurus/plugin-content-blog': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/plugin-content-docs': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/plugin-content-pages': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/theme-common': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/theme-translations': 3.5.2
+ '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
+ '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
+ '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
'@mdx-js/react': 3.0.1(@types/react@18.3.3)(react@18.3.1)
clsx: 2.1.1
copy-text-to-clipboard: 3.2.0
- infima: 0.2.0-alpha.43
+ infima: 0.2.0-alpha.44
lodash: 4.17.21
nprogress: 0.2.0
- postcss: 8.4.38
+ postcss: 8.4.41
prism-react-renderer: 2.3.1(react@18.3.1)
prismjs: 1.29.0
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
react-router-dom: 5.3.4(react@18.3.1)
- rtlcss: 4.1.1
+ rtlcss: 4.2.0
tslib: 2.6.3
utility-types: 3.11.0
transitivePeerDependencies:
@@ -6864,15 +7355,13 @@ snapshots:
- vue-template-compiler
- webpack-cli
- '@docusaurus/theme-common@3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)':
+ '@docusaurus/theme-common@3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(debug@4.3.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)':
dependencies:
- '@docusaurus/mdx-loader': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/module-type-aliases': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@docusaurus/plugin-content-blog': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/plugin-content-docs': 3.4.0(debug@4.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/plugin-content-pages': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/utils': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
- '@docusaurus/utils-common': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
+ '@docusaurus/mdx-loader': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/module-type-aliases': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@docusaurus/plugin-content-docs': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(debug@4.3.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
+ '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
'@types/history': 4.7.11
'@types/react': 18.3.3
'@types/react-router-config': 5.0.11
@@ -6885,35 +7374,51 @@ snapshots:
utility-types: 3.11.0
transitivePeerDependencies:
- '@docusaurus/types'
- - '@parcel/css'
- - '@rspack/core'
- '@swc/core'
- - '@swc/css'
- - bufferutil
- - csso
- - debug
- esbuild
- - eslint
- - lightningcss
- supports-color
- typescript
- uglify-js
- - utf-8-validate
- - vue-template-compiler
- webpack-cli
- '@docusaurus/theme-search-algolia@3.4.0(@algolia/client-search@4.23.3)(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.14.0)(typescript@5.4.5)':
+ '@docusaurus/theme-common@3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)':
dependencies:
- '@docsearch/react': 3.6.0(@algolia/client-search@4.23.3)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.14.0)
- '@docusaurus/core': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(debug@4.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/logger': 3.4.0
- '@docusaurus/plugin-content-docs': 3.4.0(debug@4.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/theme-common': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/theme-translations': 3.4.0
- '@docusaurus/utils': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
- '@docusaurus/utils-validation': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
- algoliasearch: 4.23.3
- algoliasearch-helper: 3.21.0(algoliasearch@4.23.3)
+ '@docusaurus/mdx-loader': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/module-type-aliases': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@docusaurus/plugin-content-docs': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
+ '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
+ '@types/history': 4.7.11
+ '@types/react': 18.3.3
+ '@types/react-router-config': 5.0.11
+ clsx: 2.1.1
+ parse-numeric-range: 1.3.0
+ prism-react-renderer: 2.3.1(react@18.3.1)
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+ tslib: 2.6.3
+ utility-types: 3.11.0
+ transitivePeerDependencies:
+ - '@docusaurus/types'
+ - '@swc/core'
+ - esbuild
+ - supports-color
+ - typescript
+ - uglify-js
+ - webpack-cli
+
+ '@docusaurus/theme-search-algolia@3.5.2(@algolia/client-search@4.24.0)(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)(typescript@5.5.4)':
+ dependencies:
+ '@docsearch/react': 3.6.1(@algolia/client-search@4.24.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)
+ '@docusaurus/core': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(debug@4.3.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/logger': 3.5.2
+ '@docusaurus/plugin-content-docs': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/theme-common': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/theme-translations': 3.5.2
+ '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
+ '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
+ algoliasearch: 4.24.0
+ algoliasearch-helper: 3.22.3(algoliasearch@4.24.0)
clsx: 2.1.1
eta: 2.2.0
fs-extra: 11.2.0
@@ -6925,6 +7430,7 @@ snapshots:
transitivePeerDependencies:
- '@algolia/client-search'
- '@docusaurus/types'
+ - '@mdx-js/react'
- '@parcel/css'
- '@rspack/core'
- '@swc/core'
@@ -6944,25 +7450,25 @@ snapshots:
- vue-template-compiler
- webpack-cli
- '@docusaurus/theme-translations@3.4.0':
+ '@docusaurus/theme-translations@3.5.2':
dependencies:
fs-extra: 11.2.0
tslib: 2.6.3
- '@docusaurus/tsconfig@3.4.0': {}
+ '@docusaurus/tsconfig@3.5.2': {}
- '@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ '@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@mdx-js/mdx': 3.0.1
'@types/history': 4.7.11
'@types/react': 18.3.3
commander: 5.1.0
- joi: 17.13.1
+ joi: 17.13.3
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
react-helmet-async: 1.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
utility-types: 3.11.0
- webpack: 5.92.0
+ webpack: 5.93.0
webpack-merge: 5.10.0
transitivePeerDependencies:
- '@swc/core'
@@ -6971,19 +7477,19 @@ snapshots:
- uglify-js
- webpack-cli
- '@docusaurus/utils-common@3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))':
+ '@docusaurus/utils-common@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))':
dependencies:
tslib: 2.6.3
optionalDependencies:
- '@docusaurus/types': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@docusaurus/utils-validation@3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)':
+ '@docusaurus/utils-validation@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)':
dependencies:
- '@docusaurus/logger': 3.4.0
- '@docusaurus/utils': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
- '@docusaurus/utils-common': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
+ '@docusaurus/logger': 3.5.2
+ '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
+ '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
fs-extra: 11.2.0
- joi: 17.13.1
+ joi: 17.13.3
js-yaml: 4.1.0
lodash: 4.17.21
tslib: 2.6.3
@@ -6996,13 +7502,13 @@ snapshots:
- uglify-js
- webpack-cli
- '@docusaurus/utils@3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)':
+ '@docusaurus/utils@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)':
dependencies:
- '@docusaurus/logger': 3.4.0
- '@docusaurus/utils-common': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
- '@svgr/webpack': 8.1.0(typescript@5.4.5)
+ '@docusaurus/logger': 3.5.2
+ '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
+ '@svgr/webpack': 8.1.0(typescript@5.5.4)
escape-string-regexp: 4.0.0
- file-loader: 6.2.0(webpack@5.92.0)
+ file-loader: 6.2.0(webpack@5.93.0)
fs-extra: 11.2.0
github-slugger: 1.5.0
globby: 11.1.0
@@ -7015,11 +7521,11 @@ snapshots:
resolve-pathname: 3.0.0
shelljs: 0.8.5
tslib: 2.6.3
- url-loader: 4.1.1(file-loader@6.2.0(webpack@5.92.0))(webpack@5.92.0)
+ url-loader: 4.1.1(file-loader@6.2.0(webpack@5.93.0))(webpack@5.93.0)
utility-types: 3.11.0
- webpack: 5.92.0
+ webpack: 5.93.0
optionalDependencies:
- '@docusaurus/types': 3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@docusaurus/types': 3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
transitivePeerDependencies:
- '@swc/core'
- esbuild
@@ -7033,19 +7539,19 @@ snapshots:
cssesc: 3.0.0
immediate: 3.3.0
- '@easyops-cn/docusaurus-search-local@0.44.0(@docusaurus/theme-common@3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5))(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)':
+ '@easyops-cn/docusaurus-search-local@0.44.5(@docusaurus/theme-common@3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)':
dependencies:
- '@docusaurus/plugin-content-docs': 3.4.0(debug@4.3.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/theme-common': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/theme-translations': 3.4.0
- '@docusaurus/utils': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
- '@docusaurus/utils-common': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
- '@docusaurus/utils-validation': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
+ '@docusaurus/plugin-content-docs': 3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(debug@4.3.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/theme-common': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/theme-translations': 3.5.2
+ '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
+ '@docusaurus/utils-common': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
+ '@docusaurus/utils-validation': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
'@easyops-cn/autocomplete.js': 0.38.1
'@node-rs/jieba': 1.10.3
- cheerio: 1.0.0-rc.12
+ cheerio: 1.0.0
clsx: 1.2.1
- debug: 4.3.5
+ debug: 4.3.6
fs-extra: 10.1.0
klaw-sync: 6.0.0
lunr: 2.3.9
@@ -7056,6 +7562,7 @@ snapshots:
tslib: 2.6.3
transitivePeerDependencies:
- '@docusaurus/types'
+ - '@mdx-js/react'
- '@parcel/css'
- '@rspack/core'
- '@swc/core'
@@ -7182,14 +7689,14 @@ snapshots:
'@jest/schemas': 29.6.3
'@types/istanbul-lib-coverage': 2.0.6
'@types/istanbul-reports': 3.0.4
- '@types/node': 20.14.5
- '@types/yargs': 17.0.32
+ '@types/node': 20.14.15
+ '@types/yargs': 17.0.33
chalk: 4.1.2
'@jridgewell/gen-mapping@0.3.5':
dependencies:
'@jridgewell/set-array': 1.2.1
- '@jridgewell/sourcemap-codec': 1.4.15
+ '@jridgewell/sourcemap-codec': 1.5.0
'@jridgewell/trace-mapping': 0.3.25
'@jridgewell/resolve-uri@3.1.2': {}
@@ -7201,12 +7708,12 @@ snapshots:
'@jridgewell/gen-mapping': 0.3.5
'@jridgewell/trace-mapping': 0.3.25
- '@jridgewell/sourcemap-codec@1.4.15': {}
+ '@jridgewell/sourcemap-codec@1.5.0': {}
'@jridgewell/trace-mapping@0.3.25':
dependencies:
'@jridgewell/resolve-uri': 3.1.2
- '@jridgewell/sourcemap-codec': 1.4.15
+ '@jridgewell/sourcemap-codec': 1.5.0
'@leichtgewicht/ip-codec@2.0.5': {}
@@ -7230,11 +7737,11 @@ snapshots:
remark-parse: 11.0.0
remark-rehype: 11.1.0
source-map: 0.7.4
- unified: 11.0.4
+ unified: 11.0.5
unist-util-position-from-estree: 2.0.0
unist-util-stringify-position: 4.0.0
unist-util-visit: 5.0.0
- vfile: 6.0.1
+ vfile: 6.0.2
transitivePeerDependencies:
- supports-color
@@ -7330,7 +7837,7 @@ snapshots:
dependencies:
graceful-fs: 4.2.10
- '@pnpm/npm-conf@2.2.2':
+ '@pnpm/npm-conf@2.3.1':
dependencies:
'@pnpm/config.env-replace': 1.1.0
'@pnpm/network.ca-file': 1.0.2
@@ -7345,10 +7852,14 @@ snapshots:
require-from-string: 2.0.2
uri-js: 4.4.1
- '@redocly/openapi-core@1.10.3':
+ '@redocly/config@0.6.3': {}
+
+ '@redocly/openapi-core@1.16.0':
dependencies:
'@redocly/ajv': 8.11.0
+ '@redocly/config': 0.6.3
colorette: 1.4.0
+ https-proxy-agent: 7.0.5
js-levenshtein: 1.1.6
js-yaml: 4.1.0
lodash.isequal: 4.5.0
@@ -7358,6 +7869,7 @@ snapshots:
yaml-ast-parser: 0.0.43
transitivePeerDependencies:
- encoding
+ - supports-color
'@sec-ant/readable-stream@0.4.1': {}
@@ -7373,7 +7885,7 @@ snapshots:
'@sindresorhus/is@4.6.0': {}
- '@sindresorhus/is@6.3.1': {}
+ '@sindresorhus/is@7.0.0': {}
'@slorber/remark-comment@1.0.0':
dependencies:
@@ -7381,56 +7893,56 @@ snapshots:
micromark-util-character: 1.2.0
micromark-util-symbol: 1.1.0
- '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.24.7)':
+ '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
+ '@babel/core': 7.25.2
- '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.24.7)':
+ '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
+ '@babel/core': 7.25.2
- '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.24.7)':
+ '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
+ '@babel/core': 7.25.2
- '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.24.7)':
+ '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
+ '@babel/core': 7.25.2
- '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.24.7)':
+ '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
+ '@babel/core': 7.25.2
- '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.24.7)':
+ '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
+ '@babel/core': 7.25.2
- '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.24.7)':
+ '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
+ '@babel/core': 7.25.2
- '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.24.7)':
+ '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
+ '@babel/core': 7.25.2
- '@svgr/babel-preset@8.1.0(@babel/core@7.24.7)':
+ '@svgr/babel-preset@8.1.0(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.24.7)
- '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.24.7)
- '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.24.7)
- '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.24.7)
- '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.24.7)
- '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.24.7)
- '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.24.7)
- '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.24.7)
+ '@babel/core': 7.25.2
+ '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.25.2)
+ '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.25.2)
+ '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.25.2)
+ '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.25.2)
+ '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.25.2)
+ '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.25.2)
+ '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.25.2)
+ '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.25.2)
- '@svgr/core@8.1.0(typescript@5.4.5)':
+ '@svgr/core@8.1.0(typescript@5.5.4)':
dependencies:
- '@babel/core': 7.24.7
- '@svgr/babel-preset': 8.1.0(@babel/core@7.24.7)
+ '@babel/core': 7.25.2
+ '@svgr/babel-preset': 8.1.0(@babel/core@7.25.2)
camelcase: 6.3.0
- cosmiconfig: 8.3.6(typescript@5.4.5)
+ cosmiconfig: 8.3.6(typescript@5.5.4)
snake-case: 3.0.4
transitivePeerDependencies:
- supports-color
@@ -7438,38 +7950,38 @@ snapshots:
'@svgr/hast-util-to-babel-ast@8.0.0':
dependencies:
- '@babel/types': 7.24.7
+ '@babel/types': 7.25.2
entities: 4.5.0
- '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.4.5))':
+ '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.5.4))':
dependencies:
- '@babel/core': 7.24.7
- '@svgr/babel-preset': 8.1.0(@babel/core@7.24.7)
- '@svgr/core': 8.1.0(typescript@5.4.5)
+ '@babel/core': 7.25.2
+ '@svgr/babel-preset': 8.1.0(@babel/core@7.25.2)
+ '@svgr/core': 8.1.0(typescript@5.5.4)
'@svgr/hast-util-to-babel-ast': 8.0.0
svg-parser: 2.0.4
transitivePeerDependencies:
- supports-color
- '@svgr/plugin-svgo@8.1.0(@svgr/core@8.1.0(typescript@5.4.5))(typescript@5.4.5)':
+ '@svgr/plugin-svgo@8.1.0(@svgr/core@8.1.0(typescript@5.5.4))(typescript@5.5.4)':
dependencies:
- '@svgr/core': 8.1.0(typescript@5.4.5)
- cosmiconfig: 8.3.6(typescript@5.4.5)
+ '@svgr/core': 8.1.0(typescript@5.5.4)
+ cosmiconfig: 8.3.6(typescript@5.5.4)
deepmerge: 4.3.1
svgo: 3.3.2
transitivePeerDependencies:
- typescript
- '@svgr/webpack@8.1.0(typescript@5.4.5)':
+ '@svgr/webpack@8.1.0(typescript@5.5.4)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/plugin-transform-react-constant-elements': 7.24.7(@babel/core@7.24.7)
- '@babel/preset-env': 7.24.7(@babel/core@7.24.7)
- '@babel/preset-react': 7.24.7(@babel/core@7.24.7)
- '@babel/preset-typescript': 7.24.7(@babel/core@7.24.7)
- '@svgr/core': 8.1.0(typescript@5.4.5)
- '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.4.5))
- '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@5.4.5))(typescript@5.4.5)
+ '@babel/core': 7.25.2
+ '@babel/plugin-transform-react-constant-elements': 7.25.1(@babel/core@7.25.2)
+ '@babel/preset-env': 7.25.2(@babel/core@7.25.2)
+ '@babel/preset-react': 7.24.7(@babel/core@7.25.2)
+ '@babel/preset-typescript': 7.24.7(@babel/core@7.25.2)
+ '@svgr/core': 8.1.0(typescript@5.5.4)
+ '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.5.4))
+ '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@5.5.4))(typescript@5.5.4)
transitivePeerDependencies:
- supports-color
- typescript
@@ -7494,20 +8006,20 @@ snapshots:
'@types/body-parser@1.19.5':
dependencies:
'@types/connect': 3.4.38
- '@types/node': 20.14.5
+ '@types/node': 20.14.15
'@types/bonjour@3.5.13':
dependencies:
- '@types/node': 20.14.5
+ '@types/node': 20.14.15
'@types/connect-history-api-fallback@1.5.4':
dependencies:
- '@types/express-serve-static-core': 4.19.3
- '@types/node': 20.14.5
+ '@types/express-serve-static-core': 4.19.5
+ '@types/node': 20.14.15
'@types/connect@3.4.38':
dependencies:
- '@types/node': 20.14.5
+ '@types/node': 20.14.15
'@types/debug@4.1.12':
dependencies:
@@ -7519,10 +8031,10 @@ snapshots:
'@types/eslint-scope@3.7.7':
dependencies:
- '@types/eslint': 8.56.10
+ '@types/eslint': 9.6.0
'@types/estree': 1.0.5
- '@types/eslint@8.56.10':
+ '@types/eslint@9.6.0':
dependencies:
'@types/estree': 1.0.5
'@types/json-schema': 7.0.15
@@ -7533,9 +8045,9 @@ snapshots:
'@types/estree@1.0.5': {}
- '@types/express-serve-static-core@4.19.3':
+ '@types/express-serve-static-core@4.19.5':
dependencies:
- '@types/node': 20.14.5
+ '@types/node': 20.14.15
'@types/qs': 6.9.15
'@types/range-parser': 1.2.7
'@types/send': 0.17.4
@@ -7543,7 +8055,7 @@ snapshots:
'@types/express@4.17.21':
dependencies:
'@types/body-parser': 1.19.5
- '@types/express-serve-static-core': 4.19.3
+ '@types/express-serve-static-core': 4.19.5
'@types/qs': 6.9.15
'@types/serve-static': 1.15.7
@@ -7551,7 +8063,7 @@ snapshots:
'@types/hast@3.0.4':
dependencies:
- '@types/unist': 3.0.2
+ '@types/unist': 3.0.3
'@types/history@4.7.11': {}
@@ -7561,9 +8073,9 @@ snapshots:
'@types/http-errors@2.0.4': {}
- '@types/http-proxy@1.17.14':
+ '@types/http-proxy@1.17.15':
dependencies:
- '@types/node': 20.14.5
+ '@types/node': 20.14.15
'@types/istanbul-lib-coverage@2.0.6': {}
@@ -7579,7 +8091,7 @@ snapshots:
'@types/mdast@4.0.4':
dependencies:
- '@types/unist': 3.0.2
+ '@types/unist': 3.0.3
'@types/mdx@2.0.13': {}
@@ -7589,11 +8101,11 @@ snapshots:
'@types/node-forge@1.3.11':
dependencies:
- '@types/node': 20.14.5
+ '@types/node': 20.14.15
'@types/node@17.0.45': {}
- '@types/node@20.14.5':
+ '@types/node@20.14.15':
dependencies:
undici-types: 5.26.5
@@ -7637,12 +8149,12 @@ snapshots:
'@types/sax@1.2.7':
dependencies:
- '@types/node': 20.14.5
+ '@types/node': 20.14.15
'@types/send@0.17.4':
dependencies:
'@types/mime': 1.3.5
- '@types/node': 20.14.5
+ '@types/node': 20.14.15
'@types/serve-index@1.9.4':
dependencies:
@@ -7651,28 +8163,28 @@ snapshots:
'@types/serve-static@1.15.7':
dependencies:
'@types/http-errors': 2.0.4
- '@types/node': 20.14.5
+ '@types/node': 20.14.15
'@types/send': 0.17.4
'@types/sockjs@0.3.36':
dependencies:
- '@types/node': 20.14.5
+ '@types/node': 20.14.15
'@types/stylis@4.2.5': {}
'@types/trusted-types@2.0.7': {}
- '@types/unist@2.0.10': {}
+ '@types/unist@2.0.11': {}
- '@types/unist@3.0.2': {}
+ '@types/unist@3.0.3': {}
- '@types/ws@8.5.10':
+ '@types/ws@8.5.12':
dependencies:
- '@types/node': 20.14.5
+ '@types/node': 20.14.15
'@types/yargs-parser@21.0.3': {}
- '@types/yargs@17.0.32':
+ '@types/yargs@17.0.33':
dependencies:
'@types/yargs-parser': 21.0.3
@@ -7763,25 +8275,25 @@ snapshots:
mime-types: 2.1.35
negotiator: 0.6.3
- acorn-import-attributes@1.9.5(acorn@8.12.0):
+ acorn-import-attributes@1.9.5(acorn@8.12.1):
dependencies:
- acorn: 8.12.0
+ acorn: 8.12.1
- acorn-jsx@5.3.2(acorn@8.12.0):
+ acorn-jsx@5.3.2(acorn@8.12.1):
dependencies:
- acorn: 8.12.0
+ acorn: 8.12.1
acorn-walk@8.3.3:
dependencies:
- acorn: 8.12.0
+ acorn: 8.12.1
- acorn@8.12.0: {}
+ acorn@8.12.1: {}
address@1.2.2: {}
agent-base@7.1.1:
dependencies:
- debug: 4.3.5
+ debug: 4.3.6
transitivePeerDependencies:
- supports-color
@@ -7790,17 +8302,17 @@ snapshots:
clean-stack: 2.2.0
indent-string: 4.0.0
- ajv-formats@2.1.1(ajv@8.16.0):
+ ajv-formats@2.1.1(ajv@8.17.1):
optionalDependencies:
- ajv: 8.16.0
+ ajv: 8.17.1
ajv-keywords@3.5.2(ajv@6.12.6):
dependencies:
ajv: 6.12.6
- ajv-keywords@5.1.0(ajv@8.16.0):
+ ajv-keywords@5.1.0(ajv@8.17.1):
dependencies:
- ajv: 8.16.0
+ ajv: 8.17.1
fast-deep-equal: 3.1.3
ajv@6.12.6:
@@ -7810,35 +8322,35 @@ snapshots:
json-schema-traverse: 0.4.1
uri-js: 4.4.1
- ajv@8.16.0:
+ ajv@8.17.1:
dependencies:
fast-deep-equal: 3.1.3
+ fast-uri: 3.0.1
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
- uri-js: 4.4.1
- algoliasearch-helper@3.21.0(algoliasearch@4.23.3):
+ algoliasearch-helper@3.22.3(algoliasearch@4.24.0):
dependencies:
'@algolia/events': 4.0.1
- algoliasearch: 4.23.3
+ algoliasearch: 4.24.0
- algoliasearch@4.23.3:
+ algoliasearch@4.24.0:
dependencies:
- '@algolia/cache-browser-local-storage': 4.23.3
- '@algolia/cache-common': 4.23.3
- '@algolia/cache-in-memory': 4.23.3
- '@algolia/client-account': 4.23.3
- '@algolia/client-analytics': 4.23.3
- '@algolia/client-common': 4.23.3
- '@algolia/client-personalization': 4.23.3
- '@algolia/client-search': 4.23.3
- '@algolia/logger-common': 4.23.3
- '@algolia/logger-console': 4.23.3
- '@algolia/recommend': 4.23.3
- '@algolia/requester-browser-xhr': 4.23.3
- '@algolia/requester-common': 4.23.3
- '@algolia/requester-node-http': 4.23.3
- '@algolia/transporter': 4.23.3
+ '@algolia/cache-browser-local-storage': 4.24.0
+ '@algolia/cache-common': 4.24.0
+ '@algolia/cache-in-memory': 4.24.0
+ '@algolia/client-account': 4.24.0
+ '@algolia/client-analytics': 4.24.0
+ '@algolia/client-common': 4.24.0
+ '@algolia/client-personalization': 4.24.0
+ '@algolia/client-search': 4.24.0
+ '@algolia/logger-common': 4.24.0
+ '@algolia/logger-console': 4.24.0
+ '@algolia/recommend': 4.24.0
+ '@algolia/requester-browser-xhr': 4.24.0
+ '@algolia/requester-common': 4.24.0
+ '@algolia/requester-node-http': 4.24.0
+ '@algolia/transporter': 4.24.0
ansi-align@3.0.1:
dependencies:
@@ -7873,66 +8385,110 @@ snapshots:
argparse@2.0.1: {}
+ array-buffer-byte-length@1.0.1:
+ dependencies:
+ call-bind: 1.0.7
+ is-array-buffer: 3.0.4
+
array-flatten@1.1.1: {}
array-union@2.1.0: {}
+ array.prototype.filter@1.0.4:
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-abstract: 1.23.3
+ es-array-method-boxes-properly: 1.0.0
+ es-object-atoms: 1.0.0
+ is-string: 1.0.7
+
+ array.prototype.flat@1.3.2:
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-abstract: 1.23.3
+ es-shim-unscopables: 1.0.2
+
+ arraybuffer.prototype.slice@1.0.3:
+ dependencies:
+ array-buffer-byte-length: 1.0.1
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-abstract: 1.23.3
+ es-errors: 1.3.0
+ get-intrinsic: 1.2.4
+ is-array-buffer: 3.0.4
+ is-shared-array-buffer: 1.0.3
+
astring@1.8.6: {}
asynckit@0.4.0: {}
at-least-node@1.0.0: {}
- autoprefixer@10.4.19(postcss@8.4.38):
+ autoprefixer@10.4.20(postcss@8.4.41):
dependencies:
- browserslist: 4.23.1
- caniuse-lite: 1.0.30001636
+ browserslist: 4.23.3
+ caniuse-lite: 1.0.30001651
fraction.js: 4.3.7
normalize-range: 0.1.2
picocolors: 1.0.1
- postcss: 8.4.38
+ postcss: 8.4.41
postcss-value-parser: 4.2.0
- axios@1.7.2:
+ available-typed-arrays@1.0.7:
dependencies:
- follow-redirects: 1.15.6(debug@4.3.5)
+ possible-typed-array-names: 1.0.0
+
+ axios@1.7.4:
+ dependencies:
+ follow-redirects: 1.15.6(debug@4.3.6)
form-data: 4.0.0
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
- babel-loader@9.1.3(@babel/core@7.24.7)(webpack@5.92.0):
+ babel-loader@9.1.3(@babel/core@7.25.2)(webpack@5.93.0):
dependencies:
- '@babel/core': 7.24.7
+ '@babel/core': 7.25.2
find-cache-dir: 4.0.0
schema-utils: 4.2.0
- webpack: 5.92.0
+ webpack: 5.93.0
babel-plugin-dynamic-import-node@2.3.3:
dependencies:
object.assign: 4.1.5
- babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.24.7):
+ babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.25.2):
dependencies:
- '@babel/compat-data': 7.24.7
- '@babel/core': 7.24.7
- '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.7)
+ '@babel/compat-data': 7.25.2
+ '@babel/core': 7.25.2
+ '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.25.2)
semver: 6.3.1
transitivePeerDependencies:
- supports-color
- babel-plugin-polyfill-corejs3@0.10.4(@babel/core@7.24.7):
+ babel-plugin-polyfill-corejs3@0.10.4(@babel/core@7.25.2):
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.7)
+ '@babel/core': 7.25.2
+ '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.25.2)
core-js-compat: 3.37.1
transitivePeerDependencies:
- supports-color
- babel-plugin-polyfill-regenerator@0.6.2(@babel/core@7.24.7):
+ babel-plugin-polyfill-corejs3@0.10.6(@babel/core@7.25.2):
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.7)
+ '@babel/core': 7.25.2
+ '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.25.2)
+ core-js-compat: 3.38.0
+ transitivePeerDependencies:
+ - supports-color
+
+ babel-plugin-polyfill-regenerator@0.6.2(@babel/core@7.25.2):
+ dependencies:
+ '@babel/core': 7.25.2
+ '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.25.2)
transitivePeerDependencies:
- supports-color
@@ -8005,12 +8561,19 @@ snapshots:
dependencies:
fill-range: 7.1.1
- browserslist@4.23.1:
+ browserslist@4.23.2:
dependencies:
- caniuse-lite: 1.0.30001636
- electron-to-chromium: 1.4.805
- node-releases: 2.0.14
- update-browserslist-db: 1.0.16(browserslist@4.23.1)
+ caniuse-lite: 1.0.30001651
+ electron-to-chromium: 1.5.3
+ node-releases: 2.0.18
+ update-browserslist-db: 1.1.0(browserslist@4.23.2)
+
+ browserslist@4.23.3:
+ dependencies:
+ caniuse-lite: 1.0.30001651
+ electron-to-chromium: 1.5.8
+ node-releases: 2.0.18
+ update-browserslist-db: 1.1.0(browserslist@4.23.3)
buffer-from@1.1.2: {}
@@ -8055,12 +8618,12 @@ snapshots:
caniuse-api@3.0.0:
dependencies:
- browserslist: 4.23.1
- caniuse-lite: 1.0.30001636
+ browserslist: 4.23.3
+ caniuse-lite: 1.0.30001651
lodash.memoize: 4.1.2
lodash.uniq: 4.5.0
- caniuse-lite@1.0.30001636: {}
+ caniuse-lite@1.0.30001651: {}
ccount@2.0.1: {}
@@ -8096,6 +8659,20 @@ snapshots:
domhandler: 5.0.3
domutils: 3.1.0
+ cheerio@1.0.0:
+ dependencies:
+ cheerio-select: 2.1.0
+ dom-serializer: 2.0.0
+ domhandler: 5.0.3
+ domutils: 3.1.0
+ encoding-sniffer: 0.2.0
+ htmlparser2: 9.1.0
+ parse5: 7.1.2
+ parse5-htmlparser2-tree-adapter: 7.0.0
+ parse5-parser-stream: 7.1.2
+ undici: 6.19.7
+ whatwg-mimetype: 4.0.0
+
cheerio@1.0.0-rc.12:
dependencies:
cheerio-select: 2.1.0
@@ -8196,7 +8773,7 @@ snapshots:
compressible@2.0.18:
dependencies:
- mime-db: 1.52.0
+ mime-db: 1.53.0
compression@1.7.4:
dependencies:
@@ -8257,7 +8834,7 @@ snapshots:
copy-text-to-clipboard@3.2.0: {}
- copy-webpack-plugin@11.0.0(webpack@5.92.0):
+ copy-webpack-plugin@11.0.0(webpack@5.93.0):
dependencies:
fast-glob: 3.3.2
glob-parent: 6.0.2
@@ -8265,15 +8842,19 @@ snapshots:
normalize-path: 3.0.0
schema-utils: 4.2.0
serialize-javascript: 6.0.2
- webpack: 5.92.0
+ webpack: 5.93.0
core-js-compat@3.37.1:
dependencies:
- browserslist: 4.23.1
+ browserslist: 4.23.2
- core-js-pure@3.37.1: {}
+ core-js-compat@3.38.0:
+ dependencies:
+ browserslist: 4.23.3
- core-js@3.37.1: {}
+ core-js-pure@3.38.0: {}
+
+ core-js@3.38.0: {}
core-util-is@1.0.3: {}
@@ -8285,14 +8866,14 @@ snapshots:
path-type: 4.0.0
yaml: 1.10.2
- cosmiconfig@8.3.6(typescript@5.4.5):
+ cosmiconfig@8.3.6(typescript@5.5.4):
dependencies:
import-fresh: 3.3.0
js-yaml: 4.1.0
parse-json: 5.2.0
path-type: 4.0.0
optionalDependencies:
- typescript: 5.4.5
+ typescript: 5.5.4
cross-spawn@7.0.3:
dependencies:
@@ -8306,32 +8887,32 @@ snapshots:
css-color-keywords@1.0.0: {}
- css-declaration-sorter@7.2.0(postcss@8.4.38):
+ css-declaration-sorter@7.2.0(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
- css-loader@6.11.0(webpack@5.92.0):
+ css-loader@6.11.0(webpack@5.93.0):
dependencies:
- icss-utils: 5.1.0(postcss@8.4.38)
- postcss: 8.4.38
- postcss-modules-extract-imports: 3.1.0(postcss@8.4.38)
- postcss-modules-local-by-default: 4.0.5(postcss@8.4.38)
- postcss-modules-scope: 3.2.0(postcss@8.4.38)
- postcss-modules-values: 4.0.0(postcss@8.4.38)
+ icss-utils: 5.1.0(postcss@8.4.41)
+ postcss: 8.4.41
+ postcss-modules-extract-imports: 3.1.0(postcss@8.4.41)
+ postcss-modules-local-by-default: 4.0.5(postcss@8.4.41)
+ postcss-modules-scope: 3.2.0(postcss@8.4.41)
+ postcss-modules-values: 4.0.0(postcss@8.4.41)
postcss-value-parser: 4.2.0
- semver: 7.6.2
+ semver: 7.6.3
optionalDependencies:
- webpack: 5.92.0
+ webpack: 5.93.0
- css-minimizer-webpack-plugin@5.0.1(clean-css@5.3.3)(webpack@5.92.0):
+ css-minimizer-webpack-plugin@5.0.1(clean-css@5.3.3)(webpack@5.93.0):
dependencies:
'@jridgewell/trace-mapping': 0.3.25
- cssnano: 6.1.2(postcss@8.4.38)
+ cssnano: 6.1.2(postcss@8.4.41)
jest-worker: 29.7.0
- postcss: 8.4.38
+ postcss: 8.4.41
schema-utils: 4.2.0
serialize-javascript: 6.0.2
- webpack: 5.92.0
+ webpack: 5.93.0
optionalDependencies:
clean-css: 5.3.3
@@ -8371,60 +8952,60 @@ snapshots:
cssesc@3.0.0: {}
- cssnano-preset-advanced@6.1.2(postcss@8.4.38):
+ cssnano-preset-advanced@6.1.2(postcss@8.4.41):
dependencies:
- autoprefixer: 10.4.19(postcss@8.4.38)
- browserslist: 4.23.1
- cssnano-preset-default: 6.1.2(postcss@8.4.38)
- postcss: 8.4.38
- postcss-discard-unused: 6.0.5(postcss@8.4.38)
- postcss-merge-idents: 6.0.3(postcss@8.4.38)
- postcss-reduce-idents: 6.0.3(postcss@8.4.38)
- postcss-zindex: 6.0.2(postcss@8.4.38)
+ autoprefixer: 10.4.20(postcss@8.4.41)
+ browserslist: 4.23.3
+ cssnano-preset-default: 6.1.2(postcss@8.4.41)
+ postcss: 8.4.41
+ postcss-discard-unused: 6.0.5(postcss@8.4.41)
+ postcss-merge-idents: 6.0.3(postcss@8.4.41)
+ postcss-reduce-idents: 6.0.3(postcss@8.4.41)
+ postcss-zindex: 6.0.2(postcss@8.4.41)
- cssnano-preset-default@6.1.2(postcss@8.4.38):
+ cssnano-preset-default@6.1.2(postcss@8.4.41):
dependencies:
- browserslist: 4.23.1
- css-declaration-sorter: 7.2.0(postcss@8.4.38)
- cssnano-utils: 4.0.2(postcss@8.4.38)
- postcss: 8.4.38
- postcss-calc: 9.0.1(postcss@8.4.38)
- postcss-colormin: 6.1.0(postcss@8.4.38)
- postcss-convert-values: 6.1.0(postcss@8.4.38)
- postcss-discard-comments: 6.0.2(postcss@8.4.38)
- postcss-discard-duplicates: 6.0.3(postcss@8.4.38)
- postcss-discard-empty: 6.0.3(postcss@8.4.38)
- postcss-discard-overridden: 6.0.2(postcss@8.4.38)
- postcss-merge-longhand: 6.0.5(postcss@8.4.38)
- postcss-merge-rules: 6.1.1(postcss@8.4.38)
- postcss-minify-font-values: 6.1.0(postcss@8.4.38)
- postcss-minify-gradients: 6.0.3(postcss@8.4.38)
- postcss-minify-params: 6.1.0(postcss@8.4.38)
- postcss-minify-selectors: 6.0.4(postcss@8.4.38)
- postcss-normalize-charset: 6.0.2(postcss@8.4.38)
- postcss-normalize-display-values: 6.0.2(postcss@8.4.38)
- postcss-normalize-positions: 6.0.2(postcss@8.4.38)
- postcss-normalize-repeat-style: 6.0.2(postcss@8.4.38)
- postcss-normalize-string: 6.0.2(postcss@8.4.38)
- postcss-normalize-timing-functions: 6.0.2(postcss@8.4.38)
- postcss-normalize-unicode: 6.1.0(postcss@8.4.38)
- postcss-normalize-url: 6.0.2(postcss@8.4.38)
- postcss-normalize-whitespace: 6.0.2(postcss@8.4.38)
- postcss-ordered-values: 6.0.2(postcss@8.4.38)
- postcss-reduce-initial: 6.1.0(postcss@8.4.38)
- postcss-reduce-transforms: 6.0.2(postcss@8.4.38)
- postcss-svgo: 6.0.3(postcss@8.4.38)
- postcss-unique-selectors: 6.0.4(postcss@8.4.38)
+ browserslist: 4.23.3
+ css-declaration-sorter: 7.2.0(postcss@8.4.41)
+ cssnano-utils: 4.0.2(postcss@8.4.41)
+ postcss: 8.4.41
+ postcss-calc: 9.0.1(postcss@8.4.41)
+ postcss-colormin: 6.1.0(postcss@8.4.41)
+ postcss-convert-values: 6.1.0(postcss@8.4.41)
+ postcss-discard-comments: 6.0.2(postcss@8.4.41)
+ postcss-discard-duplicates: 6.0.3(postcss@8.4.41)
+ postcss-discard-empty: 6.0.3(postcss@8.4.41)
+ postcss-discard-overridden: 6.0.2(postcss@8.4.41)
+ postcss-merge-longhand: 6.0.5(postcss@8.4.41)
+ postcss-merge-rules: 6.1.1(postcss@8.4.41)
+ postcss-minify-font-values: 6.1.0(postcss@8.4.41)
+ postcss-minify-gradients: 6.0.3(postcss@8.4.41)
+ postcss-minify-params: 6.1.0(postcss@8.4.41)
+ postcss-minify-selectors: 6.0.4(postcss@8.4.41)
+ postcss-normalize-charset: 6.0.2(postcss@8.4.41)
+ postcss-normalize-display-values: 6.0.2(postcss@8.4.41)
+ postcss-normalize-positions: 6.0.2(postcss@8.4.41)
+ postcss-normalize-repeat-style: 6.0.2(postcss@8.4.41)
+ postcss-normalize-string: 6.0.2(postcss@8.4.41)
+ postcss-normalize-timing-functions: 6.0.2(postcss@8.4.41)
+ postcss-normalize-unicode: 6.1.0(postcss@8.4.41)
+ postcss-normalize-url: 6.0.2(postcss@8.4.41)
+ postcss-normalize-whitespace: 6.0.2(postcss@8.4.41)
+ postcss-ordered-values: 6.0.2(postcss@8.4.41)
+ postcss-reduce-initial: 6.1.0(postcss@8.4.41)
+ postcss-reduce-transforms: 6.0.2(postcss@8.4.41)
+ postcss-svgo: 6.0.3(postcss@8.4.41)
+ postcss-unique-selectors: 6.0.4(postcss@8.4.41)
- cssnano-utils@4.0.2(postcss@8.4.38):
+ cssnano-utils@4.0.2(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
- cssnano@6.1.2(postcss@8.4.38):
+ cssnano@6.1.2(postcss@8.4.41):
dependencies:
- cssnano-preset-default: 6.1.2(postcss@8.4.38)
+ cssnano-preset-default: 6.1.2(postcss@8.4.41)
lilconfig: 3.1.2
- postcss: 8.4.38
+ postcss: 8.4.41
csso@5.0.5:
dependencies:
@@ -8441,9 +9022,27 @@ snapshots:
whatwg-mimetype: 4.0.0
whatwg-url: 14.0.0
+ data-view-buffer@1.0.1:
+ dependencies:
+ call-bind: 1.0.7
+ es-errors: 1.3.0
+ is-data-view: 1.0.1
+
+ data-view-byte-length@1.0.1:
+ dependencies:
+ call-bind: 1.0.7
+ es-errors: 1.3.0
+ is-data-view: 1.0.1
+
+ data-view-byte-offset@1.0.0:
+ dependencies:
+ call-bind: 1.0.7
+ es-errors: 1.3.0
+ is-data-view: 1.0.1
+
date-fns@2.30.0:
dependencies:
- '@babel/runtime': 7.24.7
+ '@babel/runtime': 7.25.0
debounce@1.2.1: {}
@@ -8451,7 +9050,7 @@ snapshots:
dependencies:
ms: 2.0.0
- debug@4.3.5:
+ debug@4.3.6:
dependencies:
ms: 2.1.2
@@ -8524,7 +9123,7 @@ snapshots:
detect-port@1.6.1:
dependencies:
address: 1.2.2
- debug: 4.3.5
+ debug: 4.3.6
transitivePeerDependencies:
- supports-color
@@ -8536,40 +9135,46 @@ snapshots:
dependencies:
path-type: 4.0.0
+ discontinuous-range@1.0.0: {}
+
dns-packet@5.6.1:
dependencies:
'@leichtgewicht/ip-codec': 2.0.5
- docusaurus-plugin-redoc@2.0.2(@docusaurus/utils@3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5))(core-js@3.37.1)(mobx@6.12.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@6.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1)):
+ docusaurus-plugin-redoc@2.1.1(@docusaurus/utils@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4))(core-js@3.38.0)(enzyme@3.11.0)(mobx@6.13.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@6.1.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1)):
dependencies:
- '@docusaurus/utils': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
- '@redocly/openapi-core': 1.10.3
- redoc: 2.1.3(core-js@3.37.1)(mobx@6.12.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@6.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
+ '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
+ '@redocly/openapi-core': 1.16.0
+ redoc: 2.1.5(core-js@3.38.0)(enzyme@3.11.0)(mobx@6.13.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@6.1.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
transitivePeerDependencies:
- core-js
- encoding
+ - enzyme
- mobx
- react
- react-dom
- react-native
- styled-components
+ - supports-color
- docusaurus-theme-redoc@2.0.2(@docusaurus/theme-common@3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5))(core-js@3.37.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(webpack@5.92.0):
+ docusaurus-theme-redoc@2.1.1(@docusaurus/theme-common@3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(core-js@3.38.0)(enzyme@3.11.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(webpack@5.93.0):
dependencies:
- '@docusaurus/theme-common': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@redocly/openapi-core': 1.10.3
+ '@docusaurus/theme-common': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@redocly/openapi-core': 1.16.0
clsx: 1.2.1
lodash: 4.17.21
- mobx: 6.12.4
- redoc: 2.1.3(core-js@3.37.1)(mobx@6.12.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@6.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
- styled-components: 6.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- webpack: 5.92.0
+ mobx: 6.13.1
+ redoc: 2.1.5(core-js@3.38.0)(enzyme@3.11.0)(mobx@6.13.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@6.1.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
+ styled-components: 6.1.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ webpack: 5.93.0
transitivePeerDependencies:
- core-js
- encoding
+ - enzyme
- react
- react-dom
- react-native
+ - supports-color
dom-converter@0.2.0:
dependencies:
@@ -8597,9 +9202,7 @@ snapshots:
dependencies:
domelementtype: 2.3.0
- dompurify@2.5.5: {}
-
- dompurify@3.1.5: {}
+ dompurify@3.1.6: {}
domutils@2.8.0:
dependencies:
@@ -8628,7 +9231,9 @@ snapshots:
ee-first@1.1.1: {}
- electron-to-chromium@1.4.805: {}
+ electron-to-chromium@1.5.3: {}
+
+ electron-to-chromium@1.5.8: {}
emoji-regex@8.0.0: {}
@@ -8638,11 +9243,16 @@ snapshots:
emojis-list@3.0.0: {}
- emoticon@4.0.1: {}
+ emoticon@4.1.0: {}
encodeurl@1.0.2: {}
- enhanced-resolve@5.17.0:
+ encoding-sniffer@0.2.0:
+ dependencies:
+ iconv-lite: 0.6.3
+ whatwg-encoding: 3.1.1
+
+ enhanced-resolve@5.17.1:
dependencies:
graceful-fs: 4.2.11
tapable: 2.2.1
@@ -8651,26 +9261,127 @@ snapshots:
entities@4.5.0: {}
+ enzyme-shallow-equal@1.0.7:
+ dependencies:
+ hasown: 2.0.2
+ object-is: 1.1.6
+
+ enzyme@3.11.0:
+ dependencies:
+ array.prototype.flat: 1.3.2
+ cheerio: 1.0.0
+ enzyme-shallow-equal: 1.0.7
+ function.prototype.name: 1.1.6
+ has: 1.0.4
+ html-element-map: 1.3.1
+ is-boolean-object: 1.1.2
+ is-callable: 1.2.7
+ is-number-object: 1.0.7
+ is-regex: 1.1.4
+ is-string: 1.0.7
+ is-subset: 0.1.1
+ lodash.escape: 4.0.1
+ lodash.isequal: 4.5.0
+ object-inspect: 1.13.2
+ object-is: 1.1.6
+ object.assign: 4.1.5
+ object.entries: 1.1.8
+ object.values: 1.2.0
+ raf: 3.4.1
+ rst-selector-parser: 2.2.3
+ string.prototype.trim: 1.2.9
+
error-ex@1.3.2:
dependencies:
is-arrayish: 0.2.1
+ es-abstract@1.23.3:
+ dependencies:
+ array-buffer-byte-length: 1.0.1
+ arraybuffer.prototype.slice: 1.0.3
+ available-typed-arrays: 1.0.7
+ call-bind: 1.0.7
+ data-view-buffer: 1.0.1
+ data-view-byte-length: 1.0.1
+ data-view-byte-offset: 1.0.0
+ es-define-property: 1.0.0
+ es-errors: 1.3.0
+ es-object-atoms: 1.0.0
+ es-set-tostringtag: 2.0.3
+ es-to-primitive: 1.2.1
+ function.prototype.name: 1.1.6
+ get-intrinsic: 1.2.4
+ get-symbol-description: 1.0.2
+ globalthis: 1.0.4
+ gopd: 1.0.1
+ has-property-descriptors: 1.0.2
+ has-proto: 1.0.3
+ has-symbols: 1.0.3
+ hasown: 2.0.2
+ internal-slot: 1.0.7
+ is-array-buffer: 3.0.4
+ is-callable: 1.2.7
+ is-data-view: 1.0.1
+ is-negative-zero: 2.0.3
+ is-regex: 1.1.4
+ is-shared-array-buffer: 1.0.3
+ is-string: 1.0.7
+ is-typed-array: 1.1.13
+ is-weakref: 1.0.2
+ object-inspect: 1.13.2
+ object-keys: 1.1.1
+ object.assign: 4.1.5
+ regexp.prototype.flags: 1.5.2
+ safe-array-concat: 1.1.2
+ safe-regex-test: 1.0.3
+ string.prototype.trim: 1.2.9
+ string.prototype.trimend: 1.0.8
+ string.prototype.trimstart: 1.0.8
+ typed-array-buffer: 1.0.2
+ typed-array-byte-length: 1.0.1
+ typed-array-byte-offset: 1.0.2
+ typed-array-length: 1.0.6
+ unbox-primitive: 1.0.2
+ which-typed-array: 1.1.15
+
+ es-array-method-boxes-properly@1.0.0: {}
+
es-define-property@1.0.0:
dependencies:
get-intrinsic: 1.2.4
es-errors@1.3.0: {}
- es-module-lexer@1.5.3: {}
+ es-module-lexer@1.5.4: {}
+
+ es-object-atoms@1.0.0:
+ dependencies:
+ es-errors: 1.3.0
+
+ es-set-tostringtag@2.0.3:
+ dependencies:
+ get-intrinsic: 1.2.4
+ has-tostringtag: 1.0.2
+ hasown: 2.0.2
+
+ es-shim-unscopables@1.0.2:
+ dependencies:
+ hasown: 2.0.2
+
+ es-to-primitive@1.2.1:
+ dependencies:
+ is-callable: 1.2.7
+ is-date-object: 1.0.5
+ is-symbol: 1.0.4
es6-promise@3.3.1: {}
- esbuild-loader@4.2.0(webpack@5.92.0):
+ esbuild-loader@4.2.2(webpack@5.93.0):
dependencies:
esbuild: 0.21.5
- get-tsconfig: 4.7.5
+ get-tsconfig: 4.7.6
loader-utils: 2.0.4
- webpack: 5.92.0
+ webpack: 5.93.0
webpack-sources: 1.4.3
esbuild@0.21.5:
@@ -8745,15 +9456,14 @@ snapshots:
astring: 1.8.6
source-map: 0.7.4
- estree-util-value-to-estree@3.1.1:
+ estree-util-value-to-estree@3.1.2:
dependencies:
'@types/estree': 1.0.5
- is-plain-obj: 4.1.0
estree-util-visit@2.0.0:
dependencies:
'@types/estree-jsx': 1.0.5
- '@types/unist': 3.0.2
+ '@types/unist': 3.0.3
estree-walker@3.0.3:
dependencies:
@@ -8767,11 +9477,13 @@ snapshots:
eval@0.1.8:
dependencies:
- '@types/node': 20.14.5
+ '@types/node': 20.14.15
require-like: 0.1.2
eventemitter3@4.0.7: {}
+ eventemitter3@5.0.1: {}
+
events@3.3.0: {}
execa@5.1.1:
@@ -8842,6 +9554,8 @@ snapshots:
fast-safe-stringify@2.1.1: {}
+ fast-uri@3.0.1: {}
+
fast-url-parser@1.1.3:
dependencies:
punycode: 1.4.1
@@ -8862,11 +9576,11 @@ snapshots:
dependencies:
xml-js: 1.6.11
- file-loader@6.2.0(webpack@5.92.0):
+ file-loader@6.2.0(webpack@5.93.0):
dependencies:
loader-utils: 2.0.4
schema-utils: 3.3.0
- webpack: 5.92.0
+ webpack: 5.93.0
filesize@8.0.7: {}
@@ -8907,13 +9621,17 @@ snapshots:
flat@5.0.2: {}
- follow-redirects@1.15.6(debug@4.3.5):
+ follow-redirects@1.15.6(debug@4.3.6):
optionalDependencies:
- debug: 4.3.5
+ debug: 4.3.6
+
+ for-each@0.3.3:
+ dependencies:
+ is-callable: 1.2.7
foreach@2.0.6: {}
- fork-ts-checker-webpack-plugin@6.5.3(typescript@5.4.5)(webpack@5.92.0):
+ fork-ts-checker-webpack-plugin@6.5.3(typescript@5.5.4)(webpack@5.93.0):
dependencies:
'@babel/code-frame': 7.24.7
'@types/json-schema': 7.0.15
@@ -8926,10 +9644,10 @@ snapshots:
memfs: 3.5.3
minimatch: 3.1.2
schema-utils: 2.7.0
- semver: 7.6.2
+ semver: 7.6.3
tapable: 1.1.3
- typescript: 5.4.5
- webpack: 5.92.0
+ typescript: 5.5.4
+ webpack: 5.93.0
form-data-encoder@4.0.2: {}
@@ -8975,6 +9693,15 @@ snapshots:
function-bind@1.1.2: {}
+ function.prototype.name@1.1.6:
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-abstract: 1.23.3
+ functions-have-names: 1.2.3
+
+ functions-have-names@1.2.3: {}
+
fuse.js@7.0.0: {}
gensync@1.0.0-beta.2: {}
@@ -8993,14 +9720,18 @@ snapshots:
get-stream@6.0.1: {}
- get-stream@8.0.1: {}
-
get-stream@9.0.1:
dependencies:
'@sec-ant/readable-stream': 0.4.1
is-stream: 4.0.1
- get-tsconfig@4.7.5:
+ get-symbol-description@1.0.2:
+ dependencies:
+ call-bind: 1.0.7
+ es-errors: 1.3.0
+ get-intrinsic: 1.2.4
+
+ get-tsconfig@4.7.6:
dependencies:
resolve-pkg-maps: 1.0.0
@@ -9041,12 +9772,17 @@ snapshots:
globals@11.12.0: {}
+ globalthis@1.0.4:
+ dependencies:
+ define-properties: 1.2.1
+ gopd: 1.0.1
+
globby@11.1.0:
dependencies:
array-union: 2.1.0
dir-glob: 3.0.1
fast-glob: 3.3.2
- ignore: 5.3.1
+ ignore: 5.3.2
merge2: 1.4.1
slash: 3.0.0
@@ -9054,7 +9790,7 @@ snapshots:
dependencies:
dir-glob: 3.0.1
fast-glob: 3.3.2
- ignore: 5.3.1
+ ignore: 5.3.2
merge2: 1.4.1
slash: 4.0.0
@@ -9062,20 +9798,19 @@ snapshots:
dependencies:
get-intrinsic: 1.2.4
- got@14.4.1:
+ got@14.4.2:
dependencies:
- '@sindresorhus/is': 6.3.1
+ '@sindresorhus/is': 7.0.0
'@szmarczak/http-timer': 5.0.1
cacheable-lookup: 7.0.0
cacheable-request: 12.0.1
decompress-response: 6.0.0
form-data-encoder: 4.0.2
- get-stream: 8.0.1
http2-wrapper: 2.2.1
lowercase-keys: 3.0.0
p-cancelable: 4.0.1
responselike: 3.0.0
- type-fest: 4.20.1
+ type-fest: 4.24.0
graceful-fs@4.2.10: {}
@@ -9094,6 +9829,8 @@ snapshots:
handle-thing@2.0.1: {}
+ has-bigints@1.0.2: {}
+
has-flag@3.0.0: {}
has-flag@4.0.0: {}
@@ -9106,8 +9843,14 @@ snapshots:
has-symbols@1.0.3: {}
+ has-tostringtag@1.0.2:
+ dependencies:
+ has-symbols: 1.0.3
+
has-yarn@3.0.0: {}
+ has@1.0.4: {}
+
hasown@2.0.2:
dependencies:
function-bind: 1.1.2
@@ -9115,12 +9858,12 @@ snapshots:
hast-util-from-parse5@8.0.1:
dependencies:
'@types/hast': 3.0.4
- '@types/unist': 3.0.2
+ '@types/unist': 3.0.3
devlop: 1.1.0
hastscript: 8.0.0
property-information: 6.5.0
- vfile: 6.0.1
- vfile-location: 5.0.2
+ vfile: 6.0.2
+ vfile-location: 5.0.3
web-namespaces: 2.0.1
hast-util-parse-selector@4.0.0:
@@ -9130,7 +9873,7 @@ snapshots:
hast-util-raw@9.0.4:
dependencies:
'@types/hast': 3.0.4
- '@types/unist': 3.0.2
+ '@types/unist': 3.0.3
'@ungap/structured-clone': 1.2.0
hast-util-from-parse5: 8.0.1
hast-util-to-parse5: 8.0.0
@@ -9139,7 +9882,7 @@ snapshots:
parse5: 7.1.2
unist-util-position: 5.0.0
unist-util-visit: 5.0.0
- vfile: 6.0.1
+ vfile: 6.0.2
web-namespaces: 2.0.1
zwitch: 2.0.4
@@ -9168,7 +9911,7 @@ snapshots:
dependencies:
'@types/estree': 1.0.5
'@types/hast': 3.0.4
- '@types/unist': 3.0.2
+ '@types/unist': 3.0.3
comma-separated-tokens: 2.0.3
devlop: 1.1.0
estree-util-is-identifier-name: 3.0.0
@@ -9210,7 +9953,7 @@ snapshots:
history@4.10.1:
dependencies:
- '@babel/runtime': 7.24.7
+ '@babel/runtime': 7.25.0
loose-envify: 1.4.0
resolve-pathname: 3.0.0
tiny-invariant: 1.3.3
@@ -9228,6 +9971,11 @@ snapshots:
readable-stream: 2.3.8
wbuf: 1.7.3
+ html-element-map@1.3.1:
+ dependencies:
+ array.prototype.filter: 1.0.4
+ call-bind: 1.0.7
+
html-encoding-sniffer@4.0.0:
dependencies:
whatwg-encoding: 3.1.1
@@ -9244,7 +9992,7 @@ snapshots:
he: 1.2.0
param-case: 3.0.4
relateurl: 0.2.7
- terser: 5.31.1
+ terser: 5.31.6
html-minifier-terser@7.2.0:
dependencies:
@@ -9254,13 +10002,13 @@ snapshots:
entities: 4.5.0
param-case: 3.0.4
relateurl: 0.2.7
- terser: 5.31.1
+ terser: 5.31.6
html-tags@3.3.1: {}
html-void-elements@3.0.0: {}
- html-webpack-plugin@5.6.0(webpack@5.92.0):
+ html-webpack-plugin@5.6.0(webpack@5.93.0):
dependencies:
'@types/html-minifier-terser': 6.1.0
html-minifier-terser: 6.1.0
@@ -9268,7 +10016,7 @@ snapshots:
pretty-error: 4.0.0
tapable: 2.2.1
optionalDependencies:
- webpack: 5.92.0
+ webpack: 5.93.0
htmlparser2@6.1.0:
dependencies:
@@ -9284,6 +10032,13 @@ snapshots:
domutils: 3.1.0
entities: 4.5.0
+ htmlparser2@9.1.0:
+ dependencies:
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ domutils: 3.1.0
+ entities: 4.5.0
+
http-cache-semantics@4.1.1: {}
http-deceiver@1.2.7: {}
@@ -9308,14 +10063,14 @@ snapshots:
http-proxy-agent@7.0.2:
dependencies:
agent-base: 7.1.1
- debug: 4.3.5
+ debug: 4.3.6
transitivePeerDependencies:
- supports-color
- http-proxy-middleware@2.0.6(@types/express@4.17.21)(debug@4.3.5):
+ http-proxy-middleware@2.0.6(@types/express@4.17.21)(debug@4.3.6):
dependencies:
- '@types/http-proxy': 1.17.14
- http-proxy: 1.18.1(debug@4.3.5)
+ '@types/http-proxy': 1.17.15
+ http-proxy: 1.18.1(debug@4.3.6)
is-glob: 4.0.3
is-plain-obj: 3.0.0
micromatch: 4.0.7
@@ -9324,10 +10079,10 @@ snapshots:
transitivePeerDependencies:
- debug
- http-proxy@1.18.1(debug@4.3.5):
+ http-proxy@1.18.1(debug@4.3.6):
dependencies:
eventemitter3: 4.0.7
- follow-redirects: 1.15.6(debug@4.3.5)
+ follow-redirects: 1.15.6(debug@4.3.6)
requires-port: 1.0.0
transitivePeerDependencies:
- debug
@@ -9339,10 +10094,10 @@ snapshots:
quick-lru: 5.1.1
resolve-alpn: 1.2.1
- https-proxy-agent@7.0.4:
+ https-proxy-agent@7.0.5:
dependencies:
agent-base: 7.1.1
- debug: 4.3.5
+ debug: 4.3.6
transitivePeerDependencies:
- supports-color
@@ -9356,11 +10111,11 @@ snapshots:
dependencies:
safer-buffer: 2.1.2
- icss-utils@5.1.0(postcss@8.4.38):
+ icss-utils@5.1.0(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
- ignore@5.3.1: {}
+ ignore@5.3.2: {}
image-size@1.1.1:
dependencies:
@@ -9381,7 +10136,7 @@ snapshots:
indent-string@4.0.0: {}
- infima@0.2.0-alpha.43: {}
+ infima@0.2.0-alpha.44: {}
inflight@1.0.6:
dependencies:
@@ -9400,6 +10155,12 @@ snapshots:
inline-style-parser@0.2.3: {}
+ internal-slot@1.0.7:
+ dependencies:
+ es-errors: 1.3.0
+ hasown: 2.0.2
+ side-channel: 1.0.6
+
interpret@1.4.0: {}
invariant@2.2.4:
@@ -9417,20 +10178,44 @@ snapshots:
is-alphabetical: 2.0.1
is-decimal: 2.0.1
+ is-array-buffer@3.0.4:
+ dependencies:
+ call-bind: 1.0.7
+ get-intrinsic: 1.2.4
+
is-arrayish@0.2.1: {}
+ is-bigint@1.0.4:
+ dependencies:
+ has-bigints: 1.0.2
+
is-binary-path@2.1.0:
dependencies:
binary-extensions: 2.3.0
+ is-boolean-object@1.1.2:
+ dependencies:
+ call-bind: 1.0.7
+ has-tostringtag: 1.0.2
+
+ is-callable@1.2.7: {}
+
is-ci@3.0.1:
dependencies:
ci-info: 3.9.0
- is-core-module@2.13.1:
+ is-core-module@2.15.0:
dependencies:
hasown: 2.0.2
+ is-data-view@1.0.1:
+ dependencies:
+ is-typed-array: 1.1.13
+
+ is-date-object@1.0.5:
+ dependencies:
+ has-tostringtag: 1.0.2
+
is-decimal@2.0.1: {}
is-docker@2.2.1: {}
@@ -9452,8 +10237,14 @@ snapshots:
global-dirs: 3.0.1
is-path-inside: 3.0.3
+ is-negative-zero@2.0.3: {}
+
is-npm@6.0.0: {}
+ is-number-object@1.0.7:
+ dependencies:
+ has-tostringtag: 1.0.2
+
is-number@7.0.0: {}
is-obj@1.0.1: {}
@@ -9478,16 +10269,43 @@ snapshots:
dependencies:
'@types/estree': 1.0.5
+ is-regex@1.1.4:
+ dependencies:
+ call-bind: 1.0.7
+ has-tostringtag: 1.0.2
+
is-regexp@1.0.0: {}
is-root@2.1.0: {}
+ is-shared-array-buffer@1.0.3:
+ dependencies:
+ call-bind: 1.0.7
+
is-stream@2.0.1: {}
is-stream@4.0.1: {}
+ is-string@1.0.7:
+ dependencies:
+ has-tostringtag: 1.0.2
+
+ is-subset@0.1.1: {}
+
+ is-symbol@1.0.4:
+ dependencies:
+ has-symbols: 1.0.3
+
+ is-typed-array@1.1.13:
+ dependencies:
+ which-typed-array: 1.1.15
+
is-typedarray@1.0.0: {}
+ is-weakref@1.0.2:
+ dependencies:
+ call-bind: 1.0.7
+
is-wsl@2.2.0:
dependencies:
is-docker: 2.2.1
@@ -9498,15 +10316,17 @@ snapshots:
isarray@1.0.0: {}
+ isarray@2.0.5: {}
+
isexe@2.0.0: {}
isobject@3.0.1: {}
- isomorphic-dompurify@2.12.0:
+ isomorphic-dompurify@2.14.0:
dependencies:
'@types/dompurify': 3.0.5
- dompurify: 3.1.5
- jsdom: 24.1.0
+ dompurify: 3.1.6
+ jsdom: 24.1.1
transitivePeerDependencies:
- bufferutil
- canvas
@@ -9516,7 +10336,7 @@ snapshots:
jest-util@29.7.0:
dependencies:
'@jest/types': 29.6.3
- '@types/node': 20.14.5
+ '@types/node': 20.14.15
chalk: 4.1.2
ci-info: 3.9.0
graceful-fs: 4.2.11
@@ -9524,20 +10344,20 @@ snapshots:
jest-worker@27.5.1:
dependencies:
- '@types/node': 20.14.5
+ '@types/node': 20.14.15
merge-stream: 2.0.0
supports-color: 8.1.1
jest-worker@29.7.0:
dependencies:
- '@types/node': 20.14.5
+ '@types/node': 20.14.15
jest-util: 29.7.0
merge-stream: 2.0.0
supports-color: 8.1.1
jiti@1.21.6: {}
- joi@17.13.1:
+ joi@17.13.3:
dependencies:
'@hapi/hoek': 9.3.0
'@hapi/topo': 5.1.0
@@ -9558,7 +10378,7 @@ snapshots:
dependencies:
argparse: 2.0.1
- jsdom@24.1.0:
+ jsdom@24.1.1:
dependencies:
cssstyle: 4.0.1
data-urls: 5.0.0
@@ -9566,9 +10386,9 @@ snapshots:
form-data: 4.0.0
html-encoding-sniffer: 4.0.0
http-proxy-agent: 7.0.2
- https-proxy-agent: 7.0.4
+ https-proxy-agent: 7.0.5
is-potential-custom-element-name: 1.0.1
- nwsapi: 2.2.10
+ nwsapi: 2.2.12
parse5: 7.1.2
rrweb-cssom: 0.7.1
saxes: 6.0.0
@@ -9579,7 +10399,7 @@ snapshots:
whatwg-encoding: 3.1.1
whatwg-mimetype: 4.0.0
whatwg-url: 14.0.0
- ws: 8.17.1
+ ws: 8.18.0
xml-name-validator: 5.0.0
transitivePeerDependencies:
- bufferutil
@@ -9626,7 +10446,7 @@ snapshots:
dependencies:
package-json: 8.1.1
- launch-editor@2.7.0:
+ launch-editor@2.8.1:
dependencies:
picocolors: 1.0.1
shell-quote: 1.8.1
@@ -9662,6 +10482,10 @@ snapshots:
lodash.debounce@4.0.8: {}
+ lodash.escape@4.0.1: {}
+
+ lodash.flattendeep@4.4.0: {}
+
lodash.isequal@4.5.0: {}
lodash.memoize@4.1.2: {}
@@ -9696,14 +10520,14 @@ snapshots:
markdown-table@3.0.3: {}
- marked@13.0.0: {}
+ marked@14.0.0: {}
marked@4.3.0: {}
mdast-util-directive@3.0.0:
dependencies:
'@types/mdast': 4.0.4
- '@types/unist': 3.0.2
+ '@types/unist': 3.0.3
devlop: 1.1.0
mdast-util-from-markdown: 2.0.1
mdast-util-to-markdown: 2.1.0
@@ -9723,7 +10547,7 @@ snapshots:
mdast-util-from-markdown@2.0.1:
dependencies:
'@types/mdast': 4.0.4
- '@types/unist': 3.0.2
+ '@types/unist': 3.0.3
decode-named-character-reference: 1.0.2
devlop: 1.1.0
mdast-util-to-string: 4.0.0
@@ -9821,7 +10645,7 @@ snapshots:
'@types/estree-jsx': 1.0.5
'@types/hast': 3.0.4
'@types/mdast': 4.0.4
- '@types/unist': 3.0.2
+ '@types/unist': 3.0.3
ccount: 2.0.1
devlop: 1.1.0
mdast-util-from-markdown: 2.0.1
@@ -9870,12 +10694,12 @@ snapshots:
trim-lines: 3.0.1
unist-util-position: 5.0.0
unist-util-visit: 5.0.0
- vfile: 6.0.1
+ vfile: 6.0.2
mdast-util-to-markdown@2.1.0:
dependencies:
'@types/mdast': 4.0.4
- '@types/unist': 3.0.2
+ '@types/unist': 3.0.3
longest-streak: 3.1.0
mdast-util-phrasing: 4.1.0
mdast-util-to-string: 4.0.0
@@ -9924,7 +10748,7 @@ snapshots:
micromark-util-symbol: 2.0.0
micromark-util-types: 2.0.0
- micromark-extension-directive@3.0.0:
+ micromark-extension-directive@3.0.1:
dependencies:
devlop: 1.1.0
micromark-factory-space: 2.0.0
@@ -9941,14 +10765,14 @@ snapshots:
micromark-util-symbol: 2.0.0
micromark-util-types: 2.0.0
- micromark-extension-gfm-autolink-literal@2.0.0:
+ micromark-extension-gfm-autolink-literal@2.1.0:
dependencies:
micromark-util-character: 2.1.0
micromark-util-sanitize-uri: 2.0.0
micromark-util-symbol: 2.0.0
micromark-util-types: 2.0.0
- micromark-extension-gfm-footnote@2.0.0:
+ micromark-extension-gfm-footnote@2.1.0:
dependencies:
devlop: 1.1.0
micromark-core-commonmark: 2.0.1
@@ -9959,7 +10783,7 @@ snapshots:
micromark-util-symbol: 2.0.0
micromark-util-types: 2.0.0
- micromark-extension-gfm-strikethrough@2.0.0:
+ micromark-extension-gfm-strikethrough@2.1.0:
dependencies:
devlop: 1.1.0
micromark-util-chunked: 2.0.0
@@ -9968,7 +10792,7 @@ snapshots:
micromark-util-symbol: 2.0.0
micromark-util-types: 2.0.0
- micromark-extension-gfm-table@2.0.0:
+ micromark-extension-gfm-table@2.1.0:
dependencies:
devlop: 1.1.0
micromark-factory-space: 2.0.0
@@ -9980,7 +10804,7 @@ snapshots:
dependencies:
micromark-util-types: 2.0.0
- micromark-extension-gfm-task-list-item@2.0.1:
+ micromark-extension-gfm-task-list-item@2.1.0:
dependencies:
devlop: 1.1.0
micromark-factory-space: 2.0.0
@@ -9990,12 +10814,12 @@ snapshots:
micromark-extension-gfm@3.0.0:
dependencies:
- micromark-extension-gfm-autolink-literal: 2.0.0
- micromark-extension-gfm-footnote: 2.0.0
- micromark-extension-gfm-strikethrough: 2.0.0
- micromark-extension-gfm-table: 2.0.0
+ micromark-extension-gfm-autolink-literal: 2.1.0
+ micromark-extension-gfm-footnote: 2.1.0
+ micromark-extension-gfm-strikethrough: 2.1.0
+ micromark-extension-gfm-table: 2.1.0
micromark-extension-gfm-tagfilter: 2.0.0
- micromark-extension-gfm-task-list-item: 2.0.1
+ micromark-extension-gfm-task-list-item: 2.1.0
micromark-util-combine-extensions: 2.0.0
micromark-util-types: 2.0.0
@@ -10041,8 +10865,8 @@ snapshots:
micromark-extension-mdxjs@3.0.0:
dependencies:
- acorn: 8.12.0
- acorn-jsx: 5.3.2(acorn@8.12.0)
+ acorn: 8.12.1
+ acorn-jsx: 5.3.2(acorn@8.12.1)
micromark-extension-mdx-expression: 3.0.0
micromark-extension-mdx-jsx: 3.0.0
micromark-extension-mdx-md: 2.0.0
@@ -10140,7 +10964,7 @@ snapshots:
dependencies:
'@types/acorn': 4.0.6
'@types/estree': 1.0.5
- '@types/unist': 3.0.2
+ '@types/unist': 3.0.3
devlop: 1.1.0
estree-util-visit: 2.0.0
micromark-util-symbol: 2.0.0
@@ -10181,7 +11005,7 @@ snapshots:
micromark@4.0.0:
dependencies:
'@types/debug': 4.1.12
- debug: 4.3.5
+ debug: 4.3.6
decode-named-character-reference: 1.0.2
devlop: 1.1.0
micromark-core-commonmark: 2.0.1
@@ -10209,6 +11033,8 @@ snapshots:
mime-db@1.52.0: {}
+ mime-db@1.53.0: {}
+
mime-types@2.1.18:
dependencies:
mime-db: 1.33.0
@@ -10225,11 +11051,11 @@ snapshots:
mimic-response@4.0.0: {}
- mini-css-extract-plugin@2.9.0(webpack@5.92.0):
+ mini-css-extract-plugin@2.9.0(webpack@5.93.0):
dependencies:
schema-utils: 4.2.0
tapable: 2.2.1
- webpack: 5.92.0
+ webpack: 5.93.0
minimalistic-assert@1.0.1: {}
@@ -10243,22 +11069,25 @@ snapshots:
minimist@1.2.8: {}
- mobx-react-lite@3.4.3(mobx@6.12.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
+ mobx-react-lite@4.0.7(mobx@6.13.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
- mobx: 6.12.4
+ mobx: 6.13.1
+ react: 18.3.1
+ use-sync-external-store: 1.2.2(react@18.3.1)
+ optionalDependencies:
+ react-dom: 18.3.1(react@18.3.1)
+
+ mobx-react@9.1.1(mobx@6.13.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
+ dependencies:
+ mobx: 6.13.1
+ mobx-react-lite: 4.0.7(mobx@6.13.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react: 18.3.1
optionalDependencies:
react-dom: 18.3.1(react@18.3.1)
- mobx-react@7.6.0(mobx@6.12.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
- dependencies:
- mobx: 6.12.4
- mobx-react-lite: 3.4.3(mobx@6.12.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- react: 18.3.1
- optionalDependencies:
- react-dom: 18.3.1(react@18.3.1)
+ mobx@6.13.1: {}
- mobx@6.12.4: {}
+ moo@0.5.2: {}
mrmime@2.0.0: {}
@@ -10275,6 +11104,13 @@ snapshots:
nanoid@3.3.7: {}
+ nearley@2.20.1:
+ dependencies:
+ commander: 2.20.3
+ moo: 0.5.2
+ railroad-diagrams: 1.0.0
+ randexp: 0.4.6
+
negotiator@0.6.3: {}
neo-async@2.6.2: {}
@@ -10305,7 +11141,7 @@ snapshots:
dependencies:
es6-promise: 3.3.1
- node-releases@2.0.14: {}
+ node-releases@2.0.18: {}
normalize-path@3.0.0: {}
@@ -10323,7 +11159,7 @@ snapshots:
dependencies:
boolbase: 1.0.0
- nwsapi@2.2.10: {}
+ nwsapi@2.2.12: {}
oas-kit-common@1.0.8:
dependencies:
@@ -10358,7 +11194,12 @@ snapshots:
object-assign@4.1.1: {}
- object-inspect@1.13.1: {}
+ object-inspect@1.13.2: {}
+
+ object-is@1.1.6:
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
object-keys@1.1.1: {}
@@ -10369,6 +11210,18 @@ snapshots:
has-symbols: 1.0.3
object-keys: 1.1.1
+ object.entries@1.1.8:
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-object-atoms: 1.0.0
+
+ object.values@1.2.0:
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-object-atoms: 1.0.0
+
obuf@1.1.2: {}
on-finished@2.4.1:
@@ -10410,7 +11263,7 @@ snapshots:
p-limit@4.0.0:
dependencies:
- yocto-queue: 1.0.0
+ yocto-queue: 1.1.1
p-locate@3.0.0:
dependencies:
@@ -10437,10 +11290,10 @@ snapshots:
package-json@8.1.1:
dependencies:
- got: 14.4.1
+ got: 14.4.2
registry-auth-token: 5.0.2
registry-url: 6.0.1
- semver: 7.6.2
+ semver: 7.6.3
param-case@3.0.4:
dependencies:
@@ -10453,7 +11306,7 @@ snapshots:
parse-entities@4.0.1:
dependencies:
- '@types/unist': 2.0.10
+ '@types/unist': 2.0.11
character-entities: 2.0.2
character-entities-legacy: 3.0.0
character-reference-invalid: 2.0.1
@@ -10476,6 +11329,10 @@ snapshots:
domhandler: 5.0.3
parse5: 7.1.2
+ parse5-parser-stream@7.1.2:
+ dependencies:
+ parse5: 7.1.2
+
parse5@7.1.2:
dependencies:
entities: 4.5.0
@@ -10515,6 +11372,8 @@ snapshots:
perfect-scrollbar@1.5.5: {}
+ performance-now@2.1.0: {}
+
periscopic@3.1.0:
dependencies:
'@types/estree': 1.0.5
@@ -10537,217 +11396,219 @@ snapshots:
polished@4.3.1:
dependencies:
- '@babel/runtime': 7.24.7
+ '@babel/runtime': 7.25.0
- postcss-calc@9.0.1(postcss@8.4.38):
+ possible-typed-array-names@1.0.0: {}
+
+ postcss-calc@9.0.1(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
- postcss-selector-parser: 6.1.0
+ postcss: 8.4.41
+ postcss-selector-parser: 6.1.2
postcss-value-parser: 4.2.0
- postcss-colormin@6.1.0(postcss@8.4.38):
+ postcss-colormin@6.1.0(postcss@8.4.41):
dependencies:
- browserslist: 4.23.1
+ browserslist: 4.23.3
caniuse-api: 3.0.0
colord: 2.9.3
- postcss: 8.4.38
+ postcss: 8.4.41
postcss-value-parser: 4.2.0
- postcss-convert-values@6.1.0(postcss@8.4.38):
+ postcss-convert-values@6.1.0(postcss@8.4.41):
dependencies:
- browserslist: 4.23.1
- postcss: 8.4.38
+ browserslist: 4.23.3
+ postcss: 8.4.41
postcss-value-parser: 4.2.0
- postcss-discard-comments@6.0.2(postcss@8.4.38):
+ postcss-discard-comments@6.0.2(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
- postcss-discard-duplicates@6.0.3(postcss@8.4.38):
+ postcss-discard-duplicates@6.0.3(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
- postcss-discard-empty@6.0.3(postcss@8.4.38):
+ postcss-discard-empty@6.0.3(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
- postcss-discard-overridden@6.0.2(postcss@8.4.38):
+ postcss-discard-overridden@6.0.2(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
- postcss-discard-unused@6.0.5(postcss@8.4.38):
+ postcss-discard-unused@6.0.5(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
- postcss-selector-parser: 6.1.0
+ postcss: 8.4.41
+ postcss-selector-parser: 6.1.2
- postcss-loader@7.3.4(postcss@8.4.38)(typescript@5.4.5)(webpack@5.92.0):
+ postcss-loader@7.3.4(postcss@8.4.41)(typescript@5.5.4)(webpack@5.93.0):
dependencies:
- cosmiconfig: 8.3.6(typescript@5.4.5)
+ cosmiconfig: 8.3.6(typescript@5.5.4)
jiti: 1.21.6
- postcss: 8.4.38
- semver: 7.6.2
- webpack: 5.92.0
+ postcss: 8.4.41
+ semver: 7.6.3
+ webpack: 5.93.0
transitivePeerDependencies:
- typescript
- postcss-merge-idents@6.0.3(postcss@8.4.38):
+ postcss-merge-idents@6.0.3(postcss@8.4.41):
dependencies:
- cssnano-utils: 4.0.2(postcss@8.4.38)
- postcss: 8.4.38
+ cssnano-utils: 4.0.2(postcss@8.4.41)
+ postcss: 8.4.41
postcss-value-parser: 4.2.0
- postcss-merge-longhand@6.0.5(postcss@8.4.38):
+ postcss-merge-longhand@6.0.5(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
postcss-value-parser: 4.2.0
- stylehacks: 6.1.1(postcss@8.4.38)
+ stylehacks: 6.1.1(postcss@8.4.41)
- postcss-merge-rules@6.1.1(postcss@8.4.38):
+ postcss-merge-rules@6.1.1(postcss@8.4.41):
dependencies:
- browserslist: 4.23.1
+ browserslist: 4.23.3
caniuse-api: 3.0.0
- cssnano-utils: 4.0.2(postcss@8.4.38)
- postcss: 8.4.38
- postcss-selector-parser: 6.1.0
+ cssnano-utils: 4.0.2(postcss@8.4.41)
+ postcss: 8.4.41
+ postcss-selector-parser: 6.1.2
- postcss-minify-font-values@6.1.0(postcss@8.4.38):
+ postcss-minify-font-values@6.1.0(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
postcss-value-parser: 4.2.0
- postcss-minify-gradients@6.0.3(postcss@8.4.38):
+ postcss-minify-gradients@6.0.3(postcss@8.4.41):
dependencies:
colord: 2.9.3
- cssnano-utils: 4.0.2(postcss@8.4.38)
- postcss: 8.4.38
+ cssnano-utils: 4.0.2(postcss@8.4.41)
+ postcss: 8.4.41
postcss-value-parser: 4.2.0
- postcss-minify-params@6.1.0(postcss@8.4.38):
+ postcss-minify-params@6.1.0(postcss@8.4.41):
dependencies:
- browserslist: 4.23.1
- cssnano-utils: 4.0.2(postcss@8.4.38)
- postcss: 8.4.38
+ browserslist: 4.23.3
+ cssnano-utils: 4.0.2(postcss@8.4.41)
+ postcss: 8.4.41
postcss-value-parser: 4.2.0
- postcss-minify-selectors@6.0.4(postcss@8.4.38):
+ postcss-minify-selectors@6.0.4(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
- postcss-selector-parser: 6.1.0
+ postcss: 8.4.41
+ postcss-selector-parser: 6.1.2
- postcss-modules-extract-imports@3.1.0(postcss@8.4.38):
+ postcss-modules-extract-imports@3.1.0(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
- postcss-modules-local-by-default@4.0.5(postcss@8.4.38):
+ postcss-modules-local-by-default@4.0.5(postcss@8.4.41):
dependencies:
- icss-utils: 5.1.0(postcss@8.4.38)
- postcss: 8.4.38
- postcss-selector-parser: 6.1.0
+ icss-utils: 5.1.0(postcss@8.4.41)
+ postcss: 8.4.41
+ postcss-selector-parser: 6.1.2
postcss-value-parser: 4.2.0
- postcss-modules-scope@3.2.0(postcss@8.4.38):
+ postcss-modules-scope@3.2.0(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
- postcss-selector-parser: 6.1.0
+ postcss: 8.4.41
+ postcss-selector-parser: 6.1.2
- postcss-modules-values@4.0.0(postcss@8.4.38):
+ postcss-modules-values@4.0.0(postcss@8.4.41):
dependencies:
- icss-utils: 5.1.0(postcss@8.4.38)
- postcss: 8.4.38
+ icss-utils: 5.1.0(postcss@8.4.41)
+ postcss: 8.4.41
- postcss-normalize-charset@6.0.2(postcss@8.4.38):
+ postcss-normalize-charset@6.0.2(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
- postcss-normalize-display-values@6.0.2(postcss@8.4.38):
+ postcss-normalize-display-values@6.0.2(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
postcss-value-parser: 4.2.0
- postcss-normalize-positions@6.0.2(postcss@8.4.38):
+ postcss-normalize-positions@6.0.2(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
postcss-value-parser: 4.2.0
- postcss-normalize-repeat-style@6.0.2(postcss@8.4.38):
+ postcss-normalize-repeat-style@6.0.2(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
postcss-value-parser: 4.2.0
- postcss-normalize-string@6.0.2(postcss@8.4.38):
+ postcss-normalize-string@6.0.2(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
postcss-value-parser: 4.2.0
- postcss-normalize-timing-functions@6.0.2(postcss@8.4.38):
+ postcss-normalize-timing-functions@6.0.2(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
postcss-value-parser: 4.2.0
- postcss-normalize-unicode@6.1.0(postcss@8.4.38):
+ postcss-normalize-unicode@6.1.0(postcss@8.4.41):
dependencies:
- browserslist: 4.23.1
- postcss: 8.4.38
+ browserslist: 4.23.3
+ postcss: 8.4.41
postcss-value-parser: 4.2.0
- postcss-normalize-url@6.0.2(postcss@8.4.38):
+ postcss-normalize-url@6.0.2(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
postcss-value-parser: 4.2.0
- postcss-normalize-whitespace@6.0.2(postcss@8.4.38):
+ postcss-normalize-whitespace@6.0.2(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
postcss-value-parser: 4.2.0
- postcss-ordered-values@6.0.2(postcss@8.4.38):
+ postcss-ordered-values@6.0.2(postcss@8.4.41):
dependencies:
- cssnano-utils: 4.0.2(postcss@8.4.38)
- postcss: 8.4.38
+ cssnano-utils: 4.0.2(postcss@8.4.41)
+ postcss: 8.4.41
postcss-value-parser: 4.2.0
- postcss-reduce-idents@6.0.3(postcss@8.4.38):
+ postcss-reduce-idents@6.0.3(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
postcss-value-parser: 4.2.0
- postcss-reduce-initial@6.1.0(postcss@8.4.38):
+ postcss-reduce-initial@6.1.0(postcss@8.4.41):
dependencies:
- browserslist: 4.23.1
+ browserslist: 4.23.3
caniuse-api: 3.0.0
- postcss: 8.4.38
+ postcss: 8.4.41
- postcss-reduce-transforms@6.0.2(postcss@8.4.38):
+ postcss-reduce-transforms@6.0.2(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
postcss-value-parser: 4.2.0
- postcss-selector-parser@6.1.0:
+ postcss-selector-parser@6.1.2:
dependencies:
cssesc: 3.0.0
util-deprecate: 1.0.2
- postcss-sort-media-queries@5.2.0(postcss@8.4.38):
+ postcss-sort-media-queries@5.2.0(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
sort-css-media-queries: 2.2.0
- postcss-svgo@6.0.3(postcss@8.4.38):
+ postcss-svgo@6.0.3(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
postcss-value-parser: 4.2.0
svgo: 3.3.2
- postcss-unique-selectors@6.0.4(postcss@8.4.38):
+ postcss-unique-selectors@6.0.4(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
- postcss-selector-parser: 6.1.0
+ postcss: 8.4.41
+ postcss-selector-parser: 6.1.2
postcss-value-parser@4.2.0: {}
- postcss-zindex@6.0.2(postcss@8.4.38):
+ postcss-zindex@6.0.2(postcss@8.4.41):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.41
postcss@8.4.38:
dependencies:
@@ -10755,6 +11616,12 @@ snapshots:
picocolors: 1.0.1
source-map-js: 1.2.0
+ postcss@8.4.41:
+ dependencies:
+ nanoid: 3.3.7
+ picocolors: 1.0.1
+ source-map-js: 1.2.0
+
pretty-error@4.0.0:
dependencies:
lodash: 4.17.21
@@ -10818,6 +11685,17 @@ snapshots:
quick-lru@5.1.1: {}
+ raf@3.4.1:
+ dependencies:
+ performance-now: 2.1.0
+
+ railroad-diagrams@1.0.0: {}
+
+ randexp@0.4.6:
+ dependencies:
+ discontinuous-range: 1.0.0
+ ret: 0.1.15
+
randombytes@2.1.0:
dependencies:
safe-buffer: 5.2.1
@@ -10840,18 +11718,18 @@ snapshots:
minimist: 1.2.8
strip-json-comments: 2.0.1
- react-dev-utils@12.0.1(typescript@5.4.5)(webpack@5.92.0):
+ react-dev-utils@12.0.1(typescript@5.5.4)(webpack@5.93.0):
dependencies:
'@babel/code-frame': 7.24.7
address: 1.2.2
- browserslist: 4.23.1
+ browserslist: 4.23.3
chalk: 4.1.2
cross-spawn: 7.0.3
detect-port-alt: 1.1.6
escape-string-regexp: 4.0.0
filesize: 8.0.7
find-up: 5.0.0
- fork-ts-checker-webpack-plugin: 6.5.3(typescript@5.4.5)(webpack@5.92.0)
+ fork-ts-checker-webpack-plugin: 6.5.3(typescript@5.5.4)(webpack@5.93.0)
global-modules: 2.0.0
globby: 11.1.0
gzip-size: 6.0.0
@@ -10866,9 +11744,9 @@ snapshots:
shell-quote: 1.8.1
strip-ansi: 6.0.1
text-table: 0.2.0
- webpack: 5.92.0
+ webpack: 5.93.0
optionalDependencies:
- typescript: 5.4.5
+ typescript: 5.5.4
transitivePeerDependencies:
- eslint
- supports-color
@@ -10886,7 +11764,7 @@ snapshots:
react-helmet-async@1.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
- '@babel/runtime': 7.24.7
+ '@babel/runtime': 7.25.0
invariant: 2.2.4
prop-types: 15.8.1
react: 18.3.1
@@ -10903,25 +11781,27 @@ snapshots:
react-is@16.13.1: {}
+ react-is@18.3.1: {}
+
react-json-view-lite@1.4.0(react@18.3.1):
dependencies:
react: 18.3.1
- react-loadable-ssr-addon-v5-slorber@1.0.1(@docusaurus/react-loadable@6.0.0(react@18.3.1))(webpack@5.92.0):
+ react-loadable-ssr-addon-v5-slorber@1.0.1(@docusaurus/react-loadable@6.0.0(react@18.3.1))(webpack@5.93.0):
dependencies:
- '@babel/runtime': 7.24.7
+ '@babel/runtime': 7.25.0
react-loadable: '@docusaurus/react-loadable@6.0.0(react@18.3.1)'
- webpack: 5.92.0
+ webpack: 5.93.0
react-router-config@5.1.1(react-router@5.3.4(react@18.3.1))(react@18.3.1):
dependencies:
- '@babel/runtime': 7.24.7
+ '@babel/runtime': 7.25.0
react: 18.3.1
react-router: 5.3.4(react@18.3.1)
react-router-dom@5.3.4(react@18.3.1):
dependencies:
- '@babel/runtime': 7.24.7
+ '@babel/runtime': 7.25.0
history: 4.10.1
loose-envify: 1.4.0
prop-types: 15.8.1
@@ -10932,7 +11812,7 @@ snapshots:
react-router@5.3.4(react@18.3.1):
dependencies:
- '@babel/runtime': 7.24.7
+ '@babel/runtime': 7.25.0
history: 4.10.1
hoist-non-react-statics: 3.3.2
loose-envify: 1.4.0
@@ -10943,9 +11823,15 @@ snapshots:
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
- react-tabs@4.3.0(react@18.3.1):
+ react-shallow-renderer@16.15.0(react@18.3.1):
dependencies:
- clsx: 1.2.1
+ object-assign: 4.1.1
+ react: 18.3.1
+ react-is: 18.3.1
+
+ react-tabs@6.0.2(react@18.3.1):
+ dependencies:
+ clsx: 2.1.1
prop-types: 15.8.1
react: 18.3.1
@@ -10983,20 +11869,21 @@ snapshots:
dependencies:
minimatch: 3.1.2
- redoc@2.1.3(core-js@3.37.1)(mobx@6.12.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@6.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1)):
+ redoc@2.1.5(core-js@3.38.0)(enzyme@3.11.0)(mobx@6.13.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@6.1.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1)):
dependencies:
- '@redocly/openapi-core': 1.10.3
+ '@cfaester/enzyme-adapter-react-18': 0.8.0(enzyme@3.11.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@redocly/openapi-core': 1.16.0
classnames: 2.5.1
- core-js: 3.37.1
+ core-js: 3.38.0
decko: 1.2.0
- dompurify: 2.5.5
- eventemitter3: 4.0.7
+ dompurify: 3.1.6
+ eventemitter3: 5.0.1
json-pointer: 0.6.2
lunr: 2.3.9
mark.js: 8.11.1
marked: 4.3.0
- mobx: 6.12.4
- mobx-react: 7.6.0(mobx@6.12.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ mobx: 6.13.1
+ mobx-react: 9.1.1(mobx@6.13.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
openapi-sampler: 1.5.1
path-browserify: 1.0.1
perfect-scrollbar: 1.5.5
@@ -11005,30 +11892,34 @@ snapshots:
prop-types: 15.8.1
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- react-tabs: 4.3.0(react@18.3.1)
+ react-tabs: 6.0.2(react@18.3.1)
slugify: 1.4.7
stickyfill: 1.1.1
- styled-components: 6.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ styled-components: 6.1.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
swagger2openapi: 7.0.8
url-template: 2.0.8
transitivePeerDependencies:
- encoding
+ - enzyme
- react-native
+ - supports-color
- redocusaurus@2.0.2(@docusaurus/theme-common@3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5))(@docusaurus/utils@3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5))(core-js@3.37.1)(mobx@6.12.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@6.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(webpack@5.92.0):
+ redocusaurus@2.1.1(@docusaurus/theme-common@3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/utils@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4))(core-js@3.38.0)(enzyme@3.11.0)(mobx@6.13.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@6.1.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(webpack@5.93.0):
dependencies:
- '@docusaurus/theme-common': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)
- '@docusaurus/utils': 3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5)
- docusaurus-plugin-redoc: 2.0.2(@docusaurus/utils@3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.4.5))(core-js@3.37.1)(mobx@6.12.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@6.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
- docusaurus-theme-redoc: 2.0.2(@docusaurus/theme-common@3.4.0(@docusaurus/types@3.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5))(core-js@3.37.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(webpack@5.92.0)
+ '@docusaurus/theme-common': 3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)
+ '@docusaurus/utils': 3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4)
+ docusaurus-plugin-redoc: 2.1.1(@docusaurus/utils@3.5.2(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.5.4))(core-js@3.38.0)(enzyme@3.11.0)(mobx@6.13.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(styled-components@6.1.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
+ docusaurus-theme-redoc: 2.1.1(@docusaurus/theme-common@3.5.2(@docusaurus/plugin-content-docs@3.5.2(@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(@docusaurus/types@3.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4))(core-js@3.38.0)(enzyme@3.11.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(webpack@5.93.0)
transitivePeerDependencies:
- core-js
- encoding
+ - enzyme
- mobx
- react
- react-dom
- react-native
- styled-components
+ - supports-color
- webpack
reftools@1.1.9: {}
@@ -11043,7 +11934,14 @@ snapshots:
regenerator-transform@0.15.2:
dependencies:
- '@babel/runtime': 7.24.7
+ '@babel/runtime': 7.25.0
+
+ regexp.prototype.flags@1.5.2:
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-errors: 1.3.0
+ set-function-name: 2.0.2
regexpu-core@5.3.2:
dependencies:
@@ -11056,7 +11954,7 @@ snapshots:
registry-auth-token@5.0.2:
dependencies:
- '@pnpm/npm-conf': 2.2.2
+ '@pnpm/npm-conf': 2.3.1
registry-url@6.0.1:
dependencies:
@@ -11070,7 +11968,7 @@ snapshots:
dependencies:
'@types/hast': 3.0.4
hast-util-raw: 9.0.4
- vfile: 6.0.1
+ vfile: 6.0.2
relateurl@0.2.7: {}
@@ -11078,25 +11976,25 @@ snapshots:
dependencies:
'@types/mdast': 4.0.4
mdast-util-directive: 3.0.0
- micromark-extension-directive: 3.0.0
- unified: 11.0.4
+ micromark-extension-directive: 3.0.1
+ unified: 11.0.5
transitivePeerDependencies:
- supports-color
remark-emoji@4.0.1:
dependencies:
'@types/mdast': 4.0.4
- emoticon: 4.0.1
+ emoticon: 4.1.0
mdast-util-find-and-replace: 3.0.1
node-emoji: 2.1.3
- unified: 11.0.4
+ unified: 11.0.5
remark-frontmatter@5.0.0:
dependencies:
'@types/mdast': 4.0.4
mdast-util-frontmatter: 2.0.1
micromark-extension-frontmatter: 2.0.0
- unified: 11.0.4
+ unified: 11.0.5
transitivePeerDependencies:
- supports-color
@@ -11107,7 +12005,7 @@ snapshots:
micromark-extension-gfm: 3.0.0
remark-parse: 11.0.0
remark-stringify: 11.0.0
- unified: 11.0.4
+ unified: 11.0.5
transitivePeerDependencies:
- supports-color
@@ -11123,7 +12021,7 @@ snapshots:
'@types/mdast': 4.0.4
mdast-util-from-markdown: 2.0.1
micromark-util-types: 2.0.0
- unified: 11.0.4
+ unified: 11.0.5
transitivePeerDependencies:
- supports-color
@@ -11132,14 +12030,14 @@ snapshots:
'@types/hast': 3.0.4
'@types/mdast': 4.0.4
mdast-util-to-hast: 13.2.0
- unified: 11.0.4
- vfile: 6.0.1
+ unified: 11.0.5
+ vfile: 6.0.2
remark-stringify@11.0.0:
dependencies:
'@types/mdast': 4.0.4
mdast-util-to-markdown: 2.1.0
- unified: 11.0.4
+ unified: 11.0.5
renderkid@3.0.0:
dependencies:
@@ -11167,7 +12065,7 @@ snapshots:
resolve@1.22.8:
dependencies:
- is-core-module: 2.13.1
+ is-core-module: 2.15.0
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
@@ -11175,6 +12073,8 @@ snapshots:
dependencies:
lowercase-keys: 3.0.0
+ ret@0.1.15: {}
+
retry@0.13.1: {}
reusify@1.0.4: {}
@@ -11187,13 +12087,18 @@ snapshots:
rrweb-cssom@0.7.1: {}
+ rst-selector-parser@2.2.3:
+ dependencies:
+ lodash.flattendeep: 4.4.0
+ nearley: 2.20.1
+
rtl-detect@1.1.2: {}
- rtlcss@4.1.1:
+ rtlcss@4.2.0:
dependencies:
escalade: 3.1.2
picocolors: 1.0.1
- postcss: 8.4.38
+ postcss: 8.4.41
strip-json-comments: 3.1.1
run-parallel@1.2.0:
@@ -11204,10 +12109,23 @@ snapshots:
dependencies:
tslib: 2.6.3
+ safe-array-concat@1.1.2:
+ dependencies:
+ call-bind: 1.0.7
+ get-intrinsic: 1.2.4
+ has-symbols: 1.0.3
+ isarray: 2.0.5
+
safe-buffer@5.1.2: {}
safe-buffer@5.2.1: {}
+ safe-regex-test@1.0.3:
+ dependencies:
+ call-bind: 1.0.7
+ es-errors: 1.3.0
+ is-regex: 1.1.4
+
safer-buffer@2.1.2: {}
sax@1.4.1: {}
@@ -11235,11 +12153,11 @@ snapshots:
schema-utils@4.2.0:
dependencies:
'@types/json-schema': 7.0.15
- ajv: 8.16.0
- ajv-formats: 2.1.1(ajv@8.16.0)
- ajv-keywords: 5.1.0(ajv@8.16.0)
+ ajv: 8.17.1
+ ajv-formats: 2.1.1(ajv@8.17.1)
+ ajv-keywords: 5.1.0(ajv@8.17.1)
- search-insights@2.14.0: {}
+ search-insights@2.15.0: {}
section-matter@1.0.0:
dependencies:
@@ -11255,11 +12173,11 @@ snapshots:
semver-diff@4.0.0:
dependencies:
- semver: 7.6.2
+ semver: 7.6.3
semver@6.3.1: {}
- semver@7.6.2: {}
+ semver@7.6.3: {}
send@0.18.0:
dependencies:
@@ -11324,6 +12242,13 @@ snapshots:
gopd: 1.0.1
has-property-descriptors: 1.0.2
+ set-function-name@2.0.2:
+ dependencies:
+ define-data-property: 1.1.4
+ es-errors: 1.3.0
+ functions-have-names: 1.2.3
+ has-property-descriptors: 1.0.2
+
setprototypeof@1.1.0: {}
setprototypeof@1.2.0: {}
@@ -11379,7 +12304,7 @@ snapshots:
call-bind: 1.0.7
es-errors: 1.3.0
get-intrinsic: 1.2.4
- object-inspect: 1.13.1
+ object-inspect: 1.13.2
signal-exit@3.0.7: {}
@@ -11440,7 +12365,7 @@ snapshots:
spdy-transport@3.0.0:
dependencies:
- debug: 4.3.5
+ debug: 4.3.6
detect-node: 2.1.0
hpack.js: 2.1.6
obuf: 1.1.2
@@ -11451,7 +12376,7 @@ snapshots:
spdy@4.0.2:
dependencies:
- debug: 4.3.5
+ debug: 4.3.6
handle-thing: 2.0.1
http-deceiver: 1.2.7
select-hose: 2.0.0
@@ -11483,6 +12408,25 @@ snapshots:
emoji-regex: 9.2.2
strip-ansi: 7.1.0
+ string.prototype.trim@1.2.9:
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-abstract: 1.23.3
+ es-object-atoms: 1.0.0
+
+ string.prototype.trimend@1.0.8:
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-object-atoms: 1.0.0
+
+ string.prototype.trimstart@1.0.8:
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-object-atoms: 1.0.0
+
string_decoder@1.1.1:
dependencies:
safe-buffer: 5.1.2
@@ -11526,7 +12470,7 @@ snapshots:
dependencies:
inline-style-parser: 0.2.3
- styled-components@6.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
+ styled-components@6.1.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@emotion/is-prop-valid': 1.2.2
'@emotion/unitless': 0.8.1
@@ -11540,11 +12484,11 @@ snapshots:
stylis: 4.3.2
tslib: 2.6.2
- stylehacks@6.1.1(postcss@8.4.38):
+ stylehacks@6.1.1(postcss@8.4.41):
dependencies:
- browserslist: 4.23.1
- postcss: 8.4.38
- postcss-selector-parser: 6.1.0
+ browserslist: 4.23.3
+ postcss: 8.4.41
+ postcss-selector-parser: 6.1.2
stylis@4.3.2: {}
@@ -11596,19 +12540,19 @@ snapshots:
tapable@2.2.1: {}
- terser-webpack-plugin@5.3.10(webpack@5.92.0):
+ terser-webpack-plugin@5.3.10(webpack@5.93.0):
dependencies:
'@jridgewell/trace-mapping': 0.3.25
jest-worker: 27.5.1
schema-utils: 3.3.0
serialize-javascript: 6.0.2
- terser: 5.31.1
- webpack: 5.92.0
+ terser: 5.31.6
+ webpack: 5.93.0
- terser@5.31.1:
+ terser@5.31.6:
dependencies:
'@jridgewell/source-map': 0.3.6
- acorn: 8.12.0
+ acorn: 8.12.1
commander: 2.20.3
source-map-support: 0.5.21
@@ -11657,21 +12601,62 @@ snapshots:
type-fest@2.19.0: {}
- type-fest@4.20.1: {}
+ type-fest@4.24.0: {}
type-is@1.6.18:
dependencies:
media-typer: 0.3.0
mime-types: 2.1.35
+ typed-array-buffer@1.0.2:
+ dependencies:
+ call-bind: 1.0.7
+ es-errors: 1.3.0
+ is-typed-array: 1.1.13
+
+ typed-array-byte-length@1.0.1:
+ dependencies:
+ call-bind: 1.0.7
+ for-each: 0.3.3
+ gopd: 1.0.1
+ has-proto: 1.0.3
+ is-typed-array: 1.1.13
+
+ typed-array-byte-offset@1.0.2:
+ dependencies:
+ available-typed-arrays: 1.0.7
+ call-bind: 1.0.7
+ for-each: 0.3.3
+ gopd: 1.0.1
+ has-proto: 1.0.3
+ is-typed-array: 1.1.13
+
+ typed-array-length@1.0.6:
+ dependencies:
+ call-bind: 1.0.7
+ for-each: 0.3.3
+ gopd: 1.0.1
+ has-proto: 1.0.3
+ is-typed-array: 1.1.13
+ possible-typed-array-names: 1.0.0
+
typedarray-to-buffer@3.1.5:
dependencies:
is-typedarray: 1.0.0
- typescript@5.4.5: {}
+ typescript@5.5.4: {}
+
+ unbox-primitive@1.0.2:
+ dependencies:
+ call-bind: 1.0.7
+ has-bigints: 1.0.2
+ has-symbols: 1.0.3
+ which-boxed-primitive: 1.0.2
undici-types@5.26.5: {}
+ undici@6.19.7: {}
+
unicode-canonical-property-names-ecmascript@2.0.0: {}
unicode-emoji-modifier-base@1.0.0: {}
@@ -11685,15 +12670,15 @@ snapshots:
unicode-property-aliases-ecmascript@2.1.0: {}
- unified@11.0.4:
+ unified@11.0.5:
dependencies:
- '@types/unist': 3.0.2
+ '@types/unist': 3.0.3
bail: 2.0.2
devlop: 1.1.0
extend: 3.0.2
is-plain-obj: 4.1.0
trough: 2.2.0
- vfile: 6.0.1
+ vfile: 6.0.2
unique-string@3.0.0:
dependencies:
@@ -11701,33 +12686,33 @@ snapshots:
unist-util-is@6.0.0:
dependencies:
- '@types/unist': 3.0.2
+ '@types/unist': 3.0.3
unist-util-position-from-estree@2.0.0:
dependencies:
- '@types/unist': 3.0.2
+ '@types/unist': 3.0.3
unist-util-position@5.0.0:
dependencies:
- '@types/unist': 3.0.2
+ '@types/unist': 3.0.3
unist-util-remove-position@5.0.0:
dependencies:
- '@types/unist': 3.0.2
+ '@types/unist': 3.0.3
unist-util-visit: 5.0.0
unist-util-stringify-position@4.0.0:
dependencies:
- '@types/unist': 3.0.2
+ '@types/unist': 3.0.3
unist-util-visit-parents@6.0.1:
dependencies:
- '@types/unist': 3.0.2
+ '@types/unist': 3.0.3
unist-util-is: 6.0.0
unist-util-visit@5.0.0:
dependencies:
- '@types/unist': 3.0.2
+ '@types/unist': 3.0.3
unist-util-is: 6.0.0
unist-util-visit-parents: 6.0.1
@@ -11737,9 +12722,15 @@ snapshots:
unpipe@1.0.0: {}
- update-browserslist-db@1.0.16(browserslist@4.23.1):
+ update-browserslist-db@1.1.0(browserslist@4.23.2):
dependencies:
- browserslist: 4.23.1
+ browserslist: 4.23.2
+ escalade: 3.1.2
+ picocolors: 1.0.1
+
+ update-browserslist-db@1.1.0(browserslist@4.23.3):
+ dependencies:
+ browserslist: 4.23.3
escalade: 3.1.2
picocolors: 1.0.1
@@ -11756,7 +12747,7 @@ snapshots:
is-yarn-global: 0.4.1
latest-version: 7.0.0
pupa: 3.1.0
- semver: 7.6.2
+ semver: 7.6.3
semver-diff: 4.0.0
xdg-basedir: 5.1.0
@@ -11764,14 +12755,14 @@ snapshots:
dependencies:
punycode: 2.3.1
- url-loader@4.1.1(file-loader@6.2.0(webpack@5.92.0))(webpack@5.92.0):
+ url-loader@4.1.1(file-loader@6.2.0(webpack@5.93.0))(webpack@5.93.0):
dependencies:
loader-utils: 2.0.4
mime-types: 2.1.35
schema-utils: 3.3.0
- webpack: 5.92.0
+ webpack: 5.93.0
optionalDependencies:
- file-loader: 6.2.0(webpack@5.92.0)
+ file-loader: 6.2.0(webpack@5.93.0)
url-parse@1.5.10:
dependencies:
@@ -11780,6 +12771,10 @@ snapshots:
url-template@2.0.8: {}
+ use-sync-external-store@1.2.2(react@18.3.1):
+ dependencies:
+ react: 18.3.1
+
util-deprecate@1.0.2: {}
utila@0.4.0: {}
@@ -11794,19 +12789,19 @@ snapshots:
vary@1.1.2: {}
- vfile-location@5.0.2:
+ vfile-location@5.0.3:
dependencies:
- '@types/unist': 3.0.2
- vfile: 6.0.1
+ '@types/unist': 3.0.3
+ vfile: 6.0.2
vfile-message@4.0.2:
dependencies:
- '@types/unist': 3.0.2
+ '@types/unist': 3.0.3
unist-util-stringify-position: 4.0.0
- vfile@6.0.1:
+ vfile@6.0.2:
dependencies:
- '@types/unist': 3.0.2
+ '@types/unist': 3.0.3
unist-util-stringify-position: 4.0.0
vfile-message: 4.0.2
@@ -11814,7 +12809,7 @@ snapshots:
dependencies:
xml-name-validator: 5.0.0
- watchpack@2.4.1:
+ watchpack@2.4.2:
dependencies:
glob-to-regexp: 0.4.1
graceful-fs: 4.2.11
@@ -11832,7 +12827,7 @@ snapshots:
webpack-bundle-analyzer@4.10.2:
dependencies:
'@discoveryjs/json-ext': 0.5.7
- acorn: 8.12.0
+ acorn: 8.12.1
acorn-walk: 8.3.3
commander: 7.2.0
debounce: 1.2.1
@@ -11847,16 +12842,16 @@ snapshots:
- bufferutil
- utf-8-validate
- webpack-dev-middleware@5.3.4(webpack@5.92.0):
+ webpack-dev-middleware@5.3.4(webpack@5.93.0):
dependencies:
colorette: 2.0.20
memfs: 3.5.3
mime-types: 2.1.35
range-parser: 1.2.1
schema-utils: 4.2.0
- webpack: 5.92.0
+ webpack: 5.93.0
- webpack-dev-server@4.15.2(debug@4.3.5)(webpack@5.92.0):
+ webpack-dev-server@4.15.2(debug@4.3.6)(webpack@5.93.0):
dependencies:
'@types/bonjour': 3.5.13
'@types/connect-history-api-fallback': 1.5.4
@@ -11864,7 +12859,7 @@ snapshots:
'@types/serve-index': 1.9.4
'@types/serve-static': 1.15.7
'@types/sockjs': 0.3.36
- '@types/ws': 8.5.10
+ '@types/ws': 8.5.12
ansi-html-community: 0.0.8
bonjour-service: 1.2.1
chokidar: 3.6.0
@@ -11875,9 +12870,9 @@ snapshots:
express: 4.19.2
graceful-fs: 4.2.11
html-entities: 2.5.2
- http-proxy-middleware: 2.0.6(@types/express@4.17.21)(debug@4.3.5)
+ http-proxy-middleware: 2.0.6(@types/express@4.17.21)(debug@4.3.6)
ipaddr.js: 2.2.0
- launch-editor: 2.7.0
+ launch-editor: 2.8.1
open: 8.4.2
p-retry: 4.6.2
rimraf: 3.0.2
@@ -11886,10 +12881,10 @@ snapshots:
serve-index: 1.9.1
sockjs: 0.3.24
spdy: 4.0.2
- webpack-dev-middleware: 5.3.4(webpack@5.92.0)
- ws: 8.17.1
+ webpack-dev-middleware: 5.3.4(webpack@5.93.0)
+ ws: 8.18.0
optionalDependencies:
- webpack: 5.92.0
+ webpack: 5.93.0
transitivePeerDependencies:
- bufferutil
- debug
@@ -11909,19 +12904,19 @@ snapshots:
webpack-sources@3.2.3: {}
- webpack@5.92.0:
+ webpack@5.93.0:
dependencies:
'@types/eslint-scope': 3.7.7
'@types/estree': 1.0.5
'@webassemblyjs/ast': 1.12.1
'@webassemblyjs/wasm-edit': 1.12.1
'@webassemblyjs/wasm-parser': 1.12.1
- acorn: 8.12.0
- acorn-import-attributes: 1.9.5(acorn@8.12.0)
- browserslist: 4.23.1
+ acorn: 8.12.1
+ acorn-import-attributes: 1.9.5(acorn@8.12.1)
+ browserslist: 4.23.3
chrome-trace-event: 1.0.4
- enhanced-resolve: 5.17.0
- es-module-lexer: 1.5.3
+ enhanced-resolve: 5.17.1
+ es-module-lexer: 1.5.4
eslint-scope: 5.1.1
events: 3.3.0
glob-to-regexp: 0.4.1
@@ -11932,21 +12927,21 @@ snapshots:
neo-async: 2.6.2
schema-utils: 3.3.0
tapable: 2.2.1
- terser-webpack-plugin: 5.3.10(webpack@5.92.0)
- watchpack: 2.4.1
+ terser-webpack-plugin: 5.3.10(webpack@5.93.0)
+ watchpack: 2.4.2
webpack-sources: 3.2.3
transitivePeerDependencies:
- '@swc/core'
- esbuild
- uglify-js
- webpackbar@5.0.2(webpack@5.92.0):
+ webpackbar@5.0.2(webpack@5.93.0):
dependencies:
chalk: 4.1.2
consola: 2.15.3
pretty-time: 1.1.0
std-env: 3.7.0
- webpack: 5.92.0
+ webpack: 5.93.0
websocket-driver@0.7.4:
dependencies:
@@ -11972,6 +12967,22 @@ snapshots:
tr46: 0.0.3
webidl-conversions: 3.0.1
+ which-boxed-primitive@1.0.2:
+ dependencies:
+ is-bigint: 1.0.4
+ is-boolean-object: 1.1.2
+ is-number-object: 1.0.7
+ is-string: 1.0.7
+ is-symbol: 1.0.4
+
+ which-typed-array@1.1.15:
+ dependencies:
+ available-typed-arrays: 1.0.7
+ call-bind: 1.0.7
+ for-each: 0.3.3
+ gopd: 1.0.1
+ has-tostringtag: 1.0.2
+
which@1.3.1:
dependencies:
isexe: 2.0.0
@@ -12009,7 +13020,7 @@ snapshots:
ws@7.5.10: {}
- ws@8.17.1: {}
+ ws@8.18.0: {}
xdg-basedir@5.1.0: {}
@@ -12029,7 +13040,7 @@ snapshots:
yaml@1.10.2: {}
- yaml@2.4.5: {}
+ yaml@2.5.0: {}
yargs-parser@21.1.1: {}
@@ -12045,6 +13056,6 @@ snapshots:
yocto-queue@0.1.0: {}
- yocto-queue@1.0.0: {}
+ yocto-queue@1.1.1: {}
zwitch@2.0.4: {}
diff --git a/docs/src/pages/index.tsx b/docs/src/pages/index.tsx
index 9fc47c2e5..0bddd28db 100644
--- a/docs/src/pages/index.tsx
+++ b/docs/src/pages/index.tsx
@@ -14,7 +14,7 @@ function HomepageHeader() {
{siteConfig.title}
{siteConfig.tagline}
-
+
Woodpecker Tutorial - 5min ⏱️
@@ -28,7 +28,7 @@ export default function Home() {
return (
diff --git a/docs/src/pages/versions.md b/docs/src/pages/versions.md
index 1b9778e4d..4efe1bcf3 100644
--- a/docs/src/pages/versions.md
+++ b/docs/src/pages/versions.md
@@ -33,6 +33,7 @@ Here you can find documentation for previous versions of Woodpecker.
| | | |
| ------- | ---------- | ------------------------------------------------------------------------------------- |
+| 2.6.0 | 2024-07-18 | [Documentation](https://github.com/woodpecker-ci/woodpecker/tree/v2.6.0/docs/docs/) |
| 2.5.0 | 2024-06-01 | [Documentation](https://github.com/woodpecker-ci/woodpecker/tree/v2.5.0/docs/docs/) |
| 2.4.1 | 2024-03-20 | [Documentation](https://github.com/woodpecker-ci/woodpecker/tree/v2.4.1/docs/docs/) |
| 2.4.0 | 2024-03-19 | [Documentation](https://github.com/woodpecker-ci/woodpecker/tree/v2.4.0/docs/docs/) |
diff --git a/docs/versioned_docs/version-1.0/92-development/01-getting-started.md b/docs/versioned_docs/version-1.0/92-development/01-getting-started.md
index 509589e67..748c27710 100644
--- a/docs/versioned_docs/version-1.0/92-development/01-getting-started.md
+++ b/docs/versioned_docs/version-1.0/92-development/01-getting-started.md
@@ -39,7 +39,7 @@ For dependencies installation (node_modules) for the UI and documentation of Woo
### Create a `.env` file with your development configuration
-Similar to the environment variables you can set for your production setup of Woodpecker, you can create a `.env` in the root of the Woodpecker project and add any need config to it.
+Similar to the environment variables you can set for your production setup of Woodpecker, you can create a `.env` file in the root of the Woodpecker project and add any needed config to it.
A common config for debugging would look like this:
diff --git a/docs/versioned_docs/version-2.4/10-intro.md b/docs/versioned_docs/version-2.4/10-intro.md
deleted file mode 100644
index 276dcb000..000000000
--- a/docs/versioned_docs/version-2.4/10-intro.md
+++ /dev/null
@@ -1,89 +0,0 @@
-# Welcome to Woodpecker
-
-Woodpecker is a simple yet powerful CI/CD engine with great extensibility. It focuses on executing pipelines inside [containers](https://opencontainers.org/).
-If you are already using containers in your daily workflow, you'll for sure love Woodpecker.
-
-![woodpecker](woodpecker.png)
-
-## `.woodpecker.yaml`
-
-- Place your pipeline in a file named `.woodpecker.yaml` in your repository
-- Pipeline steps can be named as you like
-- Run any command in the commands section
-
-```yaml title=".woodpecker.yaml"
-steps:
- - name: build
- image: debian
- commands:
- - echo "This is the build step"
- - name: a-test-step
- image: debian
- commands:
- - echo "Testing.."
-```
-
-### Steps are containers
-
-- Define any container image as context
- - either use your own and install the needed tools in a custom image
- - or search for available images that are already tailored for your needs in image registries like [Docker Hub](https://hub.docker.com/search?type=image)
-- List the commands that should be executed in the container
-
-```diff
- steps:
- - name: build
-- image: debian
-+ image: mycompany/image-with-awscli
- commands:
- - aws help
-```
-
-### File changes are incremental
-
-- Woodpecker clones the source code in the beginning
-- File changes are persisted throughout individual steps as the same volume is being mounted in all steps
-
-```yaml title=".woodpecker.yaml"
-steps:
- - name: build
- image: debian
- commands:
- - touch myfile
- - name: a-test-step
- image: debian
- commands:
- - cat myfile
-```
-
-## Plugins are straightforward
-
-- If you copy the same shell script from project to project
-- Pack it into a plugin instead
-- And make the yaml declarative
-- Plugins are Docker images with your script as an entrypoint
-
-```dockerfile title="Dockerfile"
-FROM laszlocloud/kubectl
-COPY deploy /usr/local/deploy
-ENTRYPOINT ["/usr/local/deploy"]
-```
-
-```bash title="deploy"
-kubectl apply -f $PLUGIN_TEMPLATE
-```
-
-```yaml title=".woodpecker.yaml"
-steps:
- deploy-to-k8s:
- image: laszlocloud/my-k8s-plugin
- settings:
- template: config/k8s/service.yaml
-```
-
-See [plugin docs](./20-usage/51-plugins/10-overview.md).
-
-## Continue reading
-
-- [Create a Woodpecker pipeline for your repository](./20-usage/10-intro.md)
-- [Setup your own Woodpecker instance](./30-administration/00-deployment/00-overview.md)
diff --git a/docs/versioned_docs/version-2.4/20-usage/10-intro.md b/docs/versioned_docs/version-2.4/20-usage/10-intro.md
deleted file mode 100644
index 477466173..000000000
--- a/docs/versioned_docs/version-2.4/20-usage/10-intro.md
+++ /dev/null
@@ -1,72 +0,0 @@
-# Getting started
-
-## Repository Activation
-
-To activate your project navigate to your account settings. You will see a list of repositories which can be activated with a simple toggle. When you activate your repository, Woodpecker automatically adds webhooks to your forge (e.g. GitHub, Gitea, ...).
-
-Webhooks are used to trigger pipeline executions. When you push code to your repository, open a pull request, or create a tag, your forge will automatically send a webhook to Woodpecker which will in turn trigger the pipeline execution.
-
-![repository list](repo-list.png)
-
-## Required Permissions
-
-The user who enables a repo in Woodpecker must have `Admin` rights on that repo, so that Woodpecker can add the webhook.
-
-:::note
-Note that manually creating webhooks yourself is not possible.
-This is because webhooks are signed using a per-repository secret key which is not exposed to end users.
-:::
-
-## Configuration
-
-To configure your pipeline you must create a `.woodpecker.yaml` file in the root of your repository. The `.woodpecker.yaml` file is used to define your pipeline steps.
-
-:::note
-We support most of YAML 1.2, but preserve some behavior from 1.1 for backward compatibility.
-Read more at: [https://github.com/go-yaml/yaml](https://github.com/go-yaml/yaml/tree/v3)
-:::
-
-Example pipeline configuration:
-
-```yaml
-steps:
- - name: build
- image: golang
- commands:
- - go get
- - go build
- - go test
-
-services:
- - name: postgres
- image: postgres:9.4.5
- environment:
- - POSTGRES_USER=myapp
-```
-
-Example pipeline configuration with multiple, serial steps:
-
-```yaml
-steps:
- - name: backend
- image: golang
- commands:
- - go get
- - go build
- - go test
-
- - name: frontend
- image: node:6
- commands:
- - npm install
- - npm test
-
- - name: notify
- image: plugins/slack
- channel: developers
- username: woodpecker
-```
-
-## Execution
-
-To trigger your first pipeline execution you can push code to your repository, open a pull request, or push a tag. Any of these events triggers a webhook from your forge and execute your pipeline.
diff --git a/docs/versioned_docs/version-2.4/20-usage/repo-list.png b/docs/versioned_docs/version-2.4/20-usage/repo-list.png
deleted file mode 100644
index b47380087..000000000
Binary files a/docs/versioned_docs/version-2.4/20-usage/repo-list.png and /dev/null differ
diff --git a/docs/versioned_docs/version-2.4/30-administration/00-deployment/00-overview.md b/docs/versioned_docs/version-2.4/30-administration/00-deployment/00-overview.md
deleted file mode 100644
index b2b6dadfd..000000000
--- a/docs/versioned_docs/version-2.4/30-administration/00-deployment/00-overview.md
+++ /dev/null
@@ -1,90 +0,0 @@
-# Deployment
-
-A Woodpecker deployment consists of two parts:
-
-- A server which is the heart of Woodpecker and ships the web interface.
-- Next to one server, you can deploy any number of agents which will run the pipelines.
-
-Each agent is able to process one pipeline step by default.
-If you have four agents installed and connected to the Woodpecker server, your system will process four workflows in parallel.
-
-:::tip
-You can add more agents to increase the number of parallel workflows or set the agent's `WOODPECKER_MAX_WORKFLOWS=1` environment variable to increase the number of parallel workflows for that agent.
-:::
-
-## Which version of Woodpecker should I use?
-
-Woodpecker is having two different kinds of releases: **stable** and **next**.
-
-### Stable releases
-
-We release a new version every four weeks and will release the current state of the `main` branch.
-If there are security fixes or critical bug fixes, we'll release them directly.
-There are no backports or similar.
-
-#### Versioning
-
-We use [Semantic Versioning](https://semver.org/) to be able,
-to communicate when admins have to do manual migration steps and when they can just bump versions up.
-
-#### Breaking changes
-
-As of semver guidelines, breaking changes will be released as a major version. We will hold back
-breaking changes to not release many majors each containing just a few breaking changes.
-Prior to the release of a major version, a release candidate (RC) will be published to allow easy testing,
-the actual release will be about a week later.
-
-## Hardware Requirements
-
-Below are minimal resources requirements for Woodpecker components itself:
-
-| Component | Memory | CPU |
-| --------- | ------ | --- |
-| Server | 200 MB | 1 |
-| Agent | 32 MB | 1 |
-
-Note, that those values do not include the operating system or workload (pipelines execution) resources consumption.
-
-In addition you need at least some kind of database which requires additional resources depending on the selected database system.
-
-## Installation
-
-You can install Woodpecker on multiple ways:
-
-- Using [docker-compose](./10-docker-compose.md) with the official [container images](./10-docker-compose.md#docker-images)
-- Using [Kubernetes](./20-kubernetes.md) via the Woodpecker Helm chart
-- Using binaries, DEBs or RPMs you can download from [latest release](https://github.com/woodpecker-ci/woodpecker/releases/latest)
-
-## Authentication
-
-Authentication is done using OAuth and is delegated to your forge which is configured using environment variables.
-
-See the complete reference for all supported forges [here](../11-forges/10-overview.md).
-
-## Database
-
-By default Woodpecker uses a SQLite database which requires zero installation or configuration. See the [database settings](../30-database.md) page to further configure it or use MySQL or Postgres.
-
-## SSL
-
-Woodpecker supports SSL configuration by using Let's encrypt or by using own certificates. See the [SSL guide](../60-ssl.md). You can also put it behind a [reverse proxy](#behind-a-proxy)
-
-## Metrics
-
-A [Prometheus endpoint](../90-prometheus.md) is exposed.
-
-## Behind a proxy
-
-See the [proxy guide](../70-proxy.md) if you want to see a setup behind Apache, Nginx, Caddy or ngrok.
-
-In the case you need to use Woodpecker with a URL path prefix (like: ), add the root path to [`WOODPECKER_HOST`](../10-server-config.md#woodpecker_host).
-
-## Third-party installation methods
-
-:::info
-These installation methods are not officially supported. If you experience issues with them, please open issues in the specific repositories.
-:::
-
-- Using [NixOS](./30-nixos.md) via the [NixOS module](https://search.nixos.org/options?channel=unstable&size=200&sort=relevance&query=woodpecker)
-- [Using YunoHost](https://apps.yunohost.org/app/woodpecker)
-- [On Cloudron](https://www.cloudron.io/store/org.woodpecker_ci.cloudronapp.html)
diff --git a/docs/versioned_docs/version-2.4/30-administration/00-deployment/_category_.yaml b/docs/versioned_docs/version-2.4/30-administration/00-deployment/_category_.yaml
deleted file mode 100644
index 728434969..000000000
--- a/docs/versioned_docs/version-2.4/30-administration/00-deployment/_category_.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-label: 'Deployment'
-collapsible: true
-collapsed: true
-link:
- type: 'doc'
- id: 'overview'
diff --git a/docs/versioned_docs/version-2.4/30-administration/11-forges/10-overview.md b/docs/versioned_docs/version-2.4/30-administration/11-forges/10-overview.md
deleted file mode 100644
index 4446896f0..000000000
--- a/docs/versioned_docs/version-2.4/30-administration/11-forges/10-overview.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Forges
-
-## Supported features
-
-| Feature | [GitHub](20-github.md) | [Gitea / Forgejo](30-gitea.md) | [Gitlab](40-gitlab.md) | [Bitbucket](50-bitbucket.md) | [Bitbucket Datacenter](60-bitbucket_datacenter.md) |
-| ------------------------------------------------------------- | :--------------------: | :----------------------------: | :--------------------: | :--------------------------: | :------------------------------------------------: |
-| Event: Push | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
-| Event: Tag | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
-| Event: Pull-Request | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
-| Event: Release | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: |
-| Event: Deploy | :white_check_mark: | :x: | :x: | :x: | :x: |
-| [Multiple workflows](../../20-usage/25-workflows.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
-| [when.path filter](../../20-usage/20-workflow-syntax.md#path) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: |
diff --git a/docs/versioned_docs/version-2.4/30-administration/75-addons/00-overview.md b/docs/versioned_docs/version-2.4/30-administration/75-addons/00-overview.md
deleted file mode 100644
index 747dc4b36..000000000
--- a/docs/versioned_docs/version-2.4/30-administration/75-addons/00-overview.md
+++ /dev/null
@@ -1,40 +0,0 @@
-# Addons
-
-:::warning
-Addons are still experimental. Their implementation can change and break at any time.
-:::
-
-:::danger
-You need to trust the author of the addons you use. Depending on their type, addons can access forge authentication codes, your secrets or other sensitive information.
-:::
-
-To adapt Woodpecker to your needs beyond the [configuration](../10-server-config.md), Woodpecker has its own **addon** system, built ontop of [Go's internal plugin system](https://go.dev/pkg/plugin).
-
-Addons can be used for:
-
-- Forges
-
-## Restrictions
-
-Addons are restricted by how Go plugins work. This includes the following restrictions:
-
-- only supported on Linux, FreeBSD, and macOS
-- addons must have been built for the correct Woodpecker version. If an addon is not provided specifically for this version, you likely won't be able to use it.
-
-## Usage
-
-To use an addon, download the addon version built for your Woodpecker version. Then, you can add the following to your configuration:
-
-```ini
-WOODPECKER_ADDONS=/path/to/your/addon/file.so
-```
-
-In case you run Woodpecker as container, you probably want to mount the addon binaries to `/opt/addons/`.
-
-You can list multiple addons, Woodpecker will automatically determine their type. If you specify multiple addons with the same type, only the first one will be used.
-
-Using an addon always overwrites Woodpecker's internal setup. This means, that a forge addon will be used if specified, no matter what's configured for the forges natively supported by Woodpecker.
-
-### Bug reports
-
-If you experience bugs, please check which component has the issue. If it's the addon, **do not raise an issue in the main repository**, but rather use the separate addon repositories. To check which component is responsible for the bug, look at the logs. Logs from addons are marked with a special field `addon` containing their addon file name.
diff --git a/docs/versioned_docs/version-2.4/30-administration/75-addons/20-creating-addons.md b/docs/versioned_docs/version-2.4/30-administration/75-addons/20-creating-addons.md
deleted file mode 100644
index 283c456f4..000000000
--- a/docs/versioned_docs/version-2.4/30-administration/75-addons/20-creating-addons.md
+++ /dev/null
@@ -1,97 +0,0 @@
-# Creating addons
-
-Addons are written in Go.
-
-## Writing your code
-
-An addon consists of two variables/functions in Go.
-
-1. The `Type` variable. Specifies the type of the addon and must be directly accessed from `shared/addons/types/types.go`.
-2. The `Addon` function which is the main point of your addon.
- This function takes the `zerolog` logger you should use to log errors, warnings, etc. as argument.
-
- It returns two values:
-
- 1. The actual addon. For type reference see [table below](#return-types).
- 2. An error. If this error is not `nil`, Woodpecker exits.
-
-Directly import Woodpecker's Go package (`go.woodpecker-ci.org/woodpecker/woodpecker/v2`) and use the interfaces and types defined there.
-
-### Return types
-
-| Addon type | Return type |
-| ---------- | -------------------------------------------------------------------- |
-| `Forge` | `"go.woodpecker-ci.org/woodpecker/woodpecker/v2/server/forge".Forge` |
-
-### Using configurations
-
-If you write a plugin for the server (`Forge` and the services), you can access the server config.
-
-Therefore, use the `"go.woodpecker-ci.org/woodpecker/v2/server".Config` variable.
-
-:::warning
-The config is not available when your addon is initialized, i.e., the `Addon` function is called.
-Only use the config in the interface methods.
-:::
-
-## Compiling
-
-After you write your addon code, compile your addon:
-
-```sh
-go build -buildmode plugin
-```
-
-The output file is your addon that is now ready to be used.
-
-## Restrictions
-
-Addons must directly depend on Woodpecker's core (`go.woodpecker-ci.org/woodpecker/woodpecker/v2`).
-The addon must have been built with **exactly the same code** as the Woodpecker instance you'd like to use it on. This means: If you build your addon with a specific commit from Woodpecker `next`, you can likely only use it with the Woodpecker version compiled from this commit.
-Also, if you change something inside Woodpecker without committing, it might fail because you need to recompile your addon with this code first.
-
-In addition to this, addons are only supported on Linux, FreeBSD, and macOS.
-
-:::info
-It is recommended to at least support the latest version of Woodpecker.
-:::
-
-### Compile for different versions
-
-As long as there are no changes to Woodpecker's interfaces,
-or they are backwards-compatible, you can compile the addon for multiple versions
-by changing the version of `go.woodpecker-ci.org/woodpecker/woodpecker/v2` using `go get` before compiling.
-
-## Logging
-
-The entrypoint receives a `zerolog.Logger` as input. **Do not use any other logging solution.** This logger follows the configuration of the Woodpecker instance and adds a special field `addon` to the log entries which allows users to find out which component is writing the log messages.
-
-## Example structure
-
-```go
-package main
-
-import (
- "context"
- "net/http"
-
- "github.com/rs/zerolog"
- "go.woodpecker-ci.org/woodpecker/v2/server/forge"
- forge_types "go.woodpecker-ci.org/woodpecker/v2/server/forge/types"
- "go.woodpecker-ci.org/woodpecker/v2/server/model"
- addon_types "go.woodpecker-ci.org/woodpecker/v2/shared/addon/types"
-)
-
-var Type = addon_types.TypeForge
-
-func Addon(logger zerolog.Logger) (forge.Forge, error) {
- logger.Info().Msg("hello world from addon")
- return &config{l: logger}, nil
-}
-
-type config struct {
- l zerolog.Logger
-}
-
-// In this case, `config` must implement `forge.Forge`. You must directly use Woodpecker's packages - see imports above.
-```
diff --git a/docs/versioned_docs/version-2.4/40-cli.md b/docs/versioned_docs/version-2.4/40-cli.md
deleted file mode 100644
index 639c2ebfb..000000000
--- a/docs/versioned_docs/version-2.4/40-cli.md
+++ /dev/null
@@ -1,595 +0,0 @@
-# CLI
-
-# NAME
-
-woodpecker-cli - A new cli application
-
-# SYNOPSIS
-
-woodpecker-cli
-
-```
-[--config|-c]=[value]
-[--disable-update-check]
-[--log-file]=[value]
-[--log-level]=[value]
-[--nocolor]
-[--pretty]
-[--server|-s]=[value]
-[--token|-t]=[value]
-```
-
-# DESCRIPTION
-
-Woodpecker command line utility
-
-**Usage**:
-
-```
-woodpecker-cli [GLOBAL OPTIONS] command [COMMAND OPTIONS] [ARGUMENTS...]
-```
-
-# GLOBAL OPTIONS
-
-**--config, -c**="": path to config file
-
-**--disable-update-check**: disable update check
-
-**--log-file**="": Output destination for logs. 'stdout' and 'stderr' can be used as special keywords. (default: "stderr")
-
-**--log-level**="": set logging level (default: "info")
-
-**--nocolor**: disable colored debug output, only has effect if pretty output is set too
-
-**--pretty**: enable pretty-printed debug output
-
-**--server, -s**="": server address
-
-**--token, -t**="": server auth token
-
-
-# COMMANDS
-
-## pipeline
-
-manage pipelines
-
-### ls
-
-show pipeline history
-
-**--branch**="": branch filter
-
-**--event**="": event filter
-
-**--format**="": format output (default: "\x1b[33mPipeline #{{ .Number }} \x1b[0m\nStatus: {{ .Status }}\nEvent: {{ .Event }}\nCommit: {{ .Commit }}\nBranch: {{ .Branch }}\nRef: {{ .Ref }}\nAuthor: {{ .Author }} {{ if .Email }}<{{.Email}}>{{ end }}\nMessage: {{ .Message }}\n")
-
-**--limit**="": limit the list size (default: 25)
-
-**--status**="": status filter
-
-### last
-
-show latest pipeline details
-
-**--branch**="": branch name (default: "main")
-
-**--format**="": format output (default: "Number: {{ .Number }}\nStatus: {{ .Status }}\nEvent: {{ .Event }}\nCommit: {{ .Commit }}\nBranch: {{ .Branch }}\nRef: {{ .Ref }}\nMessage: {{ .Message }}\nAuthor: {{ .Author }}\n")
-
-### logs
-
-show pipeline logs
-
-### info
-
-show pipeline details
-
-**--format**="": format output (default: "Number: {{ .Number }}\nStatus: {{ .Status }}\nEvent: {{ .Event }}\nCommit: {{ .Commit }}\nBranch: {{ .Branch }}\nRef: {{ .Ref }}\nMessage: {{ .Message }}\nAuthor: {{ .Author }}\n")
-
-### stop
-
-stop a pipeline
-
-### start
-
-start a pipeline
-
-**--param, -p**="": custom parameters to be injected into the step environment. Format: KEY=value
-
-### approve
-
-approve a pipeline
-
-### decline
-
-decline a pipeline
-
-### queue
-
-show pipeline queue
-
-**--format**="": format output (default: "\x1b[33m{{ .FullName }} #{{ .Number }} \x1b[0m\nStatus: {{ .Status }}\nEvent: {{ .Event }}\nCommit: {{ .Commit }}\nBranch: {{ .Branch }}\nRef: {{ .Ref }}\nAuthor: {{ .Author }} {{ if .Email }}<{{.Email}}>{{ end }}\nMessage: {{ .Message }}\n")
-
-### ps
-
-show pipeline steps
-
-**--format**="": format output (default: "\x1b[33mStep #{{ .PID }} \x1b[0m\nStep: {{ .Name }}\nState: {{ .State }}\n")
-
-### create
-
-create new pipeline
-
-**--branch**="": branch to create pipeline from
-
-**--format**="": format output (default: "\x1b[33mPipeline #{{ .Number }} \x1b[0m\nStatus: {{ .Status }}\nEvent: {{ .Event }}\nCommit: {{ .Commit }}\nBranch: {{ .Branch }}\nRef: {{ .Ref }}\nAuthor: {{ .Author }} {{ if .Email }}<{{.Email}}>{{ end }}\nMessage: {{ .Message }}\n")
-
-**--var**="": key=value
-
-## log
-
-manage logs
-
-### purge
-
-purge a log
-
-## deploy
-
-deploy code
-
-**--branch**="": branch filter (default: "main")
-
-**--event**="": event filter (default: "push")
-
-**--format**="": format output (default: "Number: {{ .Number }}\nStatus: {{ .Status }}\nCommit: {{ .Commit }}\nBranch: {{ .Branch }}\nRef: {{ .Ref }}\nMessage: {{ .Message }}\nAuthor: {{ .Author }}\nTarget: {{ .Deploy }}\n")
-
-**--param, -p**="": custom parameters to be injected into the step environment. Format: KEY=value
-
-**--status**="": status filter (default: "success")
-
-## exec
-
-execute a local pipeline
-
-**--backend-docker-api-version**="": the version of the API to reach, leave empty for latest.
-
-**--backend-docker-cert**="": path to load the TLS certificates for connecting to docker server
-
-**--backend-docker-host**="": path to docker socket or url to the docker server
-
-**--backend-docker-ipv6**: backend docker enable IPV6
-
-**--backend-docker-network**="": backend docker network
-
-**--backend-docker-tls-verify**: enable or disable TLS verification for connecting to docker server
-
-**--backend-docker-volumes**="": backend docker volumes (comma separated)
-
-**--backend-engine**="": backend engine to run pipelines on (default: "auto-detect")
-
-**--backend-http-proxy**="": if set, pass the environment variable down as "HTTP_PROXY" to steps
-
-**--backend-https-proxy**="": if set, pass the environment variable down as "HTTPS_PROXY" to steps
-
-**--backend-k8s-namespace**="": backend k8s namespace (default: "woodpecker")
-
-**--backend-k8s-pod-annotations**="": backend k8s additional worker pod annotations
-
-**--backend-k8s-pod-image-pull-secret-names**="": backend k8s pull secret names for private registries (default: "regcred")
-
-**--backend-k8s-pod-labels**="": backend k8s additional worker pod labels
-
-**--backend-k8s-secctx-nonroot**: `run as non root` Kubernetes security context option
-
-**--backend-k8s-storage-class**="": backend k8s storage class
-
-**--backend-k8s-storage-rwx**: backend k8s storage access mode, should ReadWriteMany (RWX) instead of ReadWriteOnce (RWO) be used? (default: true)
-
-**--backend-k8s-volume-size**="": backend k8s volume size (default 10G) (default: "10G")
-
-**--backend-local-temp-dir**="": set a different temp dir to clone workflows into (default: "/tmp")
-
-**--backend-no-proxy**="": if set, pass the environment variable down as "NO_PROXY" to steps
-
-**--commit-author-avatar**="":
-
-**--commit-author-email**="":
-
-**--commit-author-name**="":
-
-**--commit-branch**="":
-
-**--commit-message**="":
-
-**--commit-ref**="":
-
-**--commit-refspec**="":
-
-**--commit-sha**="":
-
-**--env**="":
-
-**--forge-type**="":
-
-**--forge-url**="":
-
-**--local**: run from local directory
-
-**--netrc-machine**="":
-
-**--netrc-password**="":
-
-**--netrc-username**="":
-
-**--network**="": external networks
-
-**--pipeline-created**="": (default: 0)
-
-**--pipeline-event**="": (default: "manual")
-
-**--pipeline-finished**="": (default: 0)
-
-**--pipeline-number**="": (default: 0)
-
-**--pipeline-parent**="": (default: 0)
-
-**--pipeline-started**="": (default: 0)
-
-**--pipeline-status**="":
-
-**--pipeline-target**="":
-
-**--pipeline-url**="":
-
-**--prev-commit-author-avatar**="":
-
-**--prev-commit-author-email**="":
-
-**--prev-commit-author-name**="":
-
-**--prev-commit-branch**="":
-
-**--prev-commit-message**="":
-
-**--prev-commit-ref**="":
-
-**--prev-commit-refspec**="":
-
-**--prev-commit-sha**="":
-
-**--prev-pipeline-created**="": (default: 0)
-
-**--prev-pipeline-event**="":
-
-**--prev-pipeline-finished**="": (default: 0)
-
-**--prev-pipeline-number**="": (default: 0)
-
-**--prev-pipeline-started**="": (default: 0)
-
-**--prev-pipeline-status**="":
-
-**--prev-pipeline-url**="":
-
-**--privileged**="": privileged plugins (default: "plugins/docker", "plugins/gcr", "plugins/ecr", "woodpeckerci/plugin-docker-buildx", "codeberg.org/woodpecker-plugins/docker-buildx")
-
-**--repo**="": full repo name
-
-**--repo-clone-ssh-url**="":
-
-**--repo-clone-url**="":
-
-**--repo-path**="": path to local repository
-
-**--repo-private**="":
-
-**--repo-remote-id**="":
-
-**--repo-trusted**:
-
-**--repo-url**="":
-
-**--step-name**="": (default: 0)
-
-**--system-name**="": (default: "woodpecker")
-
-**--system-platform**="":
-
-**--system-url**="": (default: "https://github.com/woodpecker-ci/woodpecker")
-
-**--timeout**="": pipeline timeout (default: 1h0m0s)
-
-**--volumes**="": pipeline volumes
-
-**--workflow-name**="": (default: 0)
-
-**--workflow-number**="": (default: 0)
-
-**--workspace-base**="": (default: "/woodpecker")
-
-**--workspace-path**="": (default: "src")
-
-## info
-
-show information about the current user
-
-## registry
-
-manage registries
-
-### add
-
-adds a registry
-
-**--hostname**="": registry hostname (default: "docker.io")
-
-**--password**="": registry password
-
-**--repository, --repo**="": repository id or full-name (e.g. 134 or octocat/hello-world)
-
-**--username**="": registry username
-
-### rm
-
-remove a registry
-
-**--hostname**="": registry hostname (default: "docker.io")
-
-**--repository, --repo**="": repository id or full-name (e.g. 134 or octocat/hello-world)
-
-### update
-
-update a registry
-
-**--hostname**="": registry hostname (default: "docker.io")
-
-**--password**="": registry password
-
-**--repository, --repo**="": repository id or full-name (e.g. 134 or octocat/hello-world)
-
-**--username**="": registry username
-
-### info
-
-display registry info
-
-**--hostname**="": registry hostname (default: "docker.io")
-
-**--repository, --repo**="": repository id or full-name (e.g. 134 or octocat/hello-world)
-
-### ls
-
-list registries
-
-**--repository, --repo**="": repository id or full-name (e.g. 134 or octocat/hello-world)
-
-## secret
-
-manage secrets
-
-### add
-
-adds a secret
-
-**--event**="": secret limited to these events
-
-**--global**: global secret
-
-**--image**="": secret limited to these images
-
-**--name**="": secret name
-
-**--organization, --org**="": organization id or full-name (e.g. 123 or octocat)
-
-**--repository, --repo**="": repository id or full-name (e.g. 134 or octocat/hello-world)
-
-**--value**="": secret value
-
-### rm
-
-remove a secret
-
-**--global**: global secret
-
-**--name**="": secret name
-
-**--organization, --org**="": organization id or full-name (e.g. 123 or octocat)
-
-**--repository, --repo**="": repository id or full-name (e.g. 134 or octocat/hello-world)
-
-### update
-
-update a secret
-
-**--event**="": secret limited to these events
-
-**--global**: global secret
-
-**--image**="": secret limited to these images
-
-**--name**="": secret name
-
-**--organization, --org**="": organization id or full-name (e.g. 123 or octocat)
-
-**--repository, --repo**="": repository id or full-name (e.g. 134 or octocat/hello-world)
-
-**--value**="": secret value
-
-### info
-
-display secret info
-
-**--global**: global secret
-
-**--name**="": secret name
-
-**--organization, --org**="": organization id or full-name (e.g. 123 or octocat)
-
-**--repository, --repo**="": repository id or full-name (e.g. 134 or octocat/hello-world)
-
-### ls
-
-list secrets
-
-**--global**: global secret
-
-**--organization, --org**="": organization id or full-name (e.g. 123 or octocat)
-
-**--repository, --repo**="": repository id or full-name (e.g. 134 or octocat/hello-world)
-
-## repo
-
-manage repositories
-
-### ls
-
-list all repos
-
-**--format**="": format output (default: "\x1b[33m{{ .FullName }}\x1b[0m (id: {{ .ID }}, forgeRemoteID: {{ .ForgeRemoteID }})")
-
-**--org**="": filter by organization
-
-### info
-
-show repository details
-
-**--format**="": format output (default: "Owner: {{ .Owner }}\nRepo: {{ .Name }}\nURL: {{ .ForgeURL }}\nConfig path: {{ .Config }}\nVisibility: {{ .Visibility }}\nPrivate: {{ .IsSCMPrivate }}\nTrusted: {{ .IsTrusted }}\nGated: {{ .IsGated }}\nClone url: {{ .Clone }}\nAllow pull-requests: {{ .AllowPullRequests }}\n")
-
-### add
-
-add a repository
-
-### update
-
-update a repository
-
-**--config**="": repository configuration path (e.g. .woodpecker.yml)
-
-**--gated**: repository is gated
-
-**--pipeline-counter**="": repository starting pipeline number (default: 0)
-
-**--timeout**="": repository timeout (default: 0s)
-
-**--trusted**: repository is trusted
-
-**--unsafe**: validate updating the pipeline-counter is unsafe
-
-**--visibility**="": repository visibility
-
-### rm
-
-remove a repository
-
-### repair
-
-repair repository webhooks
-
-### chown
-
-assume ownership of a repository
-
-### sync
-
-synchronize the repository list
-
-**--format**="": format output (default: "\x1b[33m{{ .FullName }}\x1b[0m (id: {{ .ID }}, forgeRemoteID: {{ .ForgeRemoteID }})")
-
-## user
-
-manage users
-
-### ls
-
-list all users
-
-**--format**="": format output (default: "{{ .Login }}")
-
-### info
-
-show user details
-
-**--format**="": format output (default: "User: {{ .Login }}\nEmail: {{ .Email }}")
-
-### add
-
-adds a user
-
-### rm
-
-remove a user
-
-## lint
-
-lint a pipeline configuration file
-
-## log-level
-
-get the logging level of the server, or set it with [level]
-
-## cron
-
-manage cron jobs
-
-### add
-
-add a cron job
-
-**--branch**="": cron branch
-
-**--name**="": cron name
-
-**--repository, --repo**="": repository id or full-name (e.g. 134 or octocat/hello-world)
-
-**--schedule**="": cron schedule
-
-### rm
-
-remove a cron job
-
-**--id**="": cron id
-
-**--repository, --repo**="": repository id or full-name (e.g. 134 or octocat/hello-world)
-
-### update
-
-update a cron job
-
-**--branch**="": cron branch
-
-**--id**="": cron id
-
-**--name**="": cron name
-
-**--repository, --repo**="": repository id or full-name (e.g. 134 or octocat/hello-world)
-
-**--schedule**="": cron schedule
-
-### info
-
-display info about a cron job
-
-**--id**="": cron id
-
-**--repository, --repo**="": repository id or full-name (e.g. 134 or octocat/hello-world)
-
-### ls
-
-list cron jobs
-
-**--repository, --repo**="": repository id or full-name (e.g. 134 or octocat/hello-world)
-
-## setup
-
-setup the woodpecker-cli for the first time
-
-**--server-url**="": The URL of the woodpecker server
-
-**--token**="": The token to authenticate with the woodpecker server
-
-## update
-
-update the woodpecker-cli to the latest version
-
-**--force**: force update even if the latest version is already installed
diff --git a/docs/versioned_docs/version-2.4/woodpecker.png b/docs/versioned_docs/version-2.4/woodpecker.png
deleted file mode 100644
index b92f3589f..000000000
Binary files a/docs/versioned_docs/version-2.4/woodpecker.png and /dev/null differ
diff --git a/docs/versioned_docs/version-2.5/10-intro.md b/docs/versioned_docs/version-2.5/10-intro.md
index 309c6f1af..e4624e623 100644
--- a/docs/versioned_docs/version-2.5/10-intro.md
+++ b/docs/versioned_docs/version-2.5/10-intro.md
@@ -1,6 +1,6 @@
# Welcome to Woodpecker
-Woodpecker is a simple yet powerful CI/CD engine with great extensibility. It focuses on executing pipelines inside [containers](https://opencontainers.org/).
+Woodpecker is a simple, yet powerful CI/CD engine with great extensibility. It focuses on executing pipelines inside [containers](https://opencontainers.org/).
If you are already using containers in your daily workflow, you'll for sure love Woodpecker.
![woodpecker](woodpecker.png)
diff --git a/docs/versioned_docs/version-2.5/92-development/01-getting-started.md b/docs/versioned_docs/version-2.5/92-development/01-getting-started.md
index e1bb1ce0c..255b92a48 100644
--- a/docs/versioned_docs/version-2.5/92-development/01-getting-started.md
+++ b/docs/versioned_docs/version-2.5/92-development/01-getting-started.md
@@ -46,7 +46,7 @@ To apply it during local development, take a look at [`pre-commit`s documentatio
### Create a `.env` file with your development configuration
-Similar to the environment variables you can set for your production setup of Woodpecker, you can create a `.env` in the root of the Woodpecker project and add any need config to it.
+Similar to the environment variables you can set for your production setup of Woodpecker, you can create a `.env` file in the root of the Woodpecker project and add any needed config to it.
A common config for debugging would look like this:
diff --git a/docs/versioned_docs/version-2.6/10-intro.md b/docs/versioned_docs/version-2.6/10-intro.md
index 309c6f1af..e4624e623 100644
--- a/docs/versioned_docs/version-2.6/10-intro.md
+++ b/docs/versioned_docs/version-2.6/10-intro.md
@@ -1,6 +1,6 @@
# Welcome to Woodpecker
-Woodpecker is a simple yet powerful CI/CD engine with great extensibility. It focuses on executing pipelines inside [containers](https://opencontainers.org/).
+Woodpecker is a simple, yet powerful CI/CD engine with great extensibility. It focuses on executing pipelines inside [containers](https://opencontainers.org/).
If you are already using containers in your daily workflow, you'll for sure love Woodpecker.
![woodpecker](woodpecker.png)
diff --git a/docs/versioned_docs/version-2.6/92-development/01-getting-started.md b/docs/versioned_docs/version-2.6/92-development/01-getting-started.md
index e1bb1ce0c..255b92a48 100644
--- a/docs/versioned_docs/version-2.6/92-development/01-getting-started.md
+++ b/docs/versioned_docs/version-2.6/92-development/01-getting-started.md
@@ -46,7 +46,7 @@ To apply it during local development, take a look at [`pre-commit`s documentatio
### Create a `.env` file with your development configuration
-Similar to the environment variables you can set for your production setup of Woodpecker, you can create a `.env` in the root of the Woodpecker project and add any need config to it.
+Similar to the environment variables you can set for your production setup of Woodpecker, you can create a `.env` file in the root of the Woodpecker project and add any needed config to it.
A common config for debugging would look like this:
diff --git a/docs/versioned_docs/version-2.7/10-intro/index.md b/docs/versioned_docs/version-2.7/10-intro/index.md
new file mode 100644
index 000000000..7d9ced179
--- /dev/null
+++ b/docs/versioned_docs/version-2.7/10-intro/index.md
@@ -0,0 +1,26 @@
+# Welcome to Woodpecker
+
+Woodpecker is a CI/CD tool. It is designed to be lightweight, simple to use and fast. Before we dive into the details, let's have a look at some of the basics.
+
+## Have you ever heard of CI/CD or pipelines?
+
+Don't worry if you haven't. We'll guide you through the basics. CI/CD stands for Continuous Integration and Continuous Deployment. It's basically like a conveyor belt that moves your code from development to production doing all kinds of
+checks, tests and routines along the way. A typical pipeline might include the following steps:
+
+1. Running tests
+2. Building your application
+3. Deploying your application
+
+[Have a deeper look into the idea of CI/CD](https://www.redhat.com/en/topics/devops/what-is-ci-cd)
+
+## Do you know containers?
+
+If you are already using containers in your daily workflow, you'll for sure love Woodpecker. If not yet, you'll be amazed how easy it is to get started with [containers](https://opencontainers.org/).
+
+## Already have access to a Woodpecker instance?
+
+Then you might want to jump directly into it and [start creating your first pipelines](../20-usage/10-intro.md).
+
+## Want to start from scratch and deploy your own Woodpecker instance?
+
+Woodpecker is [pretty lightweight](../30-administration/00-getting-started.md#hardware-requirements) and will even run on your Raspberry Pi. You can follow the [deployment guide](../30-administration/00-getting-started.md) to set up your own Woodpecker instance.
diff --git a/docs/versioned_docs/version-2.7/20-usage/10-intro.md b/docs/versioned_docs/version-2.7/20-usage/10-intro.md
new file mode 100644
index 000000000..9c4cb3c21
--- /dev/null
+++ b/docs/versioned_docs/version-2.7/20-usage/10-intro.md
@@ -0,0 +1,109 @@
+# Your first pipeline
+
+Let's get started and create your first pipeline.
+
+## 1. Repository Activation
+
+To activate your repository in Woodpecker navigate to the repository list and `New repository`. You will see a list of repositories from your forge (GitHub, Gitlab, ...) which can be activated with a simple click.
+
+![new repository list](repo-new.png)
+
+To enable a repository in Woodpecker you must have `Admin` rights on that repository, so that Woodpecker can add something
+that is called a webhook (Woodpecker needs it to know about actions like pushes, pull requests, tags, etc.).
+
+## 2. Define first workflow
+
+After enabling a repository Woodpecker will listen for changes in your repository. When a change is detected, Woodpecker will check for a pipeline configuration. So let's create a file at `.woodpecker/my-first-workflow.yaml` inside your repository:
+
+```yaml title=".woodpecker/my-first-workflow.yaml"
+when:
+ - event: push
+ branch: main
+
+steps:
+ - name: build
+ image: debian
+ commands:
+ - echo "This is the build step"
+ - echo "binary-data-123" > executable
+ - name: a-test-step
+ image: golang:1.16
+ commands:
+ - echo "Testing ..."
+ - ./executable
+```
+
+**So what did we do here?**
+
+1. We defined your first workflow file `my-first-workflow.yaml`.
+2. This workflow will be executed when a push event happens on the `main` branch,
+ because we added a filter using the `when` section:
+
+ ```diff
+ + when:
+ + - event: push
+ + branch: main
+
+ ...
+ ```
+
+3. We defined two steps: `build` and `a-test-step`
+
+The steps are executed in the order they are defined, so `build` will be executed first and then `a-test-step`.
+
+In the `build` step we use the `debian` image and build a "binary file" called `executable`.
+
+In the `a-test-step` we use the `golang:1.16` image and run the `executable` file to test it.
+
+You can use any image from registries like the [Docker Hub](https://hub.docker.com/search?type=image) you have access to:
+
+```diff
+ steps:
+ - name: build
+- image: debian
++ image: mycompany/image-with-awscli
+ commands:
+ - aws help
+```
+
+## 3. Push the file and trigger first pipeline
+
+If you push this file to your repository now, Woodpecker will already execute your first pipeline.
+
+You can check the pipeline execution in the Woodpecker UI by navigating to the `Pipelines` section of your repository.
+
+![pipeline view](./pipeline.png)
+
+As you probably noticed, there is another step in called `clone` which is executed before your steps. This step clones your repository into a folder called `workspace` which is available throughout all steps.
+
+This for example allows the first step to build your application using your source code and as the second step will receive
+the same workspace it can use the previously built binary and test it.
+
+## 4. Use a plugin for reusable tasks
+
+Sometimes you have some tasks that you need to do in every project. For example, deploying to Kubernetes or sending a Slack message. Therefore you can use one of the [official and community plugins](/plugins) or simply [create your own](./51-plugins/20-creating-plugins.md).
+
+If you want to get a Slack notification after your pipeline has finished, you can add a Slack plugin to your pipeline:
+
+```yaml
+---
+- name: notify me on Slack
+ image: plugins/slack
+ settings:
+ channel: developers
+ username: woodpecker
+ password:
+ from_secret: slack_token
+ when:
+ status: [success, failure] # This will execute the step on success and failure
+```
+
+To configure a plugin you can use the `settings` section.
+
+Sometime you need to provide secrets to the plugin. You can do this by using the `from_secret` key. The secret must be defined in the Woodpecker UI. You can find more information about secrets [here](./40-secrets.md).
+
+Similar to the `when` section at the top of the file which is for the complete workflow, you can use the `when` section for each step to define when a step should be executed.
+
+Learn more about [plugins](./51-plugins/51-overview.md).
+
+As you now have a basic understanding of how to create a pipeline, you can dive deeper into the [workflow syntax](./20-workflow-syntax.md) and [plugins](./51-plugins/51-overview.md).
diff --git a/docs/versioned_docs/version-2.7/20-usage/100-troubleshooting.md b/docs/versioned_docs/version-2.7/20-usage/100-troubleshooting.md
new file mode 100644
index 000000000..b961530f4
--- /dev/null
+++ b/docs/versioned_docs/version-2.7/20-usage/100-troubleshooting.md
@@ -0,0 +1,37 @@
+# Troubleshooting
+
+## How to debug clone issues
+
+(And what to do with an error message like `fatal: could not read Username for 'https://': No such device or address`)
+
+This error can have multiple causes. If you use internal repositories you might have to enable `WOODPECKER_AUTHENTICATE_PUBLIC_REPOS`:
+
+```ini
+WOODPECKER_AUTHENTICATE_PUBLIC_REPOS=true
+```
+
+If that does not work, try to make sure the container can reach your git server. In order to do that disable git checkout and make the container "hang":
+
+```yaml
+skip_clone: true
+
+steps:
+ build:
+ image: debian:stable-backports
+ commands:
+ - apt update
+ - apt install -y inetutils-ping wget
+ - ping -c 4 git.example.com
+ - wget git.example.com
+ - sleep 9999999
+```
+
+Get the container id using `docker ps` and copy the id from the first column. Enter the container with: `docker exec -it 1234asdf bash` (replace `1234asdf` with the docker id). Then try to clone the git repository with the commands from the failing pipeline:
+
+```bash
+git init
+git remote add origin https://git.example.com/username/repo.git
+git fetch --no-tags origin +refs/heads/branch:
+```
+
+(replace the url AND the branch with the correct values, use your username and password as log in values)
diff --git a/docs/versioned_docs/version-2.4/20-usage/15-terminiology/architecture.excalidraw b/docs/versioned_docs/version-2.7/20-usage/15-terminology/architecture.excalidraw
similarity index 100%
rename from docs/versioned_docs/version-2.4/20-usage/15-terminiology/architecture.excalidraw
rename to docs/versioned_docs/version-2.7/20-usage/15-terminology/architecture.excalidraw
diff --git a/docs/versioned_docs/version-2.4/20-usage/15-terminiology/architecture.svg b/docs/versioned_docs/version-2.7/20-usage/15-terminology/architecture.svg
similarity index 100%
rename from docs/versioned_docs/version-2.4/20-usage/15-terminiology/architecture.svg
rename to docs/versioned_docs/version-2.7/20-usage/15-terminology/architecture.svg
diff --git a/docs/versioned_docs/version-2.4/20-usage/15-terminiology/index.md b/docs/versioned_docs/version-2.7/20-usage/15-terminology/index.md
similarity index 94%
rename from docs/versioned_docs/version-2.4/20-usage/15-terminiology/index.md
rename to docs/versioned_docs/version-2.7/20-usage/15-terminology/index.md
index 3d8f12772..f05f18207 100644
--- a/docs/versioned_docs/version-2.4/20-usage/15-terminiology/index.md
+++ b/docs/versioned_docs/version-2.7/20-usage/15-terminology/index.md
@@ -1,13 +1,5 @@
# Terminology
-## Woodpecker architecture
-
-![Woodpecker architecture](architecture.svg)
-
-## Pipeline, workflow & step
-
-![Relation between pipelines, workflows and steps](pipeline-workflow-step.svg)
-
## Glossary
- **Woodpecker CI**: The project name around Woodpecker.
@@ -31,7 +23,15 @@
- **YAML File**: A file format used to define and configure [workflows][Workflow].
- **Dependency**: [Workflows][Workflow] can depend on each other, and if possible, they are executed in parallel.
- **Status**: Status refers to the outcome of a step or [workflow][Workflow] after it has been executed, determined by the internal command exit code. At the end of a [workflow][Workflow], its status is sent to the [forge][Forge].
-- **Service extension**: Some parts of woodpecker internal services like secrets storage or config fetcher can be replaced through service extensions.
+- **Service extension**: Some parts of Woodpecker internal services like secrets storage or config fetcher can be replaced through service extensions.
+
+## Woodpecker architecture
+
+![Woodpecker architecture](architecture.svg)
+
+## Pipeline, workflow & step
+
+![Relation between pipelines, workflows and steps](pipeline-workflow-step.svg)
## Pipeline events
@@ -50,13 +50,14 @@ Sometimes there are multiple terms that can be used to describe something. This
- Environment variables `*_LINK` should be called `*_URL`. In the code use `URL()` instead of `Link()`
- Use the term **pipelines** instead of the previous **builds**
- Use the term **steps** instead of the previous **jobs**
+- Use the prefix `WOODPECKER_EXPERT_` for advanced environment variables that are normally not required to be set by users
[Pipeline]: ../20-workflow-syntax.md
[Workflow]: ../25-workflows.md
-[Forge]: ../../30-administration/11-forges/10-overview.md
-[Plugin]: ../51-plugins/10-overview.md
+[Forge]: ../../30-administration/11-forges/11-overview.md
+[Plugin]: ../51-plugins/51-overview.md
[Workspace]: ../20-workflow-syntax.md#workspace
[Matrix]: ../30-matrix-workflows.md
[Docker]: ../../30-administration/22-backends/10-docker.md
diff --git a/docs/versioned_docs/version-2.4/20-usage/15-terminiology/pipeline-workflow-step.excalidraw b/docs/versioned_docs/version-2.7/20-usage/15-terminology/pipeline-workflow-step.excalidraw
similarity index 100%
rename from docs/versioned_docs/version-2.4/20-usage/15-terminiology/pipeline-workflow-step.excalidraw
rename to docs/versioned_docs/version-2.7/20-usage/15-terminology/pipeline-workflow-step.excalidraw
diff --git a/docs/versioned_docs/version-2.4/20-usage/15-terminiology/pipeline-workflow-step.svg b/docs/versioned_docs/version-2.7/20-usage/15-terminology/pipeline-workflow-step.svg
similarity index 100%
rename from docs/versioned_docs/version-2.4/20-usage/15-terminiology/pipeline-workflow-step.svg
rename to docs/versioned_docs/version-2.7/20-usage/15-terminology/pipeline-workflow-step.svg
diff --git a/docs/versioned_docs/version-2.4/20-usage/20-workflow-syntax.md b/docs/versioned_docs/version-2.7/20-usage/20-workflow-syntax.md
similarity index 90%
rename from docs/versioned_docs/version-2.4/20-usage/20-workflow-syntax.md
rename to docs/versioned_docs/version-2.7/20-usage/20-workflow-syntax.md
index 84f2b54f7..956401c7e 100644
--- a/docs/versioned_docs/version-2.4/20-usage/20-workflow-syntax.md
+++ b/docs/versioned_docs/version-2.7/20-usage/20-workflow-syntax.md
@@ -1,6 +1,15 @@
# Workflow syntax
-The workflow section defines a list of steps to build, test and deploy your code. Steps are executed serially, in the order in which they are defined. If a step returns a non-zero exit code, the workflow and therefore all other workflows and the pipeline immediately aborts and returns a failure status.
+The Workflow section defines a list of steps to build, test and deploy your code. The steps are executed serially in the order in which they are defined. If a step returns a non-zero exit code, the workflow and therefore the entire pipeline terminates immediately and returns an error status.
+
+:::note
+An exception to this rule are steps with a [`status: [failure]`](#status) condition, which ensures that they are executed in the case of a failed run.
+:::
+
+:::note
+We support most of YAML 1.2, but preserve some behavior from 1.1 for backward compatibility.
+Read more at: [https://github.com/go-yaml/yaml](https://github.com/go-yaml/yaml/tree/v3)
+:::
Example steps:
@@ -161,6 +170,9 @@ Only build steps can define commands. You cannot use commands with plugins or se
Allows you to specify the entrypoint for containers. Note that this must be a list of the command and its arguments (e.g. `["/bin/sh", "-c"]`).
+If you define [`commands`](#commands), the default entrypoint will be `["/bin/sh", "-c", "echo $CI_SCRIPT | base64 -d | /bin/sh -e"]`.
+You can also use a custom shell with `CI_SCRIPT` (Base64-encoded) if you set `commands`.
+
### `environment`
Woodpecker provides the ability to pass environment variables to individual steps.
@@ -189,7 +201,8 @@ Some of the steps may be allowed to fail without causing the whole workflow and
### `when` - Conditional Execution
-Woodpecker supports defining a list of conditions for a step by using a `when` block. If at least one of the conditions in the `when` block evaluate to true the step is executed, otherwise it is skipped. A condition can be a check like:
+Woodpecker supports defining a list of conditions for a step by using a `when` block. If at least one of the conditions in the `when` block evaluate to true the step is executed, otherwise it is skipped. A condition is evaluated to true if _all_ subconditions are true.
+A condition can be a check like:
```diff
steps:
@@ -204,6 +217,11 @@ Woodpecker supports defining a list of conditions for a step by using a `when` b
+ branch: main
```
+The `slack` step is executed if one of these conditions is met:
+
+1. The pipeline is executed from a pull request in the repo `test/test`
+2. The pipeline is executed from a push to `main`
+
#### `repo`
Example conditional execution by repository:
@@ -353,20 +371,6 @@ when:
- platform: [linux/*, windows/amd64]
```
-
-
-#### `environment`
-
-
-
-Execute a step for deployment events matching the target deployment environment:
-
-```yaml
-when:
- - environment: production
- - event: deployment
-```
-
#### `matrix`
Execute a step for a single matrix permutation:
@@ -403,16 +407,19 @@ when:
You can use [glob patterns](https://github.com/bmatcuk/doublestar#patterns) to match the changed files and specify if the step should run if a file matching that pattern has been changed `include` or if some files have **not** been changed `exclude`.
+For pipelines without file changes (empty commits or on events without file changes like `tag`), you can use `on_empty` to set whether this condition should be **true** _(default)_ or **false** in these cases.
+
```yaml
when:
- path:
include: ['.woodpecker/*.yaml', '*.ini']
exclude: ['*.md', 'docs/**']
ignore_message: '[ALL]'
+ on_empty: true
```
:::info
-Passing a defined ignore-message like `[ALL]` inside the commit message will ignore all path conditions.
+Passing a defined ignore-message like `[ALL]` inside the commit message will ignore all path conditions and the `on_empty` setting.
:::
#### `evaluate`
@@ -516,7 +523,9 @@ For more details check the [services docs](./60-services.md).
## `workspace`
-The workspace defines the shared volume and working directory shared by all workflow steps. The default workspace matches the pattern `/woodpecker/src/github.com/octocat/hello-world`, based on your repository URL.
+The workspace defines the shared volume and working directory shared by all workflow steps.
+The default workspace base is `/woodpecker` and the path is extended with the repository URL (`src/{url-without-schema}`).
+So an example would be `/woodpecker/src/github.com/octocat/hello-world`.
The workspace can be customized using the workspace block in the YAML file:
@@ -533,6 +542,10 @@ The workspace can be customized using the workspace block in the YAML file:
- go test
```
+:::note
+Plugins will always have the workspace base at `/woodpecker`
+:::
+
The base attribute defines a shared base volume available to all steps. This ensures your source code, dependencies and compiled binaries are persisted and shared between steps.
```diff
@@ -640,7 +653,7 @@ You can manually configure the clone step in your workflow for customization:
```diff
+clone:
-+ - name: git
++ git:
+ image: woodpeckerci/plugin-git
steps:
@@ -716,7 +729,7 @@ skip_clone: true
## `when` - Global workflow conditions
-Woodpecker gives the ability to skip whole workflows (not just steps #when---conditional-execution-1) based on certain conditions by a `when` block. If all conditions in the `when` block evaluate to true the workflow is executed, otherwise it is skipped, but treated as successful and other workflows depending on it will still continue.
+Woodpecker gives the ability to skip whole workflows ([not just steps](#when---conditional-execution)) based on certain conditions by a `when` block. If all conditions in the `when` block evaluate to true the workflow is executed, otherwise it is skipped, but treated as successful and other workflows depending on it will still continue.
For more information about the specific filters, take a look at the [step-specific `when` filters](#when---conditional-execution).
@@ -752,7 +765,7 @@ Workflows that should run even on failure should set the `runs_on` tag. See [her
Woodpecker gives the ability to configure privileged mode in the YAML. You can use this parameter to launch containers with escalated capabilities.
:::info
-Privileged mode is only available to trusted repositories and for security reasons should only be used in private environments. See [project settings](./71-project-settings.md#trusted) to enable trusted mode.
+Privileged mode is only available to trusted repositories and for security reasons should only be used in private environments. See [project settings](./75-project-settings.md#trusted) to enable trusted mode.
:::
```diff
diff --git a/docs/versioned_docs/version-2.4/20-usage/25-workflows.md b/docs/versioned_docs/version-2.7/20-usage/25-workflows.md
similarity index 96%
rename from docs/versioned_docs/version-2.4/20-usage/25-workflows.md
rename to docs/versioned_docs/version-2.7/20-usage/25-workflows.md
index 1a3f40fc8..5adc39f85 100644
--- a/docs/versioned_docs/version-2.4/20-usage/25-workflows.md
+++ b/docs/versioned_docs/version-2.7/20-usage/25-workflows.md
@@ -6,7 +6,7 @@ In case there is a single configuration in `.woodpecker.yaml` Woodpecker will cr
By placing the configurations in a folder which is by default named `.woodpecker/` Woodpecker will create a pipeline with multiple workflows each named by the file they are defined in. Only `.yml` and `.yaml` files will be used and files in any subfolders like `.woodpecker/sub-folder/test.yaml` will be ignored.
-You can also set some custom path like `.my-ci/pipelines/` instead of `.woodpecker/` in the [project settings](./71-project-settings.md).
+You can also set some custom path like `.my-ci/pipelines/` instead of `.woodpecker/` in the [project settings](./75-project-settings.md).
## Benefits of using workflows
@@ -18,7 +18,7 @@ You can also set some custom path like `.my-ci/pipelines/` instead of `.woodpeck
:::warning
Please note that files are only shared between steps of the same workflow (see [File changes are incremental](./20-workflow-syntax.md#file-changes-are-incremental)). That means you cannot access artifacts e.g. from the `build` workflow in the `deploy` workflow.
-If you still need to pass artifacts between the workflows you need use some storage [plugin](./51-plugins/10-overview.md) (e.g. one which stores files in an Amazon S3 bucket).
+If you still need to pass artifacts between the workflows you need use some storage [plugin](./51-plugins/51-overview.md) (e.g. one which stores files in an Amazon S3 bucket).
:::
```bash
diff --git a/docs/versioned_docs/version-2.4/20-usage/30-matrix-workflows.md b/docs/versioned_docs/version-2.7/20-usage/30-matrix-workflows.md
similarity index 100%
rename from docs/versioned_docs/version-2.4/20-usage/30-matrix-workflows.md
rename to docs/versioned_docs/version-2.7/20-usage/30-matrix-workflows.md
diff --git a/docs/versioned_docs/version-2.4/20-usage/40-secrets.md b/docs/versioned_docs/version-2.7/20-usage/40-secrets.md
similarity index 100%
rename from docs/versioned_docs/version-2.4/20-usage/40-secrets.md
rename to docs/versioned_docs/version-2.7/20-usage/40-secrets.md
diff --git a/docs/versioned_docs/version-2.4/20-usage/41-registries.md b/docs/versioned_docs/version-2.7/20-usage/41-registries.md
similarity index 100%
rename from docs/versioned_docs/version-2.4/20-usage/41-registries.md
rename to docs/versioned_docs/version-2.7/20-usage/41-registries.md
diff --git a/docs/versioned_docs/version-2.4/20-usage/45-cron.md b/docs/versioned_docs/version-2.7/20-usage/45-cron.md
similarity index 88%
rename from docs/versioned_docs/version-2.4/20-usage/45-cron.md
rename to docs/versioned_docs/version-2.7/20-usage/45-cron.md
index 994e022bc..95ee8202e 100644
--- a/docs/versioned_docs/version-2.4/20-usage/45-cron.md
+++ b/docs/versioned_docs/version-2.7/20-usage/45-cron.md
@@ -19,11 +19,11 @@ To configure cron jobs you need at least push access to the repository.
+ cron: "name of the cron job" # if you only want to execute this step by a specific cron job
```
-1. Create a new cron job in the repository settings:
+2. Create a new cron job in the repository settings:
![cron settings](./cron-settings.png)
- The supported schedule syntax can be found at . If you need general understanding of the cron syntax is a good place to start and experiment.
+ The supported schedule syntax can be found at . If you need general understanding of the cron syntax is a good place to start and experiment.
Examples: `@every 5m`, `@daily`, `0 30 * * * *` ...
diff --git a/docs/versioned_docs/version-2.4/20-usage/50-environment.md b/docs/versioned_docs/version-2.7/20-usage/50-environment.md
similarity index 97%
rename from docs/versioned_docs/version-2.4/20-usage/50-environment.md
rename to docs/versioned_docs/version-2.7/20-usage/50-environment.md
index ce05812e4..299bb8f53 100644
--- a/docs/versioned_docs/version-2.4/20-usage/50-environment.md
+++ b/docs/versioned_docs/version-2.7/20-usage/50-environment.md
@@ -81,10 +81,11 @@ This is the reference list of all environment variables available to your pipeli
| | **Current pipeline** |
| `CI_PIPELINE_NUMBER` | pipeline number |
| `CI_PIPELINE_PARENT` | number of parent pipeline |
-| `CI_PIPELINE_EVENT` | pipeline event (see [pipeline events](../20-usage/15-terminiology/index.md#pipeline-events)) |
+| `CI_PIPELINE_EVENT` | pipeline event (see [pipeline events](../20-usage/15-terminology/index.md#pipeline-events)) |
| `CI_PIPELINE_URL` | link to the web UI for the pipeline |
| `CI_PIPELINE_FORGE_URL` | link to the forge's web UI for the commit(s) or tag that triggered the pipeline |
| `CI_PIPELINE_DEPLOY_TARGET` | pipeline deploy target for `deployment` events (i.e. production) |
+| `CI_PIPELINE_DEPLOY_TASK` | pipeline deploy task for `deployment` events (i.e. migration) |
| `CI_PIPELINE_STATUS` | pipeline status (success, failure) |
| `CI_PIPELINE_CREATED` | pipeline created UNIX timestamp |
| `CI_PIPELINE_STARTED` | pipeline started UNIX timestamp |
@@ -114,10 +115,11 @@ This is the reference list of all environment variables available to your pipeli
| | **Previous pipeline** |
| `CI_PREV_PIPELINE_NUMBER` | previous pipeline number |
| `CI_PREV_PIPELINE_PARENT` | previous pipeline number of parent pipeline |
-| `CI_PREV_PIPELINE_EVENT` | previous pipeline event (see [pipeline events](../20-usage/15-terminiology/index.md#pipeline-events)) |
+| `CI_PREV_PIPELINE_EVENT` | previous pipeline event (see [pipeline events](../20-usage/15-terminology/index.md#pipeline-events)) |
| `CI_PREV_PIPELINE_URL` | previous pipeline link in CI |
| `CI_PREV_PIPELINE_FORGE_URL` | previous pipeline link to event in forge |
| `CI_PREV_PIPELINE_DEPLOY_TARGET` | previous pipeline deploy target for `deployment` events (ie production) |
+| `CI_PREV_PIPELINE_DEPLOY_TASK` | previous pipeline deploy task for `deployment` events (ie migration) |
| `CI_PREV_PIPELINE_STATUS` | previous pipeline status (success, failure) |
| `CI_PREV_PIPELINE_CREATED` | previous pipeline created UNIX timestamp |
| `CI_PREV_PIPELINE_STARTED` | previous pipeline started UNIX timestamp |
diff --git a/docs/versioned_docs/version-2.4/20-usage/51-plugins/20-creating-plugins.md b/docs/versioned_docs/version-2.7/20-usage/51-plugins/20-creating-plugins.md
similarity index 83%
rename from docs/versioned_docs/version-2.4/20-usage/51-plugins/20-creating-plugins.md
rename to docs/versioned_docs/version-2.7/20-usage/51-plugins/20-creating-plugins.md
index cd74ea455..8a0ea5920 100644
--- a/docs/versioned_docs/version-2.4/20-usage/51-plugins/20-creating-plugins.md
+++ b/docs/versioned_docs/version-2.7/20-usage/51-plugins/20-creating-plugins.md
@@ -48,6 +48,23 @@ Secrets should be passed as settings too. Therefore, users should use [`from_sec
For Go, we provide a plugin library you can use to get easy access to internal env vars and your settings. See .
+## Metadata
+
+In your documentation, you can use a Markdown header to define metadata for your plugin. This data is used by [our plugin index](/plugins).
+
+Supported metadata:
+
+- `name`: The plugin's full name
+- `icon`: URL to your plugin's icon
+- `description`: A short description of what it's doing
+- `author`: Your name
+- `tags`: List of keywords (e.g. `[git, clone]` for the clone plugin)
+- `containerImage`: name of the container image
+- `containerImageUrl`: link to the container image
+- `url`: homepage or repository of your plugin
+
+If you want your plugin to be listed in the index, you should add as many fields as possible, but only `name` is required.
+
## Example plugin
This provides a brief tutorial for creating a Woodpecker webhook plugin, using simple shell scripting, to make HTTP requests during the build pipeline.
@@ -118,5 +135,5 @@ docker run --rm \
These should also be built for different OS/architectures.
- Use [built-in env vars](../50-environment.md#built-in-environment-variables) where possible.
- Do not use any configuration except settings (and internal env vars). This means: Don't require using [`environment`](../50-environment.md) and don't require specific secret names.
-- Add a `docs.md` file, listing all your settings and plugin metadata ([example](https://codeberg.org/woodpecker-plugins/plugin-docker-buildx/src/branch/main/docs.md)).
-- Add your plugin to the [plugin index](/plugins) using your `docs.md` ([the example above in the index](https://woodpecker-ci.org/plugins/Docker%20Buildx)).
+- Add a `docs.md` file, listing all your settings and plugin metadata ([example](https://github.com/woodpecker-ci/plugin-git/blob/main/docs.md)).
+- Add your plugin to the [plugin index](/plugins) using your `docs.md` ([the example above in the index](https://woodpecker-ci.org/plugins/Git%20Clone)).
diff --git a/docs/versioned_docs/version-2.4/20-usage/51-plugins/10-overview.md b/docs/versioned_docs/version-2.7/20-usage/51-plugins/51-overview.md
similarity index 58%
rename from docs/versioned_docs/version-2.4/20-usage/51-plugins/10-overview.md
rename to docs/versioned_docs/version-2.7/20-usage/51-plugins/51-overview.md
index ab8db3df3..0e5905036 100644
--- a/docs/versioned_docs/version-2.4/20-usage/51-plugins/10-overview.md
+++ b/docs/versioned_docs/version-2.7/20-usage/51-plugins/51-overview.md
@@ -4,6 +4,24 @@ Plugins are pipeline steps that perform pre-defined tasks and are configured as
They are automatically pulled from the default container registry the agent's have configured.
+```dockerfile title="Dockerfile"
+FROM laszlocloud/kubectl
+COPY deploy /usr/local/deploy
+ENTRYPOINT ["/usr/local/deploy"]
+```
+
+```bash title="deploy"
+kubectl apply -f $PLUGIN_TEMPLATE
+```
+
+```yaml title=".woodpecker.yaml"
+steps:
+ - name: deploy-to-k8s
+ image: laszlocloud/my-k8s-plugin
+ settings:
+ template: config/k8s/service.yaml
+```
+
Example pipeline using the Docker and Slack plugins:
```yaml
@@ -29,6 +47,11 @@ steps:
## Plugin Isolation
Plugins are just pipeline steps. They share the build workspace, mounted as a volume, and therefore have access to your source tree.
+While normal steps are all about arbitrary code execution, plugins should only allow the functions intended by the plugin author.
+
+So there are a few limitations, like the workspace base is always mounted at `/woodpecker`, but the working directory is dynamically adjusted accordingly. So as user of a plugin you should not have to care about this.
+
+Also instead of using environment variables the plugin should only care about one prefixed with `PLUGIN_` witch are the internal representation of the **settings** ([read more](./20-creating-plugins.md)).
## Finding Plugins
diff --git a/docs/versioned_docs/version-2.4/20-usage/51-plugins/_category_.yaml b/docs/versioned_docs/version-2.7/20-usage/51-plugins/_category_.yaml
similarity index 100%
rename from docs/versioned_docs/version-2.4/20-usage/51-plugins/_category_.yaml
rename to docs/versioned_docs/version-2.7/20-usage/51-plugins/_category_.yaml
diff --git a/docs/versioned_docs/version-2.4/20-usage/60-services.md b/docs/versioned_docs/version-2.7/20-usage/60-services.md
similarity index 100%
rename from docs/versioned_docs/version-2.4/20-usage/60-services.md
rename to docs/versioned_docs/version-2.7/20-usage/60-services.md
diff --git a/docs/versioned_docs/version-2.4/20-usage/70-volumes.md b/docs/versioned_docs/version-2.7/20-usage/70-volumes.md
similarity index 93%
rename from docs/versioned_docs/version-2.4/20-usage/70-volumes.md
rename to docs/versioned_docs/version-2.7/20-usage/70-volumes.md
index 3397e879c..6897053fb 100644
--- a/docs/versioned_docs/version-2.4/20-usage/70-volumes.md
+++ b/docs/versioned_docs/version-2.7/20-usage/70-volumes.md
@@ -3,7 +3,7 @@
Woodpecker gives the ability to define Docker volumes in the YAML. You can use this parameter to mount files or folders on the host machine into your containers.
:::note
-Volumes are only available to trusted repositories and for security reasons should only be used in private environments. See [project settings](./71-project-settings.md#trusted) to enable trusted mode.
+Volumes are only available to trusted repositories and for security reasons should only be used in private environments. See [project settings](./75-project-settings.md#trusted) to enable trusted mode.
:::
```diff
diff --git a/docs/versioned_docs/version-2.7/20-usage/72-linter.md b/docs/versioned_docs/version-2.7/20-usage/72-linter.md
new file mode 100644
index 000000000..4fae3d643
--- /dev/null
+++ b/docs/versioned_docs/version-2.7/20-usage/72-linter.md
@@ -0,0 +1,62 @@
+# Linter
+
+Woodpecker automatically lints your workflow files for errors, deprecations and bad habits. Errors and warnings are shown in the UI for any pipelines.
+
+![errors and warnings in UI](./linter-warnings-errors.png)
+
+## Running the linter from CLI
+
+You can run the linter also manually from the CLI:
+
+```shell
+woodpecker-cli lint
+```
+
+## Bad habit warnings
+
+Woodpecker warns you if your configuration contains some bad habits.
+
+### Event filter for all steps
+
+All your items in `when` blocks should have an `event` filter, so no step runs on all events. This is recommended because if new events are added, your steps probably shouldn't run on those as well.
+
+Examples of an **incorrect** config for this rule:
+
+```yaml
+when:
+ - branch: main
+ - event: tag
+```
+
+This will trigger the warning because the first item (`branch: main`) does not filter with an event.
+
+```yaml
+steps:
+ - name: test
+ when:
+ branch: main
+
+ - name: deploy
+ when:
+ event: tag
+```
+
+Examples of a **correct** config for this rule:
+
+```yaml
+when:
+ - branch: main
+ event: push
+ - event: tag
+```
+
+```yaml
+steps:
+ - name: test
+ when:
+ event: [tag, push]
+
+ - name: deploy
+ when:
+ - event: tag
+```
diff --git a/docs/versioned_docs/version-2.4/20-usage/71-project-settings.md b/docs/versioned_docs/version-2.7/20-usage/75-project-settings.md
similarity index 89%
rename from docs/versioned_docs/version-2.4/20-usage/71-project-settings.md
rename to docs/versioned_docs/version-2.7/20-usage/75-project-settings.md
index 573e85eee..24bdbe605 100644
--- a/docs/versioned_docs/version-2.4/20-usage/71-project-settings.md
+++ b/docs/versioned_docs/version-2.7/20-usage/75-project-settings.md
@@ -16,6 +16,15 @@ Your Version-Control-System will notify Woodpecker about events via webhooks. If
Enables handling webhook's pull request event. If disabled, then pipeline won't run for pull requests.
+## Allow deployments
+
+Enables a pipeline to be started with the `deploy` event from a successful pipeline.
+
+:::danger
+Only activate this option if you trust all users who have push access to your repository.
+Otherwise, these users will be able to steal secrets that are only available for `deploy` events.
+:::
+
## Protected
Every pipeline initiated by an webhook event needs to be approved by a project members with push permissions before being executed.
diff --git a/docs/versioned_docs/version-2.4/20-usage/80-badges.md b/docs/versioned_docs/version-2.7/20-usage/80-badges.md
similarity index 100%
rename from docs/versioned_docs/version-2.4/20-usage/80-badges.md
rename to docs/versioned_docs/version-2.7/20-usage/80-badges.md
diff --git a/docs/versioned_docs/version-2.4/20-usage/90-advanced-usage.md b/docs/versioned_docs/version-2.7/20-usage/90-advanced-usage.md
similarity index 100%
rename from docs/versioned_docs/version-2.4/20-usage/90-advanced-usage.md
rename to docs/versioned_docs/version-2.7/20-usage/90-advanced-usage.md
diff --git a/docs/versioned_docs/version-2.4/20-usage/_category_.yaml b/docs/versioned_docs/version-2.7/20-usage/_category_.yaml
similarity index 100%
rename from docs/versioned_docs/version-2.4/20-usage/_category_.yaml
rename to docs/versioned_docs/version-2.7/20-usage/_category_.yaml
diff --git a/docs/versioned_docs/version-2.4/20-usage/cron-settings.png b/docs/versioned_docs/version-2.7/20-usage/cron-settings.png
similarity index 100%
rename from docs/versioned_docs/version-2.4/20-usage/cron-settings.png
rename to docs/versioned_docs/version-2.7/20-usage/cron-settings.png
diff --git a/docs/versioned_docs/version-2.7/20-usage/linter-warnings-errors.png b/docs/versioned_docs/version-2.7/20-usage/linter-warnings-errors.png
new file mode 100644
index 000000000..663e49704
Binary files /dev/null and b/docs/versioned_docs/version-2.7/20-usage/linter-warnings-errors.png differ
diff --git a/docs/versioned_docs/version-2.7/20-usage/pipeline.png b/docs/versioned_docs/version-2.7/20-usage/pipeline.png
new file mode 100644
index 000000000..dd4063c9a
Binary files /dev/null and b/docs/versioned_docs/version-2.7/20-usage/pipeline.png differ
diff --git a/docs/versioned_docs/version-2.4/20-usage/project-settings.png b/docs/versioned_docs/version-2.7/20-usage/project-settings.png
similarity index 100%
rename from docs/versioned_docs/version-2.4/20-usage/project-settings.png
rename to docs/versioned_docs/version-2.7/20-usage/project-settings.png
diff --git a/docs/versioned_docs/version-2.7/20-usage/repo-new.png b/docs/versioned_docs/version-2.7/20-usage/repo-new.png
new file mode 100644
index 000000000..e6136bc12
Binary files /dev/null and b/docs/versioned_docs/version-2.7/20-usage/repo-new.png differ
diff --git a/docs/versioned_docs/version-2.7/30-administration/00-getting-started.md b/docs/versioned_docs/version-2.7/30-administration/00-getting-started.md
new file mode 100644
index 000000000..8bb1b0a71
--- /dev/null
+++ b/docs/versioned_docs/version-2.7/30-administration/00-getting-started.md
@@ -0,0 +1,59 @@
+# Getting started
+
+A Woodpecker deployment consists of two parts:
+
+- A server which is the heart of Woodpecker and ships the web interface.
+- Next to one server, you can deploy any number of agents which will run the pipelines.
+
+Each agent is able to process one [workflow](../20-usage/15-terminology/index.md) by default. If you have 4 agents installed and connected to the Woodpecker server, your system will process four workflows (not pipelines) in parallel.
+
+:::tip
+You can add more agents to increase the number of parallel workflows or set the agent's `WOODPECKER_MAX_WORKFLOWS=1` environment variable to increase the number of parallel workflows per agent.
+:::
+
+## Which version of Woodpecker should I use?
+
+Woodpecker is having two different kinds of releases: **stable** and **next**.
+
+Find more information about the different versions [here](/versions).
+
+## Hardware Requirements
+
+Below are minimal resources requirements for Woodpecker components itself:
+
+| Component | Memory | CPU |
+| --------- | ------ | --- |
+| Server | 200 MB | 1 |
+| Agent | 32 MB | 1 |
+
+Note, that those values do not include the operating system or workload (pipelines execution) resource consumption.
+
+In addition you need at least some kind of database which requires additional resources depending on the selected database system.
+
+## Installation
+
+You can install Woodpecker on multiple ways. If you are not sure which one to choose, we recommend using the [docker-compose](./05-deployment-methods/10-docker-compose.md) method for the beginning:
+
+- Using [docker-compose](./05-deployment-methods/10-docker-compose.md) with the official [container images](./05-deployment-methods/10-docker-compose.md#docker-images)
+- Using [Kubernetes](./05-deployment-methods/20-kubernetes.md) via the Woodpecker Helm chart
+- Using binaries, DEBs or RPMs you can download from [latest release](https://github.com/woodpecker-ci/woodpecker/releases/latest)
+- Or using a [third-party installation method](./05-deployment-methods/30-third-party.md)
+
+## Database
+
+By default Woodpecker uses a SQLite database which requires zero installation or configuration. See the [database settings](./10-database.md) page if you want to use a different database system like MySQL or PostgreSQL.
+
+## Forge
+
+What would be a CI/CD system without any code? By connecting Woodpecker to your [forge](../20-usage/15-terminology/index.md) like GitHub or Gitea you can start running pipelines on events like pushes or pull requests. Woodpecker will also use your forge for authentication and to report back the status of your pipelines. See the [forge settings](./11-forges/11-overview.md) to connect it to Woodpecker.
+
+## Configuration
+
+Check the [server configuration](./10-server-config.md) and [agent configuration](./15-agent-config.md) pages to see if you need to adjust any additional parts and after that you should be ready to start with [your first pipeline](../20-usage/10-intro.md).
+
+## Agent
+
+The agent is the worker which executes the [workflows](../20-usage/15-terminology/index.md).
+Woodpecker agents can execute work using a [backend](../20-usage/15-terminology/index.md) like [docker](./22-backends/10-docker.md) or [kubernetes](./22-backends/40-kubernetes.md).
+By default if you choose to deploy an agent using [docker-compose](./05-deployment-methods/10-docker-compose.md) the agent simply use docker for the backend as well.
+So nothing to worry about here. If you still prefer to adjust the agent to your needs, check the [agent configuration](./15-agent-config.md) page.
diff --git a/docs/versioned_docs/version-2.4/30-administration/00-deployment/10-docker-compose.md b/docs/versioned_docs/version-2.7/30-administration/05-deployment-methods/10-docker-compose.md
similarity index 94%
rename from docs/versioned_docs/version-2.4/30-administration/00-deployment/10-docker-compose.md
rename to docs/versioned_docs/version-2.7/30-administration/05-deployment-methods/10-docker-compose.md
index a9c2bb6ab..5af7e85fc 100644
--- a/docs/versioned_docs/version-2.4/30-administration/00-deployment/10-docker-compose.md
+++ b/docs/versioned_docs/version-2.7/30-administration/05-deployment-methods/10-docker-compose.md
@@ -67,7 +67,7 @@ They can be configured with `*_ADDR` variables:
+ - WOODPECKER_SERVER_ADDR=${WOODPECKER_HTTP_ADDR}
```
-Reverse proxying can also be [configured for gRPC](../70-proxy.md#caddy). If the agents are connecting over the internet, it should also be SSL encrypted. The agent then needs to be configured to be secure:
+Reverse proxying can also be [configured for gRPC](../40-advanced/10-proxy.md#caddy). If the agents are connecting over the internet, it should also be SSL encrypted. The agent then needs to be configured to be secure:
```diff title="docker-compose.yaml"
version: '3'
diff --git a/docs/docs/30-administration/00-deployment/20-kubernetes.md b/docs/versioned_docs/version-2.7/30-administration/05-deployment-methods/20-kubernetes.md
similarity index 100%
rename from docs/docs/30-administration/00-deployment/20-kubernetes.md
rename to docs/versioned_docs/version-2.7/30-administration/05-deployment-methods/20-kubernetes.md
diff --git a/docs/versioned_docs/version-2.7/30-administration/05-deployment-methods/30-third-party.md b/docs/versioned_docs/version-2.7/30-administration/05-deployment-methods/30-third-party.md
new file mode 100644
index 000000000..acad9c0fd
--- /dev/null
+++ b/docs/versioned_docs/version-2.7/30-administration/05-deployment-methods/30-third-party.md
@@ -0,0 +1,12 @@
+# Third-party installation methods
+
+:::info
+These installation methods are not officially supported. If you experience issues with them, please open issues in the specific repositories.
+:::
+
+- [Using NixOS](./40-nixos.md) via the [NixOS module](https://search.nixos.org/options?channel=unstable&size=200&sort=relevance&query=woodpecker)
+- [On Alpine Edge](https://pkgs.alpinelinux.org/packages?name=woodpecker&branch=edge&repo=&arch=&maintainer=)
+- [On Arch Linux](https://archlinux.org/packages/?q=woodpecker)
+- [On openSUSE](https://software.opensuse.org/package/woodpecker)
+- [Using YunoHost](https://apps.yunohost.org/app/woodpecker)
+- [On Cloudron](https://www.cloudron.io/store/org.woodpecker_ci.cloudronapp.html)
diff --git a/docs/docs/30-administration/00-deployment/30-nixos.md b/docs/versioned_docs/version-2.7/30-administration/05-deployment-methods/40-nixos.md
similarity index 100%
rename from docs/docs/30-administration/00-deployment/30-nixos.md
rename to docs/versioned_docs/version-2.7/30-administration/05-deployment-methods/40-nixos.md
diff --git a/docs/versioned_docs/version-2.7/30-administration/05-deployment-methods/_category_.yaml b/docs/versioned_docs/version-2.7/30-administration/05-deployment-methods/_category_.yaml
new file mode 100644
index 000000000..3907838b0
--- /dev/null
+++ b/docs/versioned_docs/version-2.7/30-administration/05-deployment-methods/_category_.yaml
@@ -0,0 +1,3 @@
+label: 'Deployment methods'
+collapsible: true
+collapsed: true
diff --git a/docs/docs/30-administration/30-database.md b/docs/versioned_docs/version-2.7/30-administration/10-database.md
similarity index 100%
rename from docs/docs/30-administration/30-database.md
rename to docs/versioned_docs/version-2.7/30-administration/10-database.md
diff --git a/docs/versioned_docs/version-2.4/30-administration/10-server-config.md b/docs/versioned_docs/version-2.7/30-administration/10-server-config.md
similarity index 94%
rename from docs/versioned_docs/version-2.4/30-administration/10-server-config.md
rename to docs/versioned_docs/version-2.7/30-administration/10-server-config.md
index 4b6e0ce10..69bd2bb7d 100644
--- a/docs/versioned_docs/version-2.4/30-administration/10-server-config.md
+++ b/docs/versioned_docs/version-2.7/30-administration/10-server-config.md
@@ -6,7 +6,7 @@ toc_max_heading_level: 2
## User registration
-Woodpecker does not have its own user registry; users are provided from your [forge](./11-forges/10-overview.md) (using OAuth2).
+Woodpecker does not have its own user registry; users are provided from your [forge](./11-forges/11-overview.md) (using OAuth2).
Registration is closed by default (`WOODPECKER_OPEN=false`). If registration is open (`WOODPECKER_OPEN=true`) then every user with an account at the configured forge can login to Woodpecker.
@@ -69,7 +69,7 @@ To handle sensitive data in docker-compose or docker-swarm configurations there
For docker-compose you can use a `.env` file next to your compose configuration to store the secrets outside of the compose file. While this separates configuration from secrets it is still not very secure.
-Alternatively use docker-secrets. As it may be difficult to use docker secrets for environment variables woodpecker allows to read sensible data from files by providing a `*_FILE` option of all sensible configuration variables. Woodpecker will try to read the value directly from this file. Keep in mind that when the original environment variable gets specified at the same time it will override the value read from the file.
+Alternatively use docker-secrets. As it may be difficult to use docker secrets for environment variables Woodpecker allows to read sensible data from files by providing a `*_FILE` option of all sensible configuration variables. Woodpecker will try to read the value directly from this file. Keep in mind that when the original environment variable gets specified at the same time it will override the value read from the file.
```diff title="docker-compose.yaml"
version: '3'
@@ -305,7 +305,7 @@ Example: `org1,org2`
> Default: empty
-Comma-separated list of syncable repo owners. ???
+Repositories by those owners will be allowed to be used in woodpecker.
Example: `user1,user2`
@@ -473,12 +473,6 @@ Supported variables:
- `owner`: the repo's owner
- `repo`: the repo's name
-### `WOODPECKER_ADDONS`
-
-> Default: empty
-
-List of addon files. See [addons](./75-addons/00-overview.md).
-
---
### `WOODPECKER_LIMIT_MEM_SWAP`
@@ -523,7 +517,7 @@ Example: `WOODPECKER_LIMIT_CPU_SET=1,2`
> Default: empty
-Specify a configuration service endpoint, see [Configuration Extension](./100-external-configuration-api.md)
+Specify a configuration service endpoint, see [Configuration Extension](./40-advanced/100-external-configuration-api.md)
### `WOODPECKER_FORGE_TIMEOUT`
@@ -531,6 +525,12 @@ Specify a configuration service endpoint, see [Configuration Extension](./100-ex
Specify timeout when fetching the Woodpecker configuration from forge. See for syntax reference.
+### `WOODPECKER_FORGE_RETRY`
+
+> Default: 3
+
+Specify how many retries of fetching the Woodpecker configuration from a forge are done before we fail.
+
### `WOODPECKER_ENABLE_SWAGGER`
> Default: true
@@ -543,6 +543,18 @@ Enable the Swagger UI for API documentation.
Disable version check in admin web UI.
+### `WOODPECKER_LOG_STORE`
+
+> Default: `database`
+
+Where to store logs. Possible values: `database` or `file`.
+
+### `WOODPECKER_LOG_STORE_FILE_PATH`
+
+> Default empty
+
+Directory to store logs in if [`WOODPECKER_LOG_STORE`](#woodpecker_log_store) is `file`.
+
---
### `WOODPECKER_GITHUB_...`
@@ -559,4 +571,8 @@ See [Bitbucket configuration](./11-forges/50-bitbucket.md#configuration)
### `WOODPECKER_GITLAB_...`
-See [Gitlab configuration](./11-forges/40-gitlab.md#configuration)
+See [GitLab configuration](./11-forges/40-gitlab.md#configuration)
+
+### `WOODPECKER_ADDON_FORGE`
+
+See [addon forges](./11-forges/100-addon.md).
diff --git a/docs/versioned_docs/version-2.7/30-administration/11-forges/100-addon.md b/docs/versioned_docs/version-2.7/30-administration/11-forges/100-addon.md
new file mode 100644
index 000000000..e280ed420
--- /dev/null
+++ b/docs/versioned_docs/version-2.7/30-administration/11-forges/100-addon.md
@@ -0,0 +1,68 @@
+# Addon forges
+
+If the forge you're using does not comply with [Woodpecker's requirements](../../92-development/02-core-ideas.md#forges) or your setup is too specific to be added to Woodpecker's core, you can write your own forge using an addon forge.
+
+:::warning
+Addon forges are still experimental. Their implementation can change and break at any time.
+:::
+
+:::danger
+You need to trust the author of the addon forge you use. It can access authentication codes and other possibly sensitive information.
+:::
+
+## Usage
+
+To use an addon forge, download the correct addon version. Then, you can add the following to your configuration:
+
+```ini
+WOODPECKER_ADDON_FORGE=/path/to/your/addon/forge/file
+```
+
+In case you run Woodpecker as container, you probably want to mount the addon binary to `/opt/addons/`.
+
+### Bug reports
+
+If you experience bugs, please check which component has the issue. If it's the addon, **do not raise an issue in the main repository**, but rather use the separate addon repositories. To check which component is responsible for the bug, look at the logs. Logs from addons are marked with a special field `addon` containing their addon file name.
+
+## List of addon forges
+
+If you wrote or found an addon forge, please add it here so others can find it!
+
+_Be the first one to add your addon forge!_
+
+## Creating addon forges
+
+Addons use RPC to communicate to the server and are implemented using the [`go-plugin` library](https://github.com/hashicorp/go-plugin).
+
+### Writing your code
+
+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.
+
+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.
+
+### Example structure
+
+```go
+package main
+
+import (
+ "context"
+ "net/http"
+
+ "go.woodpecker-ci.org/woodpecker/v2/server/forge/addon"
+ forgeTypes "go.woodpecker-ci.org/woodpecker/v2/server/forge/types"
+ "go.woodpecker-ci.org/woodpecker/v2/server/model"
+)
+
+func main() {
+ addon.Serve(config{})
+}
+
+type config struct {
+}
+
+// `config` must implement `"go.woodpecker-ci.org/woodpecker/v2/server/forge".Forge`. You must directly use Woodpecker's packages - see imports above.
+```
diff --git a/docs/versioned_docs/version-2.7/30-administration/11-forges/11-overview.md b/docs/versioned_docs/version-2.7/30-administration/11-forges/11-overview.md
new file mode 100644
index 000000000..ba45adf87
--- /dev/null
+++ b/docs/versioned_docs/version-2.7/30-administration/11-forges/11-overview.md
@@ -0,0 +1,13 @@
+# Forges
+
+## Supported features
+
+| Feature | [GitHub](20-github.md) | [Gitea](30-gitea.md) | [Forgejo](35-forgejo.md) | [Gitlab](40-gitlab.md) | [Bitbucket](50-bitbucket.md) | [Bitbucket Datacenter](60-bitbucket_datacenter.md) |
+| ------------------------------------------------------------- | :--------------------: | :------------------: | :----------------------: | :--------------------: | :--------------------------: | :------------------------------------------------: |
+| Event: Push | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| Event: Tag | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| Event: Pull-Request | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| Event: Release | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: |
+| Event: Deploy | :white_check_mark: | :x: | :x: | :x: | :x: | :x: |
+| [Multiple workflows](../../20-usage/25-workflows.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| [when.path filter](../../20-usage/20-workflow-syntax.md#path) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: |
diff --git a/docs/versioned_docs/version-2.4/30-administration/11-forges/20-github.md b/docs/versioned_docs/version-2.7/30-administration/11-forges/20-github.md
similarity index 93%
rename from docs/versioned_docs/version-2.4/30-administration/11-forges/20-github.md
rename to docs/versioned_docs/version-2.7/30-administration/11-forges/20-github.md
index f3656f8fd..338e555fd 100644
--- a/docs/versioned_docs/version-2.4/30-administration/11-forges/20-github.md
+++ b/docs/versioned_docs/version-2.7/30-administration/11-forges/20-github.md
@@ -81,3 +81,9 @@ Read the value for `WOODPECKER_GITHUB_SECRET` from the specified filepath.
> Default: `false`
Configure if SSL verification should be skipped.
+
+### `WOODPECKER_GITHUB_PUBLIC_ONLY`
+
+> Default: `false`
+
+Configures the GitHub OAuth client to only obtain a token that can manage public repositories.
diff --git a/docs/versioned_docs/version-2.4/30-administration/11-forges/30-gitea.md b/docs/versioned_docs/version-2.7/30-administration/11-forges/30-gitea.md
similarity index 84%
rename from docs/versioned_docs/version-2.4/30-administration/11-forges/30-gitea.md
rename to docs/versioned_docs/version-2.7/30-administration/11-forges/30-gitea.md
index b50d2e011..bb8e93c2a 100644
--- a/docs/versioned_docs/version-2.4/30-administration/11-forges/30-gitea.md
+++ b/docs/versioned_docs/version-2.7/30-administration/11-forges/30-gitea.md
@@ -2,9 +2,9 @@
toc_max_heading_level: 2
---
-# Gitea / Forgejo
+# Gitea
-Woodpecker comes with built-in support for Gitea and the "soft" fork Forgejo. To enable Gitea you should configure the Woodpecker container using the following environment variables:
+Woodpecker comes with built-in support for Gitea. To enable Gitea you should configure the Woodpecker container using the following environment variables:
```ini
WOODPECKER_GITEA=true
@@ -16,7 +16,7 @@ WOODPECKER_GITEA_SECRET=YOUR_GITEA_CLIENT_SECRET
## Gitea on the same host with containers
If you have Gitea also running on the same host within a container, make sure the agent does have access to it.
-The agent tries to clone using the URL which Gitea reports through its API. For simplified connectivity, you should add the woodpecker agent to the same docker network as Gitea is in.
+The agent tries to clone using the URL which Gitea reports through its API. For simplified connectivity, you should add the Woodpecker agent to the same docker network as Gitea is in.
Otherwise, the communication should go via the `docker0` gateway (usually 172.17.0.1).
To configure the Docker network if the network's name is `gitea`, configure it like this:
@@ -93,3 +93,11 @@ Read the value for `WOODPECKER_GITEA_SECRET` from the specified filepath
> Default: `false`
Configure if SSL verification should be skipped.
+
+## Advanced options
+
+### `WOODPECKER_DEV_GITEA_OAUTH_URL`
+
+> Default: value of `WOODPECKER_GITEA_URL`
+
+Configures the user-facing Gitea server address. Should be used if `WOODPECKER_GITEA_URL` points to an internal URL used for API requests.
diff --git a/docs/versioned_docs/version-2.7/30-administration/11-forges/35-forgejo.md b/docs/versioned_docs/version-2.7/30-administration/11-forges/35-forgejo.md
new file mode 100644
index 000000000..df7793118
--- /dev/null
+++ b/docs/versioned_docs/version-2.7/30-administration/11-forges/35-forgejo.md
@@ -0,0 +1,97 @@
+---
+toc_max_heading_level: 2
+---
+
+# Forgejo
+
+:::warning
+Forgejo support is experimental.
+:::
+
+Woodpecker comes with built-in support for Forgejo. To enable Forgejo you should configure the Woodpecker container using the following environment variables:
+
+```ini
+WOODPECKER_FORGEJO=true
+WOODPECKER_FORGEJO_URL=YOUR_FORGEJO_URL
+WOODPECKER_FORGEJO_CLIENT=YOUR_FORGEJO_CLIENT
+WOODPECKER_FORGEJO_SECRET=YOUR_FORGEJO_CLIENT_SECRET
+```
+
+## Forgejo on the same host with containers
+
+If you have Forgejo also running on the same host within a container, make sure the agent does have access to it.
+The agent tries to clone using the URL which Forgejo reports through its API. For simplified connectivity, you should add the Woodpecker agent to the same docker network as Forgejo is in.
+Otherwise, the communication should go via the `docker0` gateway (usually 172.17.0.1).
+
+To configure the Docker network if the network's name is `forgejo`, configure it like this:
+
+```diff title="docker-compose.yaml"
+ services:
+ [...]
+ woodpecker-agent:
+ [...]
+ environment:
+ - [...]
++ - WOODPECKER_BACKEND_DOCKER_NETWORK=forgejo
+```
+
+## Registration
+
+Register your application with Forgejo to create your client id and secret. You can find the OAuth applications settings of Forgejo at `https://forgejo./user/settings/`. It is very import the authorization callback URL matches your http(s) scheme and hostname exactly with `https:///authorize` as the path.
+
+If you run the Woodpecker CI server on the same host as the Forgejo instance, you might also need to allow local connections in Forgejo. Otherwise webhooks will fail. Add the following lines to your Forgejo configuration (usually at `/etc/forgejo/conf/app.ini`).
+
+```ini
+[webhook]
+ALLOWED_HOST_LIST=external,loopback
+```
+
+For reference see [Configuration Cheat Sheet](https://forgejo.org/docs/latest/admin/config-cheat-sheet/#webhook-webhook).
+
+![forgejo oauth setup](gitea_oauth.gif)
+
+## Configuration
+
+This is a full list of configuration options. Please note that many of these options use default configuration values that should work for the majority of installations.
+
+### `WOODPECKER_FORGEJO`
+
+> Default: `false`
+
+Enables the Forgejo driver.
+
+### `WOODPECKER_FORGEJO_URL`
+
+> Default: `https://next.forgejo.org`
+
+Configures the Forgejo server address.
+
+### `WOODPECKER_FORGEJO_CLIENT`
+
+> Default: empty
+
+Configures the Forgejo OAuth client id. This is used to authorize access.
+
+### `WOODPECKER_FORGEJO_CLIENT_FILE`
+
+> Default: empty
+
+Read the value for `WOODPECKER_FORGEJO_CLIENT` from the specified filepath
+
+### `WOODPECKER_FORGEJO_SECRET`
+
+> Default: empty
+
+Configures the Forgejo OAuth client secret. This is used to authorize access.
+
+### `WOODPECKER_FORGEJO_SECRET_FILE`
+
+> Default: empty
+
+Read the value for `WOODPECKER_FORGEJO_SECRET` from the specified filepath
+
+### `WOODPECKER_FORGEJO_SKIP_VERIFY`
+
+> Default: `false`
+
+Configure if SSL verification should be skipped.
diff --git a/docs/versioned_docs/version-2.4/30-administration/11-forges/40-gitlab.md b/docs/versioned_docs/version-2.7/30-administration/11-forges/40-gitlab.md
similarity index 100%
rename from docs/versioned_docs/version-2.4/30-administration/11-forges/40-gitlab.md
rename to docs/versioned_docs/version-2.7/30-administration/11-forges/40-gitlab.md
diff --git a/docs/versioned_docs/version-2.4/30-administration/11-forges/50-bitbucket.md b/docs/versioned_docs/version-2.7/30-administration/11-forges/50-bitbucket.md
similarity index 97%
rename from docs/versioned_docs/version-2.4/30-administration/11-forges/50-bitbucket.md
rename to docs/versioned_docs/version-2.7/30-administration/11-forges/50-bitbucket.md
index b658238d6..d368e709c 100644
--- a/docs/versioned_docs/version-2.4/30-administration/11-forges/50-bitbucket.md
+++ b/docs/versioned_docs/version-2.7/30-administration/11-forges/50-bitbucket.md
@@ -14,7 +14,7 @@ WOODPECKER_BITBUCKET_SECRET=...
## Registration
-You must register an OAuth application at Bitbucket in order to get a key and secret combination for woodpecker. Navigate to your workspace settings and choose `OAuth consumers` from the menu, and finally click `Add Consumer` (the url should be like: `https://bitbucket.org/[your-project-name]/workspace/settings/api`).
+You must register an OAuth application at Bitbucket in order to get a key and secret combination for Woodpecker. Navigate to your workspace settings and choose `OAuth consumers` from the menu, and finally click `Add Consumer` (the url should be like: `https://bitbucket.org/[your-project-name]/workspace/settings/api`).
Please set a name and set the `Callback URL` like this:
diff --git a/docs/versioned_docs/version-2.4/30-administration/11-forges/60-bitbucket_datacenter.md b/docs/versioned_docs/version-2.7/30-administration/11-forges/60-bitbucket_datacenter.md
similarity index 74%
rename from docs/versioned_docs/version-2.4/30-administration/11-forges/60-bitbucket_datacenter.md
rename to docs/versioned_docs/version-2.7/30-administration/11-forges/60-bitbucket_datacenter.md
index e85242c05..53926fa73 100644
--- a/docs/versioned_docs/version-2.4/30-administration/11-forges/60-bitbucket_datacenter.md
+++ b/docs/versioned_docs/version-2.7/30-administration/11-forges/60-bitbucket_datacenter.md
@@ -10,24 +10,23 @@ Woodpecker comes with experimental support for Bitbucket Datacenter / Server, fo
To enable Bitbucket Server you should configure the Woodpecker container using the following environment variables:
-```diff
-# docker-compose.yml
-version: '3'
+```diff title="docker-compose.yaml"
+ version: '3'
-services:
- woodpecker-server:
- [...]
- environment:
- - [...]
-+ - WOODPECKER_BITBUCKET_DC=true
-+ - WOODPECKER_BITBUCKET_DC_GIT_USERNAME=foo
-+ - WOODPECKER_BITBUCKET_DC_GIT_PASSWORD=bar
-+ - WOODPECKER_BITBUCKET_DC_CLIENT_ID=xxx
-+ - WOODPECKER_BITBUCKET_DC_CLIENT_SECRET=yyy
-+ - WOODPECKER_BITBUCKET_DC_URL=http://stash.mycompany.com
+ services:
+ woodpecker-server:
+ [...]
+ environment:
+ - [...]
++ - WOODPECKER_BITBUCKET_DC=true
++ - WOODPECKER_BITBUCKET_DC_GIT_USERNAME=foo
++ - WOODPECKER_BITBUCKET_DC_GIT_PASSWORD=bar
++ - WOODPECKER_BITBUCKET_DC_CLIENT_ID=xxx
++ - WOODPECKER_BITBUCKET_DC_CLIENT_SECRET=yyy
++ - WOODPECKER_BITBUCKET_DC_URL=http://stash.mycompany.com
- woodpecker-agent:
- [...]
+ woodpecker-agent:
+ [...]
```
## Service Account
@@ -36,7 +35,10 @@ Woodpecker uses `git+https` to clone repositories, however, Bitbucket Server doe
## Registration
-Woodpecker must be registered with Bitbucket Datacenter / Server. In the administration section of Bitbucket choose "Application Links" and then "Create link". Woodpecker should be listed as "External Application" and the direction should be set to "Incomming". Note the client id and client secret of the registration to be used in the configuration of Woodpecker.
+Woodpecker must be registered with Bitbucket Datacenter / Server.
+In the administration section of Bitbucket choose "Application Links" and then "Create link".
+Woodpecker should be listed as "External Application" and the direction should be set to "Incoming".
+Note the client id and client secret of the registration to be used in the configuration of Woodpecker.
See also [Configure an incoming link](https://confluence.atlassian.com/bitbucketserver/configure-an-incoming-link-1108483657.html).
diff --git a/docs/versioned_docs/version-2.4/30-administration/11-forges/_category_.yaml b/docs/versioned_docs/version-2.7/30-administration/11-forges/_category_.yaml
similarity index 100%
rename from docs/versioned_docs/version-2.4/30-administration/11-forges/_category_.yaml
rename to docs/versioned_docs/version-2.7/30-administration/11-forges/_category_.yaml
diff --git a/docs/versioned_docs/version-2.4/30-administration/11-forges/bitbucket_oauth.png b/docs/versioned_docs/version-2.7/30-administration/11-forges/bitbucket_oauth.png
similarity index 100%
rename from docs/versioned_docs/version-2.4/30-administration/11-forges/bitbucket_oauth.png
rename to docs/versioned_docs/version-2.7/30-administration/11-forges/bitbucket_oauth.png
diff --git a/docs/versioned_docs/version-2.4/30-administration/11-forges/bitbucket_permissions.png b/docs/versioned_docs/version-2.7/30-administration/11-forges/bitbucket_permissions.png
similarity index 100%
rename from docs/versioned_docs/version-2.4/30-administration/11-forges/bitbucket_permissions.png
rename to docs/versioned_docs/version-2.7/30-administration/11-forges/bitbucket_permissions.png
diff --git a/docs/versioned_docs/version-2.4/30-administration/11-forges/gitea_oauth.gif b/docs/versioned_docs/version-2.7/30-administration/11-forges/gitea_oauth.gif
similarity index 100%
rename from docs/versioned_docs/version-2.4/30-administration/11-forges/gitea_oauth.gif
rename to docs/versioned_docs/version-2.7/30-administration/11-forges/gitea_oauth.gif
diff --git a/docs/versioned_docs/version-2.4/30-administration/11-forges/github_oauth.png b/docs/versioned_docs/version-2.7/30-administration/11-forges/github_oauth.png
similarity index 100%
rename from docs/versioned_docs/version-2.4/30-administration/11-forges/github_oauth.png
rename to docs/versioned_docs/version-2.7/30-administration/11-forges/github_oauth.png
diff --git a/docs/versioned_docs/version-2.4/30-administration/15-agent-config.md b/docs/versioned_docs/version-2.7/30-administration/15-agent-config.md
similarity index 100%
rename from docs/versioned_docs/version-2.4/30-administration/15-agent-config.md
rename to docs/versioned_docs/version-2.7/30-administration/15-agent-config.md
diff --git a/docs/versioned_docs/version-2.4/30-administration/22-backends/10-docker.md b/docs/versioned_docs/version-2.7/30-administration/22-backends/10-docker.md
similarity index 100%
rename from docs/versioned_docs/version-2.4/30-administration/22-backends/10-docker.md
rename to docs/versioned_docs/version-2.7/30-administration/22-backends/10-docker.md
diff --git a/docs/versioned_docs/version-2.4/30-administration/22-backends/20-local.md b/docs/versioned_docs/version-2.7/30-administration/22-backends/20-local.md
similarity index 58%
rename from docs/versioned_docs/version-2.4/30-administration/22-backends/20-local.md
rename to docs/versioned_docs/version-2.7/30-administration/22-backends/20-local.md
index 7ec95f0f8..c0faf9c2f 100644
--- a/docs/versioned_docs/version-2.4/30-administration/22-backends/20-local.md
+++ b/docs/versioned_docs/version-2.7/30-administration/22-backends/20-local.md
@@ -5,33 +5,31 @@ toc_max_heading_level: 3
# Local backend
:::danger
-The local backend will execute the pipelines on the local system without any isolation of any kind.
+The local backend executes pipelines on the local system without any isolation.
:::
:::note
-Currently we do not support services for this backend.
+Currently we do not support [services](../../20-usage/60-services.md) for this backend.
[Read more here](https://github.com/woodpecker-ci/woodpecker/issues/3095).
:::
-Since the code runs directly in the same context as the agent (same user, same
+Since the commands run directly in the same context as the agent (same user, same
filesystem), a malicious pipeline could be used to access the agent
configuration especially the `WOODPECKER_AGENT_SECRET` variable.
It is recommended to use this backend only for private setup where the code and
-pipeline can be trusted. You shouldn't use it for a public facing CI where
-anyone can submit code or add new repositories. You shouldn't execute the agent
-as a privileged user (root).
+pipeline can be trusted. It should not be used in a public instance where
+anyone can submit code or add new repositories. The agent should not run as a privileged user (root).
The local backend will use a random directory in `$TMPDIR` to store the cloned
code and execute commands.
In order to use this backend, you need to download (or build) the
-[binary](https://github.com/woodpecker-ci/woodpecker/releases/latest) of the
-agent, configure it and run it on the host machine.
+[agent](https://github.com/woodpecker-ci/woodpecker/releases/latest), configure it and run it on the host machine.
## Usage
-To enable the local backend, add this to your configuration:
+To enable the local backend, set the following:
```ini
WOODPECKER_BACKEND=local
@@ -39,7 +37,7 @@ WOODPECKER_BACKEND=local
### Shell
-The `image` entry is used to specify the shell, such as Bash or Fish, that is
+The `image` entrypoint is used to specify the shell, such as `bash` or `fish`, that is
used to run the commands.
```yaml title=".woodpecker.yaml"
@@ -51,15 +49,13 @@ steps:
### Plugins
-Plugins are just executable binaries:
-
```yaml
steps:
- name: build
image: /usr/bin/tree
```
-If no commands are provided, we treat them as plugins in the usual manner.
+If no commands are provided, plugins are treated in the usual manner.
In the context of the local backend, plugins are simply executable binaries, which can be located using their name if they are listed in `$PATH`, or through an absolute path.
### Options
diff --git a/docs/versioned_docs/version-2.4/30-administration/22-backends/40-kubernetes.md b/docs/versioned_docs/version-2.7/30-administration/22-backends/40-kubernetes.md
similarity index 66%
rename from docs/versioned_docs/version-2.4/30-administration/22-backends/40-kubernetes.md
rename to docs/versioned_docs/version-2.7/30-administration/22-backends/40-kubernetes.md
index e878b6a4f..72524946b 100644
--- a/docs/versioned_docs/version-2.4/30-administration/22-backends/40-kubernetes.md
+++ b/docs/versioned_docs/version-2.7/30-administration/22-backends/40-kubernetes.md
@@ -4,19 +4,19 @@ toc_max_heading_level: 2
# Kubernetes backend
-The kubernetes backend executes steps inside standalone pods. A temporary PVC is created for the lifetime of the pipeline to transfer files between steps.
+The Kubernetes backend executes steps inside standalone Pods. A temporary PVC is created for the lifetime of the pipeline to transfer files between steps.
## Images from private registries
-In order to pull private container images defined in your pipeline YAML you must provide [registry credentials in Kubernetes secret](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/).
-As the secret is Agent-wide, it has to be placed in namespace defined by `WOODPECKER_BACKEND_K8S_NAMESPACE`.
-Besides, you need to provide the secret name to Agent via `WOODPECKER_BACKEND_K8S_PULL_SECRET_NAMES`.
+In order to pull private container images defined in your pipeline YAML you must provide [registry credentials in Kubernetes Secret](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/).
+As the Secret is Agent-wide, it has to be placed in namespace defined by `WOODPECKER_BACKEND_K8S_NAMESPACE`.
+Besides, you need to provide the Secret name to Agent via `WOODPECKER_BACKEND_K8S_PULL_SECRET_NAMES`.
## Job specific configuration
### Resources
-The kubernetes backend also allows for specifying requests and limits on a per-step basic, most commonly for CPU and memory.
+The Kubernetes backend also allows for specifying requests and limits on a per-step basic, most commonly for CPU and memory.
We recommend to add a `resources` definition to all steps to ensure efficient scheduling.
Here is an example definition with an arbitrary `resources` definition below the `backend_options` section:
@@ -40,10 +40,15 @@ steps:
You can use [Limit Ranges](https://kubernetes.io/docs/concepts/policy/limit-range/) if you want to set the limits by per-namespace basis.
+### Runtime class
+
+`runtimeClassName` specifies the name of the RuntimeClass which will be used to run this Pod. If no `runtimeClassName` is specified, the default RuntimeHandler will be used.
+See the [Kubernetes documentation](https://kubernetes.io/docs/concepts/containers/runtime-class/) for more information on specifying runtime classes.
+
### Service account
-`serviceAccountName` specifies the name of the ServiceAccount which the pod will mount. This service account must be created externally.
-See the [kubernetes documentation](https://kubernetes.io/docs/concepts/security/service-accounts/) for more information on using service accounts.
+`serviceAccountName` specifies the name of the ServiceAccount which the Pod will mount. This service account must be created externally.
+See the [Kubernetes documentation](https://kubernetes.io/docs/concepts/security/service-accounts/) for more information on using service accounts.
### Node selector
@@ -74,12 +79,13 @@ And then overwrite the `nodeSelector` in the `backend_options` section of the st
kubernetes.io/arch: "${ARCH}"
```
-You can use [PodNodeSelector](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#podnodeselector) admission controller if you want to set the node selector by per-namespace basis.
+You can use [WOODPECKER_BACKEND_K8S_POD_NODE_SELECTOR](#woodpecker_backend_k8s_pod_node_selector) if you want to set the node selector per Agent
+or [PodNodeSelector](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#podnodeselector) admission controller if you want to set the node selector by per-namespace basis.
### Tolerations
-When you use `nodeSelector` and the node pool is configured with Taints, you need to specify the Tolerations. Tolerations allow the scheduler to schedule pods with matching taints.
-See the [kubernetes documentation](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) for more information on using tolerations.
+When you use `nodeSelector` and the node pool is configured with Taints, you need to specify the Tolerations. Tolerations allow the scheduler to schedule Pods with matching taints.
+See the [Kubernetes documentation](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) for more information on using tolerations.
Example pipeline configuration:
@@ -112,7 +118,7 @@ steps:
### Volumes
-To mount volumes a persistent volume (PV) and persistent volume claim (PVC) are needed on the cluster which can be referenced in steps via the `volumes` option.
+To mount volumes a PersistentVolume (PV) and PersistentVolumeClaim (PVC) are needed on the cluster which can be referenced in steps via the `volumes` option.
Assuming a PVC named `woodpecker-cache` exists, it can be referenced as follows in a step:
```yaml
@@ -129,7 +135,7 @@ steps:
### Security context
-Use the following configuration to set the [Security Context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) for the pod/container running a given pipeline step:
+Use the following configuration to set the [Security Context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) for the Pod/container running a given pipeline step:
```yaml
steps:
@@ -146,9 +152,9 @@ steps:
[...]
```
-Note that the `backend_options.kubernetes.securityContext` object allows you to set both pod and container level security context options in one object.
-By default, the properties will be set at the pod level. Properties that are only supported on the container level will be set there instead. So, the
-configuration shown above will result in something like the following pod spec:
+Note that the `backend_options.kubernetes.securityContext` object allows you to set both Pod and container level security context options in one object.
+By default, the properties will be set at the Pod level. Properties that are only supported on the container level will be set there instead. So, the
+configuration shown above will result in something like the following Pod spec:
```yaml
kind: Pod
@@ -190,6 +196,24 @@ backend_options:
AppArmor syntax follows [KEP-24](https://github.com/kubernetes/enhancements/blob/fddcbb9cbf3df39ded03bad71228265ac6e5215f/keps/sig-node/24-apparmor/README.md).
:::
+### Annotations and labels
+
+You can specify arbitrary [annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) and [labels](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/) to be set on the Pod definition for a given workflow step using the following configuration:
+
+```yaml
+backend_options:
+ kubernetes:
+ annotations:
+ workflow-group: alpha
+ io.kubernetes.cri-o.Devices: /dev/fuse
+ labels:
+ environment: ci
+ app.kubernetes.io/name: builder
+```
+
+In order to enable this configuration you need to set the appropriate environment variables to `true` on the woodpecker agent:
+[WOODPECKER_BACKEND_K8S_POD_ANNOTATIONS_ALLOW_FROM_STEP](#woodpecker_backend_k8s_pod_annotations_allow_from_step) and/or [WOODPECKER_BACKEND_K8S_POD_LABELS_ALLOW_FROM_STEP](#woodpecker_backend_k8s_pod_labels_allow_from_step).
+
## Tips and tricks
### CRI-O
@@ -204,6 +228,13 @@ workspace:
See [this issue](https://github.com/woodpecker-ci/woodpecker/issues/2510) for more details.
+### `KUBERNETES_SERVICE_HOST` environment variable
+
+Like the below env vars used for configuration, this can be set in the environment for configuration of the agent.
+It configures the address of the Kubernetes API server to connect to.
+
+If running the agent within Kubernetes, this will already be set and you don't have to add it manually.
+
## Configuration
These env vars can be set in the `env:` sections of the agent.
@@ -212,7 +243,7 @@ These env vars can be set in the `env:` sections of the agent.
> Default: `woodpecker`
-The namespace to create worker pods in.
+The namespace to create worker Pods in.
### `WOODPECKER_BACKEND_K8S_VOLUME_SIZE`
@@ -236,13 +267,31 @@ Determines if `RWX` should be used for the pipeline volume's [access mode](https
> Default: empty
-Additional labels to apply to worker pods. Must be a YAML object, e.g. `{"example.com/test-label":"test-value"}`.
+Additional labels to apply to worker Pods. Must be a YAML object, e.g. `{"example.com/test-label":"test-value"}`.
+
+### `WOODPECKER_BACKEND_K8S_POD_LABELS_ALLOW_FROM_STEP`
+
+> Default: `false`
+
+Determines if additional Pod labels can be defined from a step's backend options.
### `WOODPECKER_BACKEND_K8S_POD_ANNOTATIONS`
> Default: empty
-Additional annotations to apply to worker pods. Must be a YAML object, e.g. `{"example.com/test-annotation":"test-value"}`.
+Additional annotations to apply to worker Pods. Must be a YAML object, e.g. `{"example.com/test-annotation":"test-value"}`.
+
+### `WOODPECKER_BACKEND_K8S_POD_ANNOTATIONS_ALLOW_FROM_STEP`
+
+> Default: `false`
+
+Determines if Pod annotations can be defined from a step's backend options.
+
+### `WOODPECKER_BACKEND_K8S_POD_NODE_SELECTOR`
+
+> Default: empty
+
+Additional node selector to apply to worker pods. Must be a YAML object, e.g. `{"topology.kubernetes.io/region":"eu-central-1"}`.
### `WOODPECKER_BACKEND_K8S_SECCTX_NONROOT`
diff --git a/docs/versioned_docs/version-2.4/30-administration/22-backends/50-custom-backends.md b/docs/versioned_docs/version-2.7/30-administration/22-backends/50-custom-backends.md
similarity index 89%
rename from docs/versioned_docs/version-2.4/30-administration/22-backends/50-custom-backends.md
rename to docs/versioned_docs/version-2.7/30-administration/22-backends/50-custom-backends.md
index 3c771c4ef..a35a4f1ee 100644
--- a/docs/versioned_docs/version-2.4/30-administration/22-backends/50-custom-backends.md
+++ b/docs/versioned_docs/version-2.7/30-administration/22-backends/50-custom-backends.md
@@ -1,6 +1,6 @@
# Custom backends
-If none of our backends fits your usecases, you can write your own.
+If none of our backends fits your usecase, you can write your own.
Therefore, implement the interface `"go.woodpecker-ci.org/woodpecker/woodpecker/v2/pipeline/backend/types".Backend` and
build a custom agent using your backend with this `main.go`:
diff --git a/docs/versioned_docs/version-2.4/30-administration/22-backends/_category_.yaml b/docs/versioned_docs/version-2.7/30-administration/22-backends/_category_.yaml
similarity index 100%
rename from docs/versioned_docs/version-2.4/30-administration/22-backends/_category_.yaml
rename to docs/versioned_docs/version-2.7/30-administration/22-backends/_category_.yaml
diff --git a/docs/docs/30-administration/70-proxy.md b/docs/versioned_docs/version-2.7/30-administration/40-advanced/10-proxy.md
similarity index 98%
rename from docs/docs/30-administration/70-proxy.md
rename to docs/versioned_docs/version-2.7/30-administration/40-advanced/10-proxy.md
index 1e253e457..607cd8bd4 100644
--- a/docs/docs/30-administration/70-proxy.md
+++ b/docs/versioned_docs/version-2.7/30-administration/40-advanced/10-proxy.md
@@ -93,7 +93,7 @@ woodpeckeragent.example.com {
```
:::note
-Above configuration shows how to create reverse-proxies for web and agent communication. If your agent uses SSL do not forget to enable [`WOODPECKER_GRPC_SECURE`](./15-agent-config.md#woodpecker_grpc_secure).
+Above configuration shows how to create reverse-proxies for web and agent communication. If your agent uses SSL do not forget to enable [`WOODPECKER_GRPC_SECURE`](../15-agent-config.md#woodpecker_grpc_secure).
:::
## Tunnelmole
diff --git a/docs/docs/30-administration/100-external-configuration-api.md b/docs/versioned_docs/version-2.7/30-administration/40-advanced/100-external-configuration-api.md
similarity index 100%
rename from docs/docs/30-administration/100-external-configuration-api.md
rename to docs/versioned_docs/version-2.7/30-administration/40-advanced/100-external-configuration-api.md
diff --git a/docs/docs/30-administration/60-ssl.md b/docs/versioned_docs/version-2.7/30-administration/40-advanced/20-ssl.md
similarity index 100%
rename from docs/docs/30-administration/60-ssl.md
rename to docs/versioned_docs/version-2.7/30-administration/40-advanced/20-ssl.md
diff --git a/docs/docs/30-administration/80-autoscaler.md b/docs/versioned_docs/version-2.7/30-administration/40-advanced/30-autoscaler.md
similarity index 93%
rename from docs/docs/30-administration/80-autoscaler.md
rename to docs/versioned_docs/version-2.7/30-administration/40-advanced/30-autoscaler.md
index 6ac581c2e..ce9ee914a 100644
--- a/docs/docs/30-administration/80-autoscaler.md
+++ b/docs/versioned_docs/version-2.7/30-administration/40-advanced/30-autoscaler.md
@@ -29,8 +29,8 @@ services:
- WOODPECKER_MIN_AGENTS=0
- WOODPECKER_MAX_AGENTS=3
- WOODPECKER_WORKFLOWS_PER_AGENT=2 # the number of workflows each agent can run at the same time
- - WOODEPCKER_GRPC_ADDR=https://grpc.your-woodpecker-server.tld # the grpc address of your woodpecker server, publicly accessible from the agents
- - WOODEPCKER_GRPC_SECURE=true
+ - WOODPECKER_GRPC_ADDR=https://grpc.your-woodpecker-server.tld # the grpc address of your woodpecker server, publicly accessible from the agents
+ - WOODPECKER_GRPC_SECURE=true
- WOODPECKER_AGENT_ENV= # optional environment variables to pass to the agents
- WOODPECKER_PROVIDER=hetznercloud # set the provider, you can find all the available ones down below
- WOODPECKER_HETZNERCLOUD_API_TOKEN=${WOODPECKER_HETZNERCLOUD_API_TOKEN} # your api token for the Hetzner cloud
diff --git a/docs/versioned_docs/version-2.7/30-administration/40-advanced/40-advanced.md b/docs/versioned_docs/version-2.7/30-administration/40-advanced/40-advanced.md
new file mode 100644
index 000000000..4261bbeea
--- /dev/null
+++ b/docs/versioned_docs/version-2.7/30-administration/40-advanced/40-advanced.md
@@ -0,0 +1,25 @@
+# Advanced options
+
+Why should we be happy with a default setup? We should not! Woodpecker offers a lot of advanced options to configure it to your needs.
+
+## Behind a proxy
+
+See the [proxy guide](./10-proxy.md) if you want to see a setup behind Apache, Nginx, Caddy or ngrok.
+
+In the case you need to use Woodpecker with a URL path prefix (like: ), add the root path to [`WOODPECKER_HOST`](../10-server-config.md#woodpecker_host).
+
+## SSL
+
+Woodpecker supports SSL configuration by using Let's encrypt or by using own certificates. See the [SSL guide](./20-ssl.md).
+
+## Metrics
+
+A [Prometheus endpoint](./90-prometheus.md) is exposed by Woodpecker to collect metrics.
+
+## Autoscaling
+
+The [autoscaler](./30-autoscaler.md) can be used to deploy new agents to a cloud provider based on the current workload your server is experiencing.
+
+## Configuration service
+
+Sometime the normal yaml configuration compiler isn't enough. You can use the [configuration service](./100-external-configuration-api.md) to process your configuration files by your own.
diff --git a/docs/docs/30-administration/90-prometheus.md b/docs/versioned_docs/version-2.7/30-administration/40-advanced/90-prometheus.md
similarity index 100%
rename from docs/docs/30-administration/90-prometheus.md
rename to docs/versioned_docs/version-2.7/30-administration/40-advanced/90-prometheus.md
diff --git a/docs/docs/30-administration/00-deployment/_category_.yaml b/docs/versioned_docs/version-2.7/30-administration/40-advanced/_category_.yaml
similarity index 59%
rename from docs/docs/30-administration/00-deployment/_category_.yaml
rename to docs/versioned_docs/version-2.7/30-administration/40-advanced/_category_.yaml
index 728434969..e6c6ba0f7 100644
--- a/docs/docs/30-administration/00-deployment/_category_.yaml
+++ b/docs/versioned_docs/version-2.7/30-administration/40-advanced/_category_.yaml
@@ -1,6 +1,6 @@
-label: 'Deployment'
+label: 'Advanced'
collapsible: true
collapsed: true
link:
type: 'doc'
- id: 'overview'
+ id: 'advanced'
diff --git a/docs/versioned_docs/version-2.4/30-administration/_category_.yaml b/docs/versioned_docs/version-2.7/30-administration/_category_.yaml
similarity index 100%
rename from docs/versioned_docs/version-2.4/30-administration/_category_.yaml
rename to docs/versioned_docs/version-2.7/30-administration/_category_.yaml
diff --git a/docs/versioned_docs/version-2.4/30-administration/new-agent-connected.png b/docs/versioned_docs/version-2.7/30-administration/new-agent-connected.png
similarity index 100%
rename from docs/versioned_docs/version-2.4/30-administration/new-agent-connected.png
rename to docs/versioned_docs/version-2.7/30-administration/new-agent-connected.png
diff --git a/docs/versioned_docs/version-2.4/30-administration/new-agent-created.png b/docs/versioned_docs/version-2.7/30-administration/new-agent-created.png
similarity index 100%
rename from docs/versioned_docs/version-2.4/30-administration/new-agent-created.png
rename to docs/versioned_docs/version-2.7/30-administration/new-agent-created.png
diff --git a/docs/versioned_docs/version-2.4/30-administration/new-agent-registration.png b/docs/versioned_docs/version-2.7/30-administration/new-agent-registration.png
similarity index 100%
rename from docs/versioned_docs/version-2.4/30-administration/new-agent-registration.png
rename to docs/versioned_docs/version-2.7/30-administration/new-agent-registration.png
diff --git a/docs/versioned_docs/version-2.7/40-cli.md b/docs/versioned_docs/version-2.7/40-cli.md
new file mode 100644
index 000000000..8e4e62358
--- /dev/null
+++ b/docs/versioned_docs/version-2.7/40-cli.md
@@ -0,0 +1,795 @@
+# CLI
+
+# NAME
+
+woodpecker-cli - command line utility
+
+# SYNOPSIS
+
+woodpecker-cli
+
+```
+[--config|-c]=[value]
+[--disable-update-check]
+[--log-file]=[value]
+[--log-level]=[value]
+[--nocolor]
+[--pretty]
+[--server|-s]=[value]
+[--token|-t]=[value]
+```
+
+# DESCRIPTION
+
+Woodpecker command line utility
+
+**Usage**:
+
+```
+woodpecker-cli [GLOBAL OPTIONS] [command [COMMAND OPTIONS]] [ARGUMENTS...]
+```
+
+# GLOBAL OPTIONS
+
+**--config, -c**="": path to config file
+
+**--disable-update-check**: disable update check
+
+**--log-file**="": Output destination for logs. 'stdout' and 'stderr' can be used as special keywords. (default: stderr)
+
+**--log-level**="": set logging level (default: info)
+
+**--nocolor**: disable colored debug output, only has effect if pretty output is set too
+
+**--pretty**: enable pretty-printed debug output
+
+**--server, -s**="": server address
+
+**--token, -t**="": server auth token
+
+# COMMANDS
+
+## admin
+
+administer server settings
+
+### registry
+
+manage global registries
+
+#### add
+
+adds a registry
+
+**--hostname**="": registry hostname (default: docker.io)
+
+**--password**="": registry password
+
+**--username**="": registry username
+
+#### rm
+
+remove a registry
+
+**--hostname**="": registry hostname (default: docker.io)
+
+#### update
+
+update a registry
+
+**--hostname**="": registry hostname (default: docker.io)
+
+**--organization, --org**="": organization id or full name (e.g. 123 or octocat)
+
+**--password**="": registry password
+
+**--username**="": registry username
+
+#### info
+
+display registry info
+
+**--hostname**="": registry hostname (default: docker.io)
+
+#### ls
+
+list registries
+
+## org
+
+manage organizations
+
+### registry
+
+manage organization registries
+
+#### add
+
+adds a registry
+
+**--hostname**="": registry hostname (default: docker.io)
+
+**--organization, --org**="": organization id or full name (e.g. 123 or octocat)
+
+**--password**="": registry password
+
+**--username**="": registry username
+
+#### rm
+
+remove a registry
+
+**--hostname**="": registry hostname (default: docker.io)
+
+**--organization, --org**="": organization id or full name (e.g. 123 or octocat)
+
+#### update
+
+update a registry
+
+**--hostname**="": registry hostname (default: docker.io)
+
+**--organization, --org**="": organization id or full name (e.g. 123 or octocat)
+
+**--password**="": registry password
+
+**--username**="": registry username
+
+#### info
+
+display registry info
+
+**--hostname**="": registry hostname (default: docker.io)
+
+**--organization, --org**="": organization id or full name (e.g. 123 or octocat)
+
+#### ls
+
+list registries
+
+**--organization, --org**="": organization id or full name (e.g. 123 or octocat)
+
+## repo
+
+manage repositories
+
+### ls
+
+list all repos
+
+**--format**="": format output (default: [33m{{ .FullName }}[0m (id: {{ .ID }}, forgeRemoteID: {{ .ForgeRemoteID }}))
+
+**--org**="": filter by organization
+
+### info
+
+show repository details
+
+**--format**="": format output (default: Owner: {{ .Owner }}
+Repo: {{ .Name }}
+URL: {{ .ForgeURL }}
+Config path: {{ .Config }}
+Visibility: {{ .Visibility }}
+Private: {{ .IsSCMPrivate }}
+Trusted: {{ .IsTrusted }}
+Gated: {{ .IsGated }}
+Clone url: {{ .Clone }}
+Allow pull-requests: {{ .AllowPullRequests }}
+)
+
+### add
+
+add a repository
+
+### update
+
+update a repository
+
+**--config**="": repository configuration path (e.g. .woodpecker.yml)
+
+**--gated**: repository is gated
+
+**--pipeline-counter**="": repository starting pipeline number (default: 0)
+
+**--timeout**="": repository timeout (default: 0s)
+
+**--trusted**: repository is trusted
+
+**--unsafe**: validate updating the pipeline-counter is unsafe
+
+**--visibility**="": repository visibility
+
+### rm
+
+remove a repository
+
+### repair
+
+repair repository webhooks
+
+### chown
+
+assume ownership of a repository
+
+### sync
+
+synchronize the repository list
+
+**--format**="": format output (default: [33m{{ .FullName }}[0m (id: {{ .ID }}, forgeRemoteID: {{ .ForgeRemoteID }}))
+
+### registry
+
+manage registries
+
+#### add
+
+adds a registry
+
+**--hostname**="": registry hostname (default: docker.io)
+
+**--password**="": registry password
+
+**--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world)
+
+**--username**="": registry username
+
+#### rm
+
+remove a registry
+
+**--hostname**="": registry hostname (default: docker.io)
+
+**--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world)
+
+#### update
+
+update a registry
+
+**--hostname**="": registry hostname (default: docker.io)
+
+**--password**="": registry password
+
+**--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world)
+
+**--username**="": registry username
+
+#### info
+
+display registry info
+
+**--hostname**="": registry hostname (default: docker.io)
+
+**--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world)
+
+#### ls
+
+list registries
+
+**--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world)
+
+## pipeline
+
+manage pipelines
+
+### ls
+
+show pipeline history
+
+**--branch**="": branch filter
+
+**--event**="": event filter
+
+**--limit**="": limit the list size (default: 25)
+
+**--output**="": output format (default: table)
+
+**--output-no-headers**: don't print headers
+
+**--status**="": status filter
+
+### last
+
+show latest pipeline details
+
+**--branch**="": branch name (default: main)
+
+**--output**="": output format (default: table)
+
+**--output-no-headers**: don't print headers
+
+### logs
+
+show pipeline logs
+
+### info
+
+show pipeline details
+
+**--output**="": output format (default: table)
+
+**--output-no-headers**: don't print headers
+
+### stop
+
+stop a pipeline
+
+### start
+
+start a pipeline
+
+**--param, -p**="": custom parameters to be injected into the step environment. Format: KEY=value (default: [])
+
+### approve
+
+approve a pipeline
+
+### decline
+
+decline a pipeline
+
+### queue
+
+show pipeline queue
+
+**--format**="": format output (default: [33m{{ .FullName }} #{{ .Number }} [0m
+Status: {{ .Status }}
+Event: {{ .Event }}
+Commit: {{ .Commit }}
+Branch: {{ .Branch }}
+Ref: {{ .Ref }}
+Author: {{ .Author }} {{ if .Email }}<{{.Email}}>{{ end }}
+Message: {{ .Message }}
+)
+
+### ps
+
+show pipeline steps
+
+**--format**="": format output (default: [33m{{ .workflow.Name }} > {{ .step.Name }} (#{{ .step.PID }}):[0m
+Step: {{ .step.Name }}
+Started: {{ .step.Started }}
+Stopped: {{ .step.Stopped }}
+Type: {{ .step.Type }}
+State: {{ .step.State }}
+)
+
+### create
+
+create new pipeline
+
+**--branch**="": branch to create pipeline from
+
+**--output**="": output format (default: table)
+
+**--output-no-headers**: don't print headers
+
+**--var**="": key=value (default: [])
+
+## log
+
+manage logs
+
+### purge
+
+purge a log
+
+## deploy
+
+trigger a pipeline with the 'deployment' event
+
+**--branch**="": branch filter
+
+**--event**="": event filter (default: push)
+
+**--format**="": format output (default: Number: {{ .Number }}
+Status: {{ .Status }}
+Commit: {{ .Commit }}
+Branch: {{ .Branch }}
+Ref: {{ .Ref }}
+Message: {{ .Message }}
+Author: {{ .Author }}
+Target: {{ .Deploy }}
+)
+
+**--param, -p**="": custom parameters to be injected into the step environment. Format: KEY=value (default: [])
+
+**--status**="": status filter (default: success)
+
+## exec
+
+execute a local pipeline
+
+**--backend-docker-api-version**="": the version of the API to reach, leave empty for latest.
+
+**--backend-docker-cert**="": path to load the TLS certificates for connecting to docker server
+
+**--backend-docker-host**="": path to docker socket or url to the docker server
+
+**--backend-docker-ipv6**: backend docker enable IPV6
+
+**--backend-docker-network**="": backend docker network
+
+**--backend-docker-tls-verify**: enable or disable TLS verification for connecting to docker server
+
+**--backend-docker-volumes**="": backend docker volumes (comma separated)
+
+**--backend-engine**="": backend engine to run pipelines on (default: auto-detect)
+
+**--backend-http-proxy**="": if set, pass the environment variable down as "HTTP_PROXY" to steps
+
+**--backend-https-proxy**="": if set, pass the environment variable down as "HTTPS_PROXY" to steps
+
+**--backend-k8s-allow-native-secrets**: whether to allow existing Kubernetes secrets to be referenced from steps
+
+**--backend-k8s-namespace**="": backend k8s namespace (default: woodpecker)
+
+**--backend-k8s-pod-annotations**="": backend k8s additional Agent-wide worker pod annotations
+
+**--backend-k8s-pod-annotations-allow-from-step**: whether to allow using annotations from step's backend options
+
+**--backend-k8s-pod-image-pull-secret-names**="": backend k8s pull secret names for private registries (default: [regcred])
+
+**--backend-k8s-pod-labels**="": backend k8s additional Agent-wide worker pod labels
+
+**--backend-k8s-pod-labels-allow-from-step**: whether to allow using labels from step's backend options
+
+**--backend-k8s-pod-node-selector**="": backend k8s Agent-wide worker pod node selector
+
+**--backend-k8s-secctx-nonroot**: `run as non root` Kubernetes security context option
+
+**--backend-k8s-storage-class**="": backend k8s storage class
+
+**--backend-k8s-storage-rwx**: backend k8s storage access mode, should ReadWriteMany (RWX) instead of ReadWriteOnce (RWO) be used? (default: true)
+
+**--backend-k8s-volume-size**="": backend k8s volume size (default 10G) (default: 10G)
+
+**--backend-local-temp-dir**="": set a different temp dir to clone workflows into (default: /tmp/nix-shell.kGX6ZV)
+
+**--backend-no-proxy**="": if set, pass the environment variable down as "NO_PROXY" to steps
+
+**--commit-author-avatar**="":
+
+**--commit-author-email**="":
+
+**--commit-author-name**="":
+
+**--commit-branch**="":
+
+**--commit-message**="":
+
+**--commit-ref**="":
+
+**--commit-refspec**="":
+
+**--commit-sha**="":
+
+**--env**="": (default: [])
+
+**--forge-type**="":
+
+**--forge-url**="":
+
+**--local**: run from local directory
+
+**--netrc-machine**="":
+
+**--netrc-password**="":
+
+**--netrc-username**="":
+
+**--network**="": external networks (default: [])
+
+**--pipeline-created**="": (default: 0)
+
+**--pipeline-deploy-task**="":
+
+**--pipeline-deploy-to**="":
+
+**--pipeline-event**="": (default: manual)
+
+**--pipeline-finished**="": (default: 0)
+
+**--pipeline-number**="": (default: 0)
+
+**--pipeline-parent**="": (default: 0)
+
+**--pipeline-started**="": (default: 0)
+
+**--pipeline-status**="":
+
+**--pipeline-url**="":
+
+**--prev-commit-author-avatar**="":
+
+**--prev-commit-author-email**="":
+
+**--prev-commit-author-name**="":
+
+**--prev-commit-branch**="":
+
+**--prev-commit-message**="":
+
+**--prev-commit-ref**="":
+
+**--prev-commit-refspec**="":
+
+**--prev-commit-sha**="":
+
+**--prev-pipeline-created**="": (default: 0)
+
+**--prev-pipeline-event**="":
+
+**--prev-pipeline-finished**="": (default: 0)
+
+**--prev-pipeline-number**="": (default: 0)
+
+**--prev-pipeline-started**="": (default: 0)
+
+**--prev-pipeline-status**="":
+
+**--prev-pipeline-url**="":
+
+**--privileged**="": privileged plugins (default: [plugins/docker plugins/gcr plugins/ecr woodpeckerci/plugin-docker-buildx codeberg.org/woodpecker-plugins/docker-buildx])
+
+**--repo**="": full repo name
+
+**--repo-clone-ssh-url**="":
+
+**--repo-clone-url**="":
+
+**--repo-path**="": path to local repository
+
+**--repo-private**="":
+
+**--repo-remote-id**="":
+
+**--repo-trusted**:
+
+**--repo-url**="":
+
+**--step-name**="": (default: 0)
+
+**--system-name**="": (default: woodpecker)
+
+**--system-platform**="":
+
+**--system-url**="": (default: https://github.com/woodpecker-ci/woodpecker)
+
+**--timeout**="": pipeline timeout (default: 1h0m0s)
+
+**--volumes**="": pipeline volumes (default: [])
+
+**--workflow-name**="": (default: 0)
+
+**--workflow-number**="": (default: 0)
+
+**--workspace-base**="": (default: /woodpecker)
+
+**--workspace-path**="": (default: src)
+
+## info
+
+show information about the current user
+
+## registry
+
+manage registries
+
+### add
+
+adds a registry
+
+**--hostname**="": registry hostname (default: docker.io)
+
+**--password**="": registry password
+
+**--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world)
+
+**--username**="": registry username
+
+### rm
+
+remove a registry
+
+**--hostname**="": registry hostname (default: docker.io)
+
+**--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world)
+
+### update
+
+update a registry
+
+**--hostname**="": registry hostname (default: docker.io)
+
+**--password**="": registry password
+
+**--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world)
+
+**--username**="": registry username
+
+### info
+
+display registry info
+
+**--hostname**="": registry hostname (default: docker.io)
+
+**--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world)
+
+### ls
+
+list registries
+
+**--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world)
+
+## secret
+
+manage secrets
+
+### add
+
+adds a secret
+
+**--event**="": secret limited to these events (default: [])
+
+**--global**: global secret
+
+**--image**="": secret limited to these images (default: [])
+
+**--name**="": secret name
+
+**--organization, --org**="": organization id or full name (e.g. 123 or octocat)
+
+**--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world)
+
+**--value**="": secret value
+
+### rm
+
+remove a secret
+
+**--global**: global secret
+
+**--name**="": secret name
+
+**--organization, --org**="": organization id or full name (e.g. 123 or octocat)
+
+**--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world)
+
+### update
+
+update a secret
+
+**--event**="": secret limited to these events (default: [])
+
+**--global**: global secret
+
+**--image**="": secret limited to these images (default: [])
+
+**--name**="": secret name
+
+**--organization, --org**="": organization id or full name (e.g. 123 or octocat)
+
+**--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world)
+
+**--value**="": secret value
+
+### info
+
+display secret info
+
+**--global**: global secret
+
+**--name**="": secret name
+
+**--organization, --org**="": organization id or full name (e.g. 123 or octocat)
+
+**--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world)
+
+### ls
+
+list secrets
+
+**--global**: global secret
+
+**--organization, --org**="": organization id or full name (e.g. 123 or octocat)
+
+**--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world)
+
+## user
+
+manage users
+
+### ls
+
+list all users
+
+**--format**="": format output (default: {{ .Login }})
+
+### info
+
+show user details
+
+**--format**="": format output (default: User: {{ .Login }}
+Email: {{ .Email }})
+
+### add
+
+adds a user
+
+### rm
+
+remove a user
+
+## lint
+
+lint a pipeline configuration file
+
+## log-level
+
+get the logging level of the server, or set it with [level]
+
+## cron
+
+manage cron jobs
+
+### add
+
+add a cron job
+
+**--branch**="": cron branch
+
+**--name**="": cron name
+
+**--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world)
+
+**--schedule**="": cron schedule
+
+### rm
+
+remove a cron job
+
+**--id**="": cron id
+
+**--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world)
+
+### update
+
+update a cron job
+
+**--branch**="": cron branch
+
+**--id**="": cron id
+
+**--name**="": cron name
+
+**--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world)
+
+**--schedule**="": cron schedule
+
+### info
+
+display info about a cron job
+
+**--id**="": cron id
+
+**--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world)
+
+### ls
+
+list cron jobs
+
+**--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world)
+
+## setup
+
+setup the woodpecker-cli for the first time
+
+**--server**="": The URL of the woodpecker server
+
+**--token**="": The token to authenticate with the woodpecker server
+
+## update
+
+update the woodpecker-cli to the latest version
+
+**--force**: force update even if the latest version is already installed
diff --git a/docs/versioned_docs/version-2.7/50-about.md b/docs/versioned_docs/version-2.7/50-about.md
new file mode 100644
index 000000000..bec3304a1
--- /dev/null
+++ b/docs/versioned_docs/version-2.7/50-about.md
@@ -0,0 +1,18 @@
+# About
+
+Woodpecker has been originally forked from Drone 0.8 as the Drone CI license was changed after the 0.8 release from Apache 2.0 to a proprietary license. Woodpecker is based on this latest freely available version.
+
+## History
+
+Woodpecker was originally forked by [@laszlocph](https://github.com/laszlocph) in 2019.
+
+A few important time points:
+
+- [`2fbaa56`](https://github.com/woodpecker-ci/woodpecker/commit/2fbaa56eee0f4be7a3ca4be03dbd00c1bf5d1274) is the first commit of the fork, made on Apr 3, 2019.
+- The first release [v0.8.91](https://github.com/woodpecker-ci/woodpecker/releases/tag/v0.8.91) was published on Apr 6, 2019.
+- On Aug 27, 2019, the project was renamed to "Woodpecker" ([`630c383`](https://github.com/woodpecker-ci/woodpecker/commit/630c383181b10c4ec375e500c812c4b76b3c52b8)).
+- The first release under the name "Woodpecker" was published on Sep 9, 2019 ([v0.8.104](https://github.com/woodpecker-ci/woodpecker/releases/tag/v0.8.104)).
+
+## Differences to Drone
+
+Woodpecker is a community-focused software that still stay free and open source forever, while Drone is managed by [Harness](https://harness.io/) and published under [Polyform Small Business](https://polyformproject.org/licenses/small-business/1.0.0/) license.
diff --git a/docs/versioned_docs/version-2.4/91-migrations.md b/docs/versioned_docs/version-2.7/91-migrations.md
similarity index 92%
rename from docs/versioned_docs/version-2.4/91-migrations.md
rename to docs/versioned_docs/version-2.7/91-migrations.md
index 9b6fa8854..84a79ac5e 100644
--- a/docs/versioned_docs/version-2.4/91-migrations.md
+++ b/docs/versioned_docs/version-2.7/91-migrations.md
@@ -2,6 +2,13 @@
Some versions need some changes to the server configuration or the pipeline configuration files.
+
+
## `next`
- Deprecated `steps.[name].group` in favor of `steps.[name].depends_on` (see [workflow syntax](./20-usage/20-workflow-syntax.md#depends_on) to learn how to set dependencies)
@@ -11,6 +18,9 @@ Some versions need some changes to the server configuration or the pipeline conf
- Deprecated uppercasing all secret env vars, instead, the value of the `secrets` property is used. [Read more](./20-usage/40-secrets.md#use-secrets-in-commands)
- Deprecated alternative names for secrets, use `environment` with `from_secret`
- Deprecated slice definition for env vars
+- Deprecated `environment` filter, use `when.evaluate`
+- Use `WOODPECKER_EXPERT_FORGE_OAUTH_HOST` instead of `WOODPECKER_DEV_GITEA_OAUTH_URL` or `WOODPECKER_DEV_OAUTH_HOST`
+- Deprecated `WOODPECKER_WEBHOOK_HOST` in favor of `WOODPECKER_EXPERT_WEBHOOK_HOST`
## 2.0.0
@@ -27,7 +37,7 @@ Some versions need some changes to the server configuration or the pipeline conf
## 1.0.0
-- The signature used to verify extension calls (like those used for the [config-extension](./30-administration/100-external-configuration-api.md)) done by the Woodpecker server switched from using a shared-secret HMac to an ed25519 key-pair. Read more about it at the [config-extensions](./30-administration/100-external-configuration-api.md) documentation.
+- The signature used to verify extension calls (like those used for the [config-extension](./30-administration/40-advanced/100-external-configuration-api.md)) done by the Woodpecker server switched from using a shared-secret HMac to an ed25519 key-pair. Read more about it at the [config-extensions](./30-administration/40-advanced/100-external-configuration-api.md) documentation.
- Refactored support for old agent filter labels and expressions. Learn how to use the new [filter](./20-usage/20-workflow-syntax.md#labels)
- Renamed step environment variable `CI_SYSTEM_ARCH` to `CI_SYSTEM_PLATFORM`. Same applies for the cli exec variable.
- Renamed environment variables `CI_BUILD_*` and `CI_PREV_BUILD_*` to `CI_PIPELINE_*` and `CI_PREV_PIPELINE_*`, old ones are still available but deprecated
@@ -66,7 +76,7 @@ Some versions need some changes to the server configuration or the pipeline conf
Only projects created after updating will have an empty value by default. Existing projects will stick to the current pipeline path which is `.drone.yml` in most cases.
- Read more about it at the [Project Settings](./20-usage/71-project-settings.md#pipeline-path)
+ Read more about it at the [Project Settings](./20-usage/75-project-settings.md#pipeline-path)
- From version `0.15.0` ongoing there will be three types of docker images: `latest`, `next` and `x.x.x` with an alpine variant for each type like `latest-alpine`.
If you used `latest` before to try pre-release features you should switch to `next` after this release.
diff --git a/docs/versioned_docs/version-2.4/92-awesome.md b/docs/versioned_docs/version-2.7/92-awesome.md
similarity index 83%
rename from docs/versioned_docs/version-2.4/92-awesome.md
rename to docs/versioned_docs/version-2.7/92-awesome.md
index b13862209..920341d33 100644
--- a/docs/versioned_docs/version-2.4/92-awesome.md
+++ b/docs/versioned_docs/version-2.7/92-awesome.md
@@ -1,6 +1,6 @@
# Awesome Woodpecker
-A curated list of awesome things related to Woodpecker-CI.
+A curated list of awesome things related to Woodpecker CI.
If you have some missing resources, please feel free to [open a pull-request](https://github.com/woodpecker-ci/woodpecker/edit/main/docs/docs/92-awesome.md) and add them.
@@ -14,7 +14,7 @@ If you have some missing resources, please feel free to [open a pull-request](ht
## Projects using Woodpecker
-- [Woodpecker-CI](https://github.com/woodpecker-ci/woodpecker/tree/main/.woodpecker) itself
+- [Woodpecker CI](https://github.com/woodpecker-ci/woodpecker/tree/main/.woodpecker) itself
- [All official plugins](https://github.com/woodpecker-ci?q=plugin&type=all)
- [dessalines/thumb-key](https://github.com/dessalines/thumb-key/blob/main/.woodpecker.yml) - Android Jetpack compose linting and building
- [Vieter](https://git.rustybever.be/vieter-v/vieter) - Archlinux/Pacman repository server & automated package build system
@@ -24,12 +24,12 @@ If you have some missing resources, please feel free to [open a pull-request](ht
## Tools
- [Convert Drone CI pipelines to Woodpecker CI](https://codeberg.org/lafriks/woodpecker-pipeline-transform)
-- [Ansible NAS](https://github.com/davestephens/ansible-nas/) - a homelab Ansible playbook that can set up Woodpecker-CI and Gitea
+- [Ansible NAS](https://github.com/davestephens/ansible-nas/) - a homelab Ansible playbook that can set up Woodpecker CI and Gitea
- [picus](https://github.com/windsource/picus) - Picus connects to a Woodpecker CI server and creates an agent in the cloud when there are pending workflows.
- [Hetzner cloud](https://www.hetzner.com/cloud) based [Woodpecker compatible autoscaler](https://git.ljoonal.xyz/ljoonal/hetzner-ci-autoscaler) - Creates and destroys VPS instances based on the count of pending & running jobs.
-- [woodpecker-lint](https://git.schmidl.dev/schtobia/woodpecker-lint) - A repository for linting a woodpecker config file via pre-commit hook
-- [Grafana Dashboard](https://github.com/Janik-Haag/woodpecker-grafana-dashboard) - A dashboard visualizing information exposed by the woodpecker prometheus endpoint.
-- [woodpecker-autoscaler](https://github.com/Lerentis/woodpecker-autoscaler) - Yet another woodpecker autoscaler currently targeting [Hetzner cloud](https://www.hetzner.com/cloud) that works in parallel to other autoscaler implementations.
+- [woodpecker-lint](https://git.schmidl.dev/schtobia/woodpecker-lint) - A repository for linting a Woodpecker config file via pre-commit hook
+- [Grafana Dashboard](https://github.com/Janik-Haag/woodpecker-grafana-dashboard) - A dashboard visualizing information exposed by the Woodpecker prometheus endpoint.
+- [woodpecker-autoscaler](https://github.com/Lerentis/woodpecker-autoscaler) - Yet another Woodpecker autoscaler currently targeting [Hetzner cloud](https://www.hetzner.com/cloud) that works in parallel to other autoscaler implementations.
## Configuration Services
@@ -50,8 +50,11 @@ If you have some missing resources, please feel free to [open a pull-request](ht
- [Locally Cached Nix CI with Woodpecker](https://blog.kotatsu.dev/posts/2023-04-21-woodpecker-nix-caching/)
- [How to run Cypress auto-tests on Woodpecker CI and report results to Slack](https://devforth.io/blog/how-to-run-cypress-auto-tests-on-woodpecker-ci-and-report-results-to-slack/)
- [Quest For CICD - WoodpeckerCI](https://omaramin.me/posts/woodpecker/)
-- [Getting started with Woodpecker CI](https://blog.lutra-it.eu/getting-started-with-woodpecker-ci.html)
+- [Getting started with Woodpecker CI](https://systeemkabouter.eu/getting-started-with-woodpecker-ci.html)
- [Installing gitea and woodpecker using binary packages](https://neelex.com/2023/03/26/Installing-gitea-using-binary-packages/)
+- [Deploying mdbook to codeberg pages using woodpecker CI](https://www.markpitblado.me/blog/deploying-mdbook-to-codeberg-pages-using-woodpecker-ci/)
+- [Deploy a Fly app with Woodpecker CI](https://joeroe.io/2024/01/09/deploy-fly-woodpecker-ci.html)
+- [Ansible - using Woodpecker as an alternative to Semaphore](https://pat-s.me/ansible-using-woodpecker-as-an-alternative-to-semaphore/)
## Videos
diff --git a/docs/versioned_docs/version-2.4/92-development/01-getting-started.md b/docs/versioned_docs/version-2.7/92-development/01-getting-started.md
similarity index 97%
rename from docs/versioned_docs/version-2.4/92-development/01-getting-started.md
rename to docs/versioned_docs/version-2.7/92-development/01-getting-started.md
index 0889afa5b..255b92a48 100644
--- a/docs/versioned_docs/version-2.4/92-development/01-getting-started.md
+++ b/docs/versioned_docs/version-2.7/92-development/01-getting-started.md
@@ -46,7 +46,7 @@ To apply it during local development, take a look at [`pre-commit`s documentatio
### Create a `.env` file with your development configuration
-Similar to the environment variables you can set for your production setup of Woodpecker, you can create a `.env` in the root of the Woodpecker project and add any need config to it.
+Similar to the environment variables you can set for your production setup of Woodpecker, you can create a `.env` file in the root of the Woodpecker project and add any needed config to it.
A common config for debugging would look like this:
@@ -82,7 +82,7 @@ WOODPECKER_HEALTHCHECK=false
### Setup OAuth
-Create an OAuth app for your forge as described in the [forges documentation](../30-administration/11-forges/10-overview.md). If you set `WOODPECKER_DEV_OAUTH_HOST=http://localhost:8000` you can use that address with the path as explained for the specific forge to login without the need for a public address. For example for GitHub you would use `http://localhost:8000/authorize` as authorization callback URL.
+Create an OAuth app for your forge as described in the [forges documentation](../30-administration/11-forges/11-overview.md). If you set `WOODPECKER_DEV_OAUTH_HOST=http://localhost:8000` you can use that address with the path as explained for the specific forge to login without the need for a public address. For example for GitHub you would use `http://localhost:8000/authorize` as authorization callback URL.
## Developing with VS Code
diff --git a/docs/versioned_docs/version-2.4/92-development/02-core-ideas.md b/docs/versioned_docs/version-2.7/92-development/02-core-ideas.md
similarity index 87%
rename from docs/versioned_docs/version-2.4/92-development/02-core-ideas.md
rename to docs/versioned_docs/version-2.7/92-development/02-core-ideas.md
index c4527e6c7..a88470f0a 100644
--- a/docs/versioned_docs/version-2.4/92-development/02-core-ideas.md
+++ b/docs/versioned_docs/version-2.7/92-development/02-core-ideas.md
@@ -8,7 +8,7 @@
## Addons and extensions
If you are wondering whether your contribution will be accepted to be merged in the Woodpecker core, or whether it's better to write an
-[addon](../30-administration/75-addons/00-overview.md), [extension](../30-administration/100-external-configuration-api.md) or an
+[addon forge](../30-administration/11-forges/100-addon.md), [extension](../30-administration/40-advanced/100-external-configuration-api.md) or an
[external custom backend](../30-administration/22-backends/50-custom-backends.md), please check these points:
- Is your change very specific to your setup and unlikely to be used by anyone else?
diff --git a/docs/versioned_docs/version-2.4/92-development/03-ui.md b/docs/versioned_docs/version-2.7/92-development/03-ui.md
similarity index 98%
rename from docs/versioned_docs/version-2.4/92-development/03-ui.md
rename to docs/versioned_docs/version-2.7/92-development/03-ui.md
index e8999b0be..6a01584c2 100644
--- a/docs/versioned_docs/version-2.4/92-development/03-ui.md
+++ b/docs/versioned_docs/version-2.7/92-development/03-ui.md
@@ -36,4 +36,4 @@ The following list contains some tools and frameworks used by the Woodpecker UI.
Woodpecker uses [Vue I18n](https://vue-i18n.intlify.dev/) as translation library. New translations have to be added to `web/src/assets/locales/en.json`. The English source file will be automatically imported into [Weblate](https://translate.woodpecker-ci.org/) (the translation system used by Woodpecker) where all other languages will be translated by the community based on the English source.
You must not provide translations except English in PRs, otherwise weblate could put git into conflicts (when someone has translated in that language file and changes are not into main branch yet)
-For more information about translations see [Translations](./07-translations.md).
+For more information about translations see [Translations](./08-translations.md).
diff --git a/docs/versioned_docs/version-2.4/92-development/04-docs.md b/docs/versioned_docs/version-2.7/92-development/04-docs.md
similarity index 100%
rename from docs/versioned_docs/version-2.4/92-development/04-docs.md
rename to docs/versioned_docs/version-2.7/92-development/04-docs.md
diff --git a/docs/versioned_docs/version-2.4/92-development/05-architecture.md b/docs/versioned_docs/version-2.7/92-development/05-architecture.md
similarity index 95%
rename from docs/versioned_docs/version-2.4/92-development/05-architecture.md
rename to docs/versioned_docs/version-2.7/92-development/05-architecture.md
index ccfd410f3..2d032ca8a 100644
--- a/docs/versioned_docs/version-2.4/92-development/05-architecture.md
+++ b/docs/versioned_docs/version-2.7/92-development/05-architecture.md
@@ -21,12 +21,12 @@
| package | meaning | imports |
| -------------------- | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `server/api/**` | handle web requests from `server/router` | `pipeline`, `../badges`, `../ccmenue`, `../logging`, `../model`, `../pubsub`, `../queue`, `../forge`, `../shared`, `../store`, `shared`, (TODO: mv `server/router/middleware/session`) |
+| `server/api/**` | handle web requests from `server/router` | `pipeline`, `../badges`, `../ccmenu`, `../logging`, `../model`, `../pubsub`, `../queue`, `../forge`, `../shared`, `../store`, `shared`, (TODO: mv `server/router/middleware/session`) |
| `server/badges/**` | generate svg badges for pipelines | `../model` |
| `server/ccmenu/**` | generate xml ccmenu for pipelines | `../model` |
| `server/grpc/**` | gRPC server agents can connect to | `pipeline/rpc/**`, `../logging`, `../model`, `../pubsub`, `../queue`, `../forge`, `../pipeline`, `../store` |
| `server/logging/**` | logging lib for gPRC server to stream logs while running | std |
-| `server/model/**` | structs for store (db) and api (json) | std |
+| `server/model/**` | structs for store (db) and api (json) | std |
| `server/plugins/**` | plugins for server | `../model`, `../forge` |
| `server/pipeline/**` | orchestrate pipelines | `pipeline`, `../model`, `../pubsub`, `../queue`, `../forge`, `../store`, `../plugins` |
| `server/pubsub/**` | pubsub lib for server to push changes to the WebUI | std |
diff --git a/docs/versioned_docs/version-2.7/92-development/06-conventions.md b/docs/versioned_docs/version-2.7/92-development/06-conventions.md
new file mode 100644
index 000000000..e94a90c43
--- /dev/null
+++ b/docs/versioned_docs/version-2.7/92-development/06-conventions.md
@@ -0,0 +1,7 @@
+# Conventions
+
+## Database naming
+
+Database tables are named plural, columns don't have any prefix.
+
+Example: Table name `agent`, columns `id`, `name`.
diff --git a/docs/versioned_docs/version-2.4/92-development/06-guides.md b/docs/versioned_docs/version-2.7/92-development/07-guides.md
similarity index 92%
rename from docs/versioned_docs/version-2.4/92-development/06-guides.md
rename to docs/versioned_docs/version-2.7/92-development/07-guides.md
index e8db28a53..c70a9ec93 100644
--- a/docs/versioned_docs/version-2.4/92-development/06-guides.md
+++ b/docs/versioned_docs/version-2.7/92-development/07-guides.md
@@ -3,7 +3,6 @@
## ORM
Woodpecker uses [Xorm](https://xorm.io/) as ORM for the database connection.
-You can find its documentation at [gobook.io/read/gitea.com/xorm](https://gobook.io/read/gitea.com/xorm/manual-en-US/).
## Add a new migration
diff --git a/docs/versioned_docs/version-2.4/92-development/07-translations.md b/docs/versioned_docs/version-2.7/92-development/08-translations.md
similarity index 100%
rename from docs/versioned_docs/version-2.4/92-development/07-translations.md
rename to docs/versioned_docs/version-2.7/92-development/08-translations.md
diff --git a/docs/versioned_docs/version-2.4/92-development/08-swagger.md b/docs/versioned_docs/version-2.7/92-development/09-swagger.md
similarity index 94%
rename from docs/versioned_docs/version-2.4/92-development/08-swagger.md
rename to docs/versioned_docs/version-2.7/92-development/09-swagger.md
index 9a3775c41..5bf303c7b 100644
--- a/docs/versioned_docs/version-2.4/92-development/08-swagger.md
+++ b/docs/versioned_docs/version-2.7/92-development/09-swagger.md
@@ -7,7 +7,7 @@ and then being using on the community's website documentation.
It's paramount important to keep the gin handler function's godoc documentation up-to-date,
to always have accurate API documentation.
-Whenever you change, add or enhance an API endpoint, please update the godocs.
+Whenever you change, add or enhance an API endpoint, please update the godoc.
You don't require any extra tools on your machine, all Swagger tooling is automatically fetched by standard Go tools.
@@ -41,8 +41,8 @@ These guidelines aim to have consistent wording in the swagger doc:
- first word after `@Summary` and `@Summary` are always uppercase
- `@Summary` has no `.` (dot) at the end of the line
- model structs shall use custom short names, to ease life for API consumers, using `@name`
-- `@Success` object or array declarations shall be short, this means the actual `model.User` struct must have a `@name` annotation, so that the model can be renderend in Swagger
-- when pagination is used, `@Parame page` and `@Parame perPage` must be added manually
+- `@Success` object or array declarations shall be short, this means the actual `model.User` struct must have a `@name` annotation, so that the model can be rendered in Swagger
+- when pagination is used, `@Param page` and `@Param perPage` must be added manually
- `@Param Authorization` is almost always present, there are just a few un-protected endpoints
There are many examples in the `server/api` package, which you can use a blueprint.
diff --git a/docs/versioned_docs/version-2.7/92-development/09-testing.md b/docs/versioned_docs/version-2.7/92-development/09-testing.md
new file mode 100644
index 000000000..b5b8ed2f2
--- /dev/null
+++ b/docs/versioned_docs/version-2.7/92-development/09-testing.md
@@ -0,0 +1,81 @@
+# Testing
+
+## Backend
+
+### Unit Tests
+
+[We use default golang unit tests](https://go.dev/doc/tutorial/add-a-test)
+with [`"github.com/stretchr/testify/assert"`](https://pkg.go.dev/github.com/stretchr/testify@v1.9.0/assert) to simplify testing.
+
+### Integration Tests
+
+### Dummy backend
+
+There is a special backend called **`dummy`** which does not execute any commands, but emulates how a typical backend should behave.
+To enable it you need to build the agent or cli with the `test` build tag.
+
+An example pipeline config would be:
+
+```yaml
+when:
+ event: manual
+
+steps:
+ - name: echo
+ image: dummy
+ commands: echo "hello woodpecker"
+ environment:
+ SLEEP: '1s'
+
+services:
+ echo:
+ image: dummy
+ commands: echo "i am a service"
+```
+
+This could be executed via `woodpecker-cli --log-level trace exec --backend-engine dummy example.yaml`:
+
+```none
+9:18PM DBG pipeline/pipeline.go:94 > executing 2 stages, in order of: CLI=exec
+9:18PM DBG pipeline/pipeline.go:104 > stage CLI=exec StagePos=0 Steps=echo
+9:18PM DBG pipeline/pipeline.go:104 > stage CLI=exec StagePos=1 Steps=echo
+9:18PM TRC pipeline/backend/dummy/dummy.go:75 > create workflow environment taskUUID=01J10P578JQE6E25VV1EQF0745
+9:18PM DBG pipeline/pipeline.go:176 > prepare CLI=exec step=echo
+9:18PM DBG pipeline/pipeline.go:203 > executing CLI=exec step=echo
+9:18PM TRC pipeline/backend/dummy/dummy.go:81 > start step echo taskUUID=01J10P578JQE6E25VV1EQF0745
+9:18PM TRC pipeline/backend/dummy/dummy.go:167 > tail logs of step echo taskUUID=01J10P578JQE6E25VV1EQF0745
+9:18PM DBG pipeline/pipeline.go:209 > complete CLI=exec step=echo
+[echo:L0:0s] StepName: echo
+[echo:L1:0s] StepType: service
+[echo:L2:0s] StepUUID: 01J10P578JQE6E25VV1A2DNQN9
+[echo:L3:0s] StepCommands:
+[echo:L4:0s] ------------------
+[echo:L5:0s] echo ja
+[echo:L6:0s] ------------------
+[echo:L7:0s] 9:18PM DBG pipeline/pipeline.go:176 > prepare CLI=exec step=echo
+9:18PM DBG pipeline/pipeline.go:203 > executing CLI=exec step=echo
+9:18PM TRC pipeline/backend/dummy/dummy.go:81 > start step echo taskUUID=01J10P578JQE6E25VV1EQF0745
+9:18PM TRC pipeline/backend/dummy/dummy.go:167 > tail logs of step echo taskUUID=01J10P578JQE6E25VV1EQF0745
+[echo:L0:0s] StepName: echo
+[echo:L1:0s] StepType: commands
+[echo:L2:0s] StepUUID: 01J10P578JQE6E25VV1DFSXX1Y
+[echo:L3:0s] StepCommands:
+[echo:L4:0s] ------------------
+[echo:L5:0s] echo ja
+[echo:L6:0s] ------------------
+[echo:L7:0s] 9:18PM TRC pipeline/backend/dummy/dummy.go:108 > wait for step echo taskUUID=01J10P578JQE6E25VV1EQF0745
+9:18PM TRC pipeline/backend/dummy/dummy.go:187 > stop step echo taskUUID=01J10P578JQE6E25VV1EQF0745
+9:18PM DBG pipeline/pipeline.go:209 > complete CLI=exec step=echo
+9:18PM TRC pipeline/backend/dummy/dummy.go:208 > delete workflow environment taskUUID=01J10P578JQE6E25VV1EQF0745
+```
+
+There are also environment variables to alter step behavior:
+
+- `SLEEP: 10` will let the step wait 10 seconds
+- `EXPECT_TYPE` allows to check if a step is a `clone`, `service`, `plugin` or `commands`
+- `STEP_START_FAIL: true` if set will simulate a step to fail before actually being started (e.g. happens when the container image can not be pulled)
+- `STEP_TAIL_FAIL: true` if set will error when we simulate to read from stdout for logs
+- `STEP_EXIT_CODE: 2` if set will be used as exit code, default is 0
+- `STEP_OOM_KILLED: true` simulates a step being killed by memory constrains
+
+You can let the setup of a whole workflow fail by setting it's UUID to `WorkflowSetupShouldFail`.
diff --git a/docs/versioned_docs/version-2.4/92-development/_category_.yaml b/docs/versioned_docs/version-2.7/92-development/_category_.yaml
similarity index 100%
rename from docs/versioned_docs/version-2.4/92-development/_category_.yaml
rename to docs/versioned_docs/version-2.7/92-development/_category_.yaml
diff --git a/docs/versioned_docs/version-2.4/92-development/ui-proxy.svg b/docs/versioned_docs/version-2.7/92-development/ui-proxy.svg
similarity index 100%
rename from docs/versioned_docs/version-2.4/92-development/ui-proxy.svg
rename to docs/versioned_docs/version-2.7/92-development/ui-proxy.svg
diff --git a/docs/versioned_docs/version-2.4/92-development/vscode-debug.png b/docs/versioned_docs/version-2.7/92-development/vscode-debug.png
similarity index 100%
rename from docs/versioned_docs/version-2.4/92-development/vscode-debug.png
rename to docs/versioned_docs/version-2.7/92-development/vscode-debug.png
diff --git a/docs/versioned_docs/version-2.4/92-development/vscode-run-test.png b/docs/versioned_docs/version-2.7/92-development/vscode-run-test.png
similarity index 100%
rename from docs/versioned_docs/version-2.4/92-development/vscode-run-test.png
rename to docs/versioned_docs/version-2.7/92-development/vscode-run-test.png
diff --git a/docs/versioned_docs/version-2.4/92-development/woodpecker-architecture.png b/docs/versioned_docs/version-2.7/92-development/woodpecker-architecture.png
similarity index 100%
rename from docs/versioned_docs/version-2.4/92-development/woodpecker-architecture.png
rename to docs/versioned_docs/version-2.7/92-development/woodpecker-architecture.png
diff --git a/docs/versioned_docs/version-2.7/pipeline-list.png b/docs/versioned_docs/version-2.7/pipeline-list.png
new file mode 100644
index 000000000..f501fe0e6
Binary files /dev/null and b/docs/versioned_docs/version-2.7/pipeline-list.png differ
diff --git a/docs/docs/woodpecker.png b/docs/versioned_docs/version-2.7/woodpecker.png
similarity index 100%
rename from docs/docs/woodpecker.png
rename to docs/versioned_docs/version-2.7/woodpecker.png
diff --git a/docs/versioned_sidebars/version-2.4-sidebars.json b/docs/versioned_sidebars/version-2.7-sidebars.json
similarity index 100%
rename from docs/versioned_sidebars/version-2.4-sidebars.json
rename to docs/versioned_sidebars/version-2.7-sidebars.json
diff --git a/docs/versions.json b/docs/versions.json
index 317e4f49d..9d0c78ccf 100644
--- a/docs/versions.json
+++ b/docs/versions.json
@@ -1 +1 @@
-["2.6", "2.5", "2.4", "1.0"]
+["2.7", "2.6", "2.5", "1.0"]
diff --git a/docs/woodpecker.png b/docs/woodpecker.png
new file mode 100644
index 000000000..93b4d47af
Binary files /dev/null and b/docs/woodpecker.png differ
diff --git a/flake.lock b/flake.lock
index 606f8836c..5e1e2f16a 100644
--- a/flake.lock
+++ b/flake.lock
@@ -20,11 +20,11 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1717974879,
- "narHash": "sha256-GTO3C88+5DX171F/gVS3Qga/hOs/eRMxPFpiHq2t+D8=",
+ "lastModified": 1724224976,
+ "narHash": "sha256-Z/ELQhrSd7bMzTO8r7NZgi9g5emh+aRKoCdaAv5fiO0=",
"owner": "nixos",
"repo": "nixpkgs",
- "rev": "c7b821ba2e1e635ba5a76d299af62821cbcb09f3",
+ "rev": "c374d94f1536013ca8e92341b540eba4c22f9c62",
"type": "github"
},
"original": {
diff --git a/flake.nix b/flake.nix
index ac4faf064..79068d9aa 100644
--- a/flake.nix
+++ b/flake.nix
@@ -17,6 +17,8 @@
# generic
gnumake
gnutar
+ zip
+ tree
# frontend
nodejs_20
@@ -31,6 +33,7 @@
golangci-lint
go-mockery
protobuf
+ sqlite
];
CFLAGS = "-I${pkgs.glibc.dev}/include";
LDFLAGS = "-L${pkgs.glibc}/lib";
diff --git a/go.mod b/go.mod
index c5fe5c976..ea3ff92af 100644
--- a/go.mod
+++ b/go.mod
@@ -2,76 +2,78 @@ module go.woodpecker-ci.org/woodpecker/v2
go 1.22.0
-toolchain go1.22.3
+toolchain go1.23.0
require (
- code.gitea.io/sdk/gitea v0.18.0
+ al.essio.dev/pkg/shellescape v1.5.0
+ code.gitea.io/sdk/gitea v0.19.0
codeberg.org/6543/go-yaml2json v1.0.0
codeberg.org/6543/xyaml v1.1.0
- codeberg.org/mvdkleijn/forgejo-sdk/forgejo v0.0.0-20240607215151-168c988b82c1
+ codeberg.org/mvdkleijn/forgejo-sdk/forgejo v1.1.1
github.com/6543/logfile-open v1.2.1
- github.com/adrg/xdg v0.4.0
- github.com/alessio/shellescape v1.4.2
+ github.com/adrg/xdg v0.5.0
github.com/bmatcuk/doublestar/v4 v4.6.1
- github.com/caddyserver/certmagic v0.21.2
+ github.com/caddyserver/certmagic v0.21.3
github.com/cenkalti/backoff/v4 v4.3.0
- github.com/charmbracelet/huh v0.3.0
+ github.com/charmbracelet/huh v0.5.3
github.com/charmbracelet/huh/spinner v0.0.0-20240327025511-ec643317aa10
- github.com/distribution/reference v0.5.0
- github.com/docker/cli v24.0.9+incompatible
- github.com/docker/docker v24.0.9+incompatible
+ github.com/distribution/reference v0.6.0
+ github.com/docker/cli v27.1.2+incompatible
+ github.com/docker/docker v27.1.2+incompatible
github.com/docker/go-connections v0.5.0
github.com/docker/go-units v0.5.0
github.com/drone/envsubst v1.0.3
- github.com/expr-lang/expr v1.16.7
+ github.com/expr-lang/expr v1.16.9
github.com/franela/goblin v0.0.0-20211003143422-0a4f594942bf
github.com/fsnotify/fsnotify v1.7.0
+ github.com/gdgvda/cron v0.3.0
+ github.com/getkin/kin-openapi v0.127.0
github.com/gin-gonic/gin v1.10.0
- github.com/go-ap/httpsig v0.0.0-20221203064646-3647b4d88fdf
+ github.com/gitsight/go-vcsurl v1.0.1
github.com/go-sql-driver/mysql v1.8.1
github.com/golang-jwt/jwt/v5 v5.2.1
- github.com/google/go-github/v62 v62.0.0
+ github.com/google/go-github/v64 v64.0.0
github.com/google/tink/go v1.7.0
github.com/gorilla/securecookie v1.1.2
github.com/hashicorp/go-hclog v1.6.3
github.com/hashicorp/go-plugin v1.6.1
- github.com/jellydator/ttlcache/v3 v3.2.0
+ github.com/jellydator/ttlcache/v3 v3.2.1
github.com/joho/godotenv v1.5.1
github.com/kinbiko/jsonassert v1.1.1
github.com/lib/pq v1.10.9
github.com/mattn/go-sqlite3 v1.14.22
github.com/mitchellh/mapstructure v1.5.0
- github.com/moby/moby v24.0.9+incompatible
+ github.com/moby/moby v27.1.2+incompatible
github.com/moby/term v0.5.0
- github.com/muesli/termenv v0.15.2
+ github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a
github.com/neticdk/go-bitbucket v1.0.0
github.com/oklog/ulid/v2 v2.1.0
github.com/pkg/errors v0.9.1
- github.com/prometheus/client_golang v1.19.1
- github.com/robfig/cron v1.2.0
+ github.com/prometheus/client_golang v1.20.2
github.com/rs/zerolog v1.33.0
github.com/stretchr/testify v1.9.0
github.com/swaggo/files v1.0.1
github.com/swaggo/gin-swagger v1.6.0
github.com/swaggo/swag v1.16.3
- github.com/tevino/abool/v2 v2.1.0
- github.com/urfave/cli/v2 v2.27.2
- github.com/xanzy/go-gitlab v0.105.0
+ github.com/urfave/cli-docs/v3 v3.0.0-alpha5.0.20240714105325-1da00919bcb4
+ github.com/urfave/cli/v3 v3.0.0-alpha9.0.20240811205807-fc07a8c3673f
+ github.com/xanzy/go-gitlab v0.108.0
github.com/xeipuuv/gojsonschema v1.2.0
- github.com/zalando/go-keyring v0.2.4
+ github.com/yaronf/httpsign v0.3.1
+ github.com/zalando/go-keyring v0.2.5
go.uber.org/multierr v1.11.0
- golang.org/x/crypto v0.23.0
- golang.org/x/net v0.25.0
- golang.org/x/oauth2 v0.20.0
- golang.org/x/sync v0.7.0
- golang.org/x/term v0.20.0
- golang.org/x/text v0.15.0
- google.golang.org/grpc v1.64.0
- google.golang.org/protobuf v1.34.1
+ golang.org/x/crypto v0.26.0
+ golang.org/x/net v0.28.0
+ golang.org/x/oauth2 v0.22.0
+ golang.org/x/sync v0.8.0
+ golang.org/x/term v0.23.0
+ golang.org/x/text v0.17.0
+ google.golang.org/grpc v1.65.0
+ google.golang.org/protobuf v1.34.2
gopkg.in/yaml.v3 v3.0.1
- k8s.io/api v0.30.1
- k8s.io/apimachinery v0.30.1
- k8s.io/client-go v0.30.1
+ k8s.io/api v0.31.0
+ k8s.io/apimachinery v0.31.0
+ k8s.io/client-go v0.31.0
src.techknowlogick.com/xormigrate v1.7.1
xorm.io/builder v0.3.13
xorm.io/xorm v1.3.9
@@ -82,6 +84,7 @@ require (
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
+ github.com/alessio/shellescape v1.4.1 // indirect
github.com/atotto/clipboard v0.1.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
@@ -89,33 +92,42 @@ require (
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.2.0 // indirect
- github.com/charmbracelet/bubbles v0.18.0 // indirect
- github.com/charmbracelet/bubbletea v0.25.0 // indirect
- github.com/charmbracelet/lipgloss v0.9.1 // indirect
+ github.com/cespare/xxhash/v2 v2.3.0 // indirect
+ github.com/charmbracelet/bubbles v0.19.0 // indirect
+ github.com/charmbracelet/bubbletea v0.27.0 // indirect
+ github.com/charmbracelet/lipgloss v0.13.0 // indirect
+ github.com/charmbracelet/x/ansi v0.2.2 // indirect
+ github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect
+ github.com/charmbracelet/x/term v0.2.0 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
- github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
+ github.com/containerd/log v0.1.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/danieljoos/wincred v1.2.0 // indirect
- github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/davidmz/go-pageant v1.0.2 // indirect
- github.com/docker/distribution v2.8.3+incompatible // indirect
+ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
github.com/docker/docker-credential-helpers v0.8.0 // indirect
+ github.com/dunglas/httpsfv v1.0.2 // indirect
+ github.com/dustin/go-humanize v1.0.1 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
- github.com/fatih/color v1.13.0 // indirect
+ github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
+ github.com/fatih/color v1.16.0 // indirect
+ github.com/felixge/httpsnoop v1.0.4 // indirect
+ github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-fed/httpsig v1.1.0 // indirect
- github.com/go-logr/logr v1.4.1 // indirect
- github.com/go-openapi/jsonpointer v0.20.2 // indirect
+ github.com/go-logr/logr v1.4.2 // indirect
+ github.com/go-logr/stdr v1.2.2 // indirect
+ github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.20.4 // indirect
github.com/go-openapi/spec v0.20.13 // indirect
- github.com/go-openapi/swag v0.22.6 // indirect
+ github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect
- github.com/goccy/go-json v0.10.2 // indirect
+ github.com/goccy/go-json v0.10.3 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
@@ -126,65 +138,84 @@ require (
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
- github.com/hashicorp/go-retryablehttp v0.7.5 // indirect
- github.com/hashicorp/go-version v1.6.0 // indirect
+ 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
+ github.com/klauspost/compress v1.17.9 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
+ github.com/lestrrat-go/blackmagic v1.0.2 // indirect
+ github.com/lestrrat-go/httpcc v1.0.1 // indirect
+ github.com/lestrrat-go/httprc v1.0.5 // indirect
+ 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.15 // indirect
+ github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mholt/acmez/v2 v2.0.1 // indirect
github.com/miekg/dns v1.1.59 // indirect
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
+ github.com/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
github.com/modern-go/reflect2 v1.0.2 // indirect
+ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
- github.com/muesli/reflow v0.3.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/oklog/run v1.0.0 // 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.2 // indirect
- github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/prometheus/client_model v0.5.0 // indirect
- github.com/prometheus/common v0.48.0 // indirect
- github.com/prometheus/procfs v0.12.0 // indirect
- github.com/rivo/uniseg v0.4.6 // indirect
+ github.com/perimeterx/marshmallow v1.1.5 // indirect
+ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
+ github.com/prometheus/client_model v0.6.1 // indirect
+ github.com/prometheus/common v0.55.0 // indirect
+ github.com/prometheus/procfs v0.15.1 // indirect
+ github.com/rivo/uniseg v0.4.7 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
+ github.com/segmentio/asm v1.2.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
+ github.com/x448/float16 v0.8.4 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
- github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect
github.com/zeebo/blake3 v0.2.3 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
+ go.opentelemetry.io/otel v1.28.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 // indirect
+ go.opentelemetry.io/otel/metric v1.28.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.28.0 // indirect
+ go.opentelemetry.io/otel/trace v1.28.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/mod v0.17.0 // indirect
- golang.org/x/sys v0.20.0 // indirect
+ golang.org/x/sys v0.24.0 // indirect
golang.org/x/time v0.5.0 // indirect
- golang.org/x/tools v0.21.0 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect
+ golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20240722135656-d784300faade // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gotest.tools/v3 v3.4.0 // indirect
- k8s.io/klog/v2 v2.120.1 // indirect
+ k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
- k8s.io/utils v0.0.0-20231127182322-b307cd553661 // indirect
+ k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
diff --git a/go.sum b/go.sum
index 98eb54196..85d2fc7b3 100644
--- a/go.sum
+++ b/go.sum
@@ -1,11 +1,13 @@
-code.gitea.io/sdk/gitea v0.18.0 h1:+zZrwVmujIrgobt6wVBWCqITz6bn1aBjnCUHmpZrerI=
-code.gitea.io/sdk/gitea v0.18.0/go.mod h1:IG9xZJoltDNeDSW0qiF2Vqx5orMWa7OhVWrjvrd5NpI=
+al.essio.dev/pkg/shellescape v1.5.0 h1:7oTvSsQ5kg9WksA9O58y9wjYnY4jP0CL82/Q8WLUGKk=
+al.essio.dev/pkg/shellescape v1.5.0/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890=
+code.gitea.io/sdk/gitea v0.19.0 h1:8I6s1s4RHgzxiPHhOQdgim1RWIRcr0LVMbHBjBFXq4Y=
+code.gitea.io/sdk/gitea v0.19.0/go.mod h1:IG9xZJoltDNeDSW0qiF2Vqx5orMWa7OhVWrjvrd5NpI=
codeberg.org/6543/go-yaml2json v1.0.0 h1:heGqo9VEi7gY2yNqjj7X4ADs5nzlFIbGsJtgYDLrnig=
codeberg.org/6543/go-yaml2json v1.0.0/go.mod h1:mz61q14LWF4ZABrgMEDMmk3t9dPi6zgR1uBh2VKV2RQ=
codeberg.org/6543/xyaml v1.1.0 h1:0PWTy8OUqshshjrrnAXFWXSPUEa8R49DIh2ah07SxFc=
codeberg.org/6543/xyaml v1.1.0/go.mod h1:jI7afXLZUxeL4rNNsG1SlHh78L+gma9lK1bIebyFZwA=
-codeberg.org/mvdkleijn/forgejo-sdk/forgejo v0.0.0-20240607215151-168c988b82c1 h1:fwiekuoe+B8uz+Jpk0URaIOfklb2MWM8Pe0lNQck32A=
-codeberg.org/mvdkleijn/forgejo-sdk/forgejo v0.0.0-20240607215151-168c988b82c1/go.mod h1:09wAYX9H0+wBo1baX9DdSqdfreZc6ji5aELsnu9m14M=
+codeberg.org/mvdkleijn/forgejo-sdk/forgejo v1.1.1 h1:WEI3FZdoQjaiaR15TRmyGfY091R7o+NAaso65ckbsq0=
+codeberg.org/mvdkleijn/forgejo-sdk/forgejo v1.1.1/go.mod h1:09wAYX9H0+wBo1baX9DdSqdfreZc6ji5aELsnu9m14M=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
@@ -21,13 +23,17 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg6
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
+github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
+github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
-github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
-github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
-github.com/alessio/shellescape v1.4.2 h1:MHPfaU+ddJ0/bYWpgIeUnQUqKrlJ1S7BfEYPM4uEoM0=
-github.com/alessio/shellescape v1.4.2/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30=
+github.com/adrg/xdg v0.5.0 h1:dDaZvhMXatArP1NPHhnfaQUqWBLBsmx1h1HXQdMoFCY=
+github.com/adrg/xdg v0.5.0/go.mod h1:dDdY4M4DF9Rjy4kHPeNL+ilVF+p2lK8IdM9/rTSGcI4=
+github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0=
+github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30=
+github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
+github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
@@ -42,26 +48,32 @@ 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.2 h1:O18LtaYBGDooyy257cYePnhp4lPfz6TaJELil6Q1fDg=
-github.com/caddyserver/certmagic v0.21.2/go.mod h1:Zq6pklO9nVRl3DIFUw9gVUfXKdpc/0qwTUAQMBlfgtI=
+github.com/caddyserver/certmagic v0.21.3 h1:pqRRry3yuB4CWBVq9+cUqu+Y6E2z8TswbhNx1AZeYm0=
+github.com/caddyserver/certmagic v0.21.3/go.mod h1:Zq6pklO9nVRl3DIFUw9gVUfXKdpc/0qwTUAQMBlfgtI=
github.com/caddyserver/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=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
-github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
-github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/charmbracelet/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0=
-github.com/charmbracelet/bubbles v0.18.0/go.mod h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw=
-github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM=
-github.com/charmbracelet/bubbletea v0.25.0/go.mod h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg=
-github.com/charmbracelet/huh v0.3.0 h1:CxPplWkgW2yUTDDG0Z4S5HH8SJOosWHd4LxCvi0XsKE=
-github.com/charmbracelet/huh v0.3.0/go.mod h1:fujUdKX8tC45CCSaRQdw789O6uaCRwx8l2NDyKfC4jA=
+github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
+github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/charmbracelet/bubbles v0.19.0 h1:gKZkKXPP6GlDk6EcfujDK19PCQqRjaJZQ7QRERx1UF0=
+github.com/charmbracelet/bubbles v0.19.0/go.mod h1:WILteEqZ+krG5c3ntGEMeG99nCupcuIk7V0/zOP0tOA=
+github.com/charmbracelet/bubbletea v0.27.0 h1:Mznj+vvYuYagD9Pn2mY7fuelGvP0HAXtZYGgRBCbHvU=
+github.com/charmbracelet/bubbletea v0.27.0/go.mod h1:5MdP9XH6MbQkgGhnlxUqCNmBXf9I74KRQ8HIidRxV1Y=
+github.com/charmbracelet/huh v0.5.3 h1:3KLP4a/K1/S4dq4xFMTNMt3XWhgMl/yx8NYtygQ0bmg=
+github.com/charmbracelet/huh v0.5.3/go.mod h1:OZC3lshuF+/y8laj//DoZdFSHxC51OrtXLJI8xWVouQ=
github.com/charmbracelet/huh/spinner v0.0.0-20240327025511-ec643317aa10 h1:/HZJSyFVH5rB1MlCDfkhQhRbLPD2Er29ngWXiUQ8bik=
github.com/charmbracelet/huh/spinner v0.0.0-20240327025511-ec643317aa10/go.mod h1:nrBG0YEHaxdbqHXW1xvG1hPqkuac9Eg7RTMvogiXuz0=
-github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg=
-github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I=
+github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw=
+github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY=
+github.com/charmbracelet/x/ansi v0.2.2 h1:BC7xzaVpfWIYZRNE8NhO9zo8KA4eGUL6L/JWXDh3GF0=
+github.com/charmbracelet/x/ansi v0.2.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
+github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 h1:qko3AQ4gK1MTS/de7F5hPGx6/k1u0w4TeYmBFwzYVP4=
+github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ=
+github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0=
+github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0=
github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY=
github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic=
github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -70,8 +82,8 @@ github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJ
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
-github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY=
-github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
+github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
+github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
@@ -83,21 +95,22 @@ github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr
github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE=
github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0SkRa/eYHgec=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0=
github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
github.com/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw=
github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo=
-github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
-github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
+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 v24.0.9+incompatible h1:OxbimnP/z+qVjDLpq9wbeFU3Nc30XhSe+LkwYQisD50=
-github.com/docker/cli v24.0.9+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
-github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
-github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
-github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0=
-github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/cli v27.1.2+incompatible h1:nYviRv5Y+YAKx3dFrTvS1ErkyVVunKOhoweCTE1BsnI=
+github.com/docker/cli v27.1.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/docker v27.1.2+incompatible h1:AhGzR1xaQIy53qCkxARaFluI00WPGtXn0AJuoQsVYTY=
+github.com/docker/docker v27.1.2+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=
@@ -106,44 +119,60 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g=
github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g=
+github.com/dunglas/httpsfv v1.0.2 h1:iERDp/YAfnojSDJ7PW3dj1AReJz4MrwbECSSE59JWL0=
+github.com/dunglas/httpsfv v1.0.2/go.mod h1:zID2mqw9mFsnt7YC3vYQ9/cjq30q41W+1AnDwH8TiMg=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
-github.com/expr-lang/expr v1.16.7 h1:gCIiHt5ODA0xIaDbD0DPKyZpM9Drph3b3lolYAYq2Kw=
-github.com/expr-lang/expr v1.16.7/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4=
-github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
+github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
+github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
+github.com/expr-lang/expr v1.16.9 h1:WUAzmR0JNI9JCiF0/ewwHB1gmcGw5wW7nWt8gc6PpCI=
+github.com/expr-lang/expr v1.16.9/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
+github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
+github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
+github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
+github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/franela/goblin v0.0.0-20211003143422-0a4f594942bf h1:NrF81UtW8gG2LBGkXFQFqlfNnvMt9WdB46sfdJY4oqc=
github.com/franela/goblin v0.0.0-20211003143422-0a4f594942bf/go.mod h1:VzmDKDJVZI3aJmnRI9VjAn9nJ8qPPsN1fqzr9dqInIo=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
+github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
+github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
+github.com/gdgvda/cron v0.3.0 h1:Wjj9NSYGzvtjkdZxOjpU749OuJGpcqr/tSxzeeBQGVI=
+github.com/gdgvda/cron v0.3.0/go.mod h1:caBF+mzTZGtQqFE05T1m6u9OmCASY3EK51XAICf3wio=
+github.com/getkin/kin-openapi v0.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY=
+github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM=
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
-github.com/go-ap/httpsig v0.0.0-20221203064646-3647b4d88fdf h1:Ab5yBsD/dXhFmgf2hX7T/YYr+VK0Df7SrIxyNztT9YE=
-github.com/go-ap/httpsig v0.0.0-20221203064646-3647b4d88fdf/go.mod h1:+4SUDMvPlRMUPW5PlMTbxj3U5a4fWasBIbakUw7Kp6c=
+github.com/gitsight/go-vcsurl v1.0.1 h1:wkijKsbVg9R2IBP97U7wOANeIW9WJJKkBwS9XqllzWo=
+github.com/gitsight/go-vcsurl v1.0.1/go.mod h1:qRFdKDa/0Lh9MT0xE+qQBYZ/01+mY1H40rZUHR24X9U=
github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI=
github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
-github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
-github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
-github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q=
-github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
+github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
+github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4=
github.com/go-openapi/spec v0.20.13 h1:XJDIN+dLH6vqXgafnl5SUIMnzaChQ6QTo0/UPMbkIaE=
github.com/go-openapi/spec v0.20.13/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw=
-github.com/go-openapi/swag v0.22.6 h1:dnqg1XfHXL9aBxSbktBqFR5CxVyVI+7fYWhAf1JOeTw=
-github.com/go-openapi/swag v0.22.6/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0=
+github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
+github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
@@ -156,11 +185,14 @@ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
-github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
+github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
+github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
+github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
+github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
-github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
+github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
@@ -190,16 +222,19 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/go-github/v62 v62.0.0 h1:/6mGCaRywZz9MuHyw9gD1CwsbmBX8GWsbFkwMmHdhl4=
-github.com/google/go-github/v62 v62.0.0/go.mod h1:EMxeUqGJq2xRu9DYBMwel/mr7kZrzUOfQmmpYrZn2a4=
+github.com/google/go-github/v64 v64.0.0 h1:4G61sozmY3eiPAjjoOHponXDBONm+utovTKbyUb2Qdg=
+github.com/google/go-github/v64 v64.0.0/go.mod h1:xB3vqMQNdHzilXBiO2I+M7iEFtHf+DP/omBOv6tQzVo=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
+github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM=
+github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
+github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/tink/go v1.7.0 h1:6Eox8zONGebBFcCBqkVmt60LaWZa6xg1cl/DwAh/J1w=
github.com/google/tink/go v1.7.0/go.mod h1:GAUOd+QE3pgj9q8VKIGTCP33c/B7eb4NhxLcgTJZStM=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -207,17 +242,18 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
-github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-plugin v1.6.1 h1:P7MR2UP6gNKGPp+y7EZw2kOiq4IR9WiqLvp0XOsVdwI=
github.com/hashicorp/go-plugin v1.6.1/go.mod h1:XPHFku2tFo3o3QKFgSYo+cghcUhw1NA1hZyMK0PWAw0=
-github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M=
-github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
-github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
-github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
+github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
+github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
+github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
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 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
@@ -225,6 +261,8 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
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=
@@ -264,8 +302,8 @@ github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0f
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
-github.com/jellydator/ttlcache/v3 v3.2.0 h1:6lqVJ8X3ZaUwvzENqPAobDsXNExfUJd61u++uW8a3LE=
-github.com/jellydator/ttlcache/v3 v3.2.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4=
+github.com/jellydator/ttlcache/v3 v3.2.1 h1:eS8ljnYY7BllYGkXw/TfczWZrXUu/CH7SIkC6ugn9Js=
+github.com/jellydator/ttlcache/v3 v3.2.1/go.mod h1:bj2/e0l4jRnQdrnSTaGTsh4GSXvMjQcy41i7th0GVGw=
github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
@@ -283,6 +321,8 @@ github.com/kinbiko/jsonassert v1.1.1 h1:DB12divY+YB+cVpHULLuKePSi6+ui4M/shHSzJIS
github.com/kinbiko/jsonassert v1.1.1/go.mod h1:NO4lzrogohtIdNUNzx8sdzB55M4R4Q1bsrWVdqQ7C+A=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
+github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
@@ -298,8 +338,22 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
+github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k=
+github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
+github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
+github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
+github.com/lestrrat-go/httprc v1.0.5 h1:bsTfiH8xaKOJPrg1R+E3iE/AWZr/x0Phj9PBTG/OLUk=
+github.com/lestrrat-go/httprc v1.0.5/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
+github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
+github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
+github.com/lestrrat-go/jwx/v2 v2.1.0 h1:0zs7Ya6+39qoit7gwAf+cYm1zzgS3fceIdo7RmQ5lkw=
+github.com/lestrrat-go/jwx/v2 v2.1.0/go.mod h1:Xpw9QIaUGiIUD1Wx0NcY1sIHwFf8lDuZn/cmxtXYRys=
+github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
+github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@@ -329,9 +383,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
-github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
-github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
-github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
+github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
@@ -342,10 +395,14 @@ github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs=
github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk=
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/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/moby v24.0.9+incompatible h1:Z/hFbZJqC5Fmuf6jesMLdHU71CMAgdiSJ1ZYey+bFmg=
-github.com/moby/moby v24.0.9+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
+github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
+github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
+github.com/moby/moby v27.1.2+incompatible h1:vqOs4c7YktTdEBnPQNm0Q+M+IOuxxTCkrYJLBAVsEHQ=
+github.com/moby/moby v27.1.2+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=
@@ -354,16 +411,16 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
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/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
-github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
-github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
-github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
+github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a h1:2MaM6YC3mGu54x+RKAA6JiFFHlHDY1UbkxqppT7wYOg=
+github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a/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=
@@ -375,11 +432,11 @@ github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNs
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
-github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
+github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
+github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/onsi/gomega v1.31.0 h1:54UJxxj6cPInHS3a35wm6BK/F9nHYueZ1NVujHDrnXE=
-github.com/onsi/gomega v1.31.0/go.mod h1:DW9aCi7U6Yi40wNVAvT6kzFnEVEI5n3DloYBiKiT6zk=
+github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
+github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
@@ -387,31 +444,31 @@ github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zM
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
+github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
+github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
-github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
-github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
-github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
-github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
-github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
-github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
-github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg=
+github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
+github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
+github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
+github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
+github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
+github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
+github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
-github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
-github.com/rivo/uniseg v0.4.6 h1:Sovz9sDSwbOz9tgUy8JpT+KgCkPYJEN/oYzlJiYTNLg=
-github.com/rivo/uniseg v0.4.6/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
-github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
-github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
+github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
+github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
-github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
+github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
+github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
@@ -421,6 +478,10 @@ github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWR
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
+github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
+github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
+github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
@@ -441,6 +502,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
@@ -458,16 +520,18 @@ github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg=
github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
-github.com/tevino/abool/v2 v2.1.0 h1:7w+Vf9f/5gmKT4m4qkayb33/92M+Um45F2BkHOR+L/c=
-github.com/tevino/abool/v2 v2.1.0/go.mod h1:+Lmlqk6bHDWHqN1cbxqhwEAwMPXgc8I1SDEamtseuXY=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
-github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI=
-github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM=
-github.com/xanzy/go-gitlab v0.105.0 h1:3nyLq0ESez0crcaM19o5S//SvezOQguuIHZ3wgX64hM=
-github.com/xanzy/go-gitlab v0.105.0/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI=
+github.com/urfave/cli-docs/v3 v3.0.0-alpha5.0.20240714105325-1da00919bcb4 h1:exFN/ZOxXslYr9t2AjrniP7wPjp/VLLAJhgazj92EBg=
+github.com/urfave/cli-docs/v3 v3.0.0-alpha5.0.20240714105325-1da00919bcb4/go.mod h1:AIqom6Q60U4tiqHp41i7+/AB2XHgi1WvQ7jOFlccmZ4=
+github.com/urfave/cli/v3 v3.0.0-alpha9.0.20240811205807-fc07a8c3673f h1:C3vgiHDZBVKtNLp3PCQ9//V2NBhGOwUhLILmZhB6/jY=
+github.com/urfave/cli/v3 v3.0.0-alpha9.0.20240811205807-fc07a8c3673f/go.mod h1:Z1ItyMma7t6I7zHG9OpbExhHQOSkFf/96n+mAZ9MtVI=
+github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
+github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
+github.com/xanzy/go-gitlab v0.108.0 h1:IEvEUWFR5G1seslRhJ8gC//INiIUqYXuSUoBd7/gFKE=
+github.com/xanzy/go-gitlab v0.108.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=
@@ -475,13 +539,13 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
-github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw=
-github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk=
+github.com/yaronf/httpsign v0.3.1 h1:A4pqjwOVCwlExyy/mPTTryCHcXn+xhq4+wxq4BKhi2k=
+github.com/yaronf/httpsign v0.3.1/go.mod h1:+7d6GccMcoljvE3QtU00NCmR1iTXCVNfbMe5nqaxRG4=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-github.com/zalando/go-keyring v0.2.4 h1:wi2xxTqdiwMKbM6TWwi+uJCG/Tum2UV0jqaQhCa9/68=
-github.com/zalando/go-keyring v0.2.4/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk=
+github.com/zalando/go-keyring v0.2.5 h1:Bc2HHpjALryKD62ppdEzaFG6VxL6Bc+5v0LYpN8Lba8=
+github.com/zalando/go-keyring v0.2.5/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk=
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=
@@ -490,6 +554,22 @@ 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=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
+go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
+go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.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.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
+go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
+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.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
+go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
+go.opentelemetry.io/proto/otlp v1.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=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
@@ -524,8 +604,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.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
-golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
+golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
+golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
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=
@@ -547,17 +627,17 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
-golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
-golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
-golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo=
-golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
+golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
+golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
+golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA=
+golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
-golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -576,26 +656,25 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
-golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
+golang.org/x/sys v0.24.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.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
-golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
+golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
+golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
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=
@@ -603,8 +682,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
-golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
+golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -621,20 +700,22 @@ golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
-golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
-google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
-google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
-google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
-google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/genproto/googleapis/api v0.0.0-20240722135656-d784300faade h1:WxZOF2yayUHpHSbUE6NMzumUzBxYc3YGwo0YHnbzsJY=
+google.golang.org/genproto/googleapis/api v0.0.0-20240722135656-d784300faade/go.mod h1:mw8MG/Qz5wfgYr6VqVCiZcHe/GJEfI+oGGDCohaVgB0=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a h1:hqK4+jJZXCU4pW7jsAdGOVFIfLHQeV7LaizZKnZ84HI=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
+google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
+google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
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=
@@ -659,18 +740,18 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
-k8s.io/api v0.30.1 h1:kCm/6mADMdbAxmIh0LBjS54nQBE+U4KmbCfIkF5CpJY=
-k8s.io/api v0.30.1/go.mod h1:ddbN2C0+0DIiPntan/bye3SW3PdwLa11/0yqwvuRrJM=
-k8s.io/apimachinery v0.30.1 h1:ZQStsEfo4n65yAdlGTfP/uSHMQSoYzU/oeEbkmF7P2U=
-k8s.io/apimachinery v0.30.1/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
-k8s.io/client-go v0.30.1 h1:uC/Ir6A3R46wdkgCV3vbLyNOYyCJ8oZnjtJGKfytl/Q=
-k8s.io/client-go v0.30.1/go.mod h1:wrAqLNs2trwiCH/wxxmT/x3hKVH9PuV0GGW0oDoHVqc=
-k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
-k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
+k8s.io/api v0.31.0 h1:b9LiSjR2ym/SzTOlfMHm1tr7/21aD7fSkqgD/CVJBCo=
+k8s.io/api v0.31.0/go.mod h1:0YiFF+JfFxMM6+1hQei8FY8M7s1Mth+z/q7eF1aJkTE=
+k8s.io/apimachinery v0.31.0 h1:m9jOiSr3FoSSL5WO9bjm1n6B9KROYYgNZOb4tyZ1lBc=
+k8s.io/apimachinery v0.31.0/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
+k8s.io/client-go v0.31.0 h1:QqEJzNjbN2Yv1H79SsS+SWnXkBgVu4Pj3CJQgbx0gI8=
+k8s.io/client-go v0.31.0/go.mod h1:Y9wvC76g4fLjmU0BA+rV+h2cncoadjvjjkkIGoTLcGU=
+k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
+k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
-k8s.io/utils v0.0.0-20231127182322-b307cd553661 h1:FepOBzJ0GXm8t0su67ln2wAZjbQ6RxQGZDnzuLcrUTI=
-k8s.io/utils v0.0.0-20231127182322-b307cd553661/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
+k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
diff --git a/nfpm/agent.yaml b/nfpm/agent.yaml
index 934dc7aab..fb3883d01 100644
--- a/nfpm/agent.yaml
+++ b/nfpm/agent.yaml
@@ -10,3 +10,7 @@ section: daemon/system
contents:
- src: ./dist/agent/linux_amd64/woodpecker-agent
dst: /usr/local/bin/woodpecker-agent
+ - src: ./woodpecker-agent.service
+ dst: /usr/local/lib/systemd/system/
+ - src: ./woodpecker-agent.env.example
+ dst: /etc/woodpecker/
diff --git a/nfpm/server.yaml b/nfpm/server.yaml
index f125da291..66c8488d8 100644
--- a/nfpm/server.yaml
+++ b/nfpm/server.yaml
@@ -10,3 +10,7 @@ section: daemon/system
contents:
- src: ./dist/server/linux_amd64/woodpecker-server
dst: /usr/local/bin/woodpecker-server
+ - src: ./woodpecker-server.service
+ dst: /usr/local/lib/systemd/system/
+ - src: ./woodpecker-server.env.example
+ dst: /etc/woodpecker/
diff --git a/nfpm/woodpecker-agent.env.example b/nfpm/woodpecker-agent.env.example
new file mode 100644
index 000000000..59c13c968
--- /dev/null
+++ b/nfpm/woodpecker-agent.env.example
@@ -0,0 +1,7 @@
+# Example for a woodpecker-agent.env file
+
+# Check the documentation for the agent:
+# https://woodpecker-ci.org/docs/administration/agent-config
+
+# Add all required environment variables for your setup in the form of VARIABLE=value
+VARIABLE=value
diff --git a/nfpm/woodpecker-agent.service b/nfpm/woodpecker-agent.service
new file mode 100644
index 000000000..20d7db4d7
--- /dev/null
+++ b/nfpm/woodpecker-agent.service
@@ -0,0 +1,19 @@
+[Unit]
+Description=WoodpeckerCI agent
+Documentation=https://woodpecker-ci.org/docs/administration/agent-config
+Requires=network.target
+After=network.target
+ConditionFileNotEmpty=/etc/woodpecker/woodpecker-agent.env
+ConditionPathExists=/etc/woodpecker/woodpecker-agent.env
+
+[Service]
+Type=simple
+EnvironmentFile=/etc/woodpecker/woodpecker-agent.env
+User=woodpecker
+Group=woodpecker
+ExecStart=/usr/local/bin/woodpecker-agent
+WorkingDirectory=/var/lib/woodpecker/
+StateDirectory=woodpecker
+
+[Install]
+WantedBy=multi-user.target
diff --git a/nfpm/woodpecker-server.env.example b/nfpm/woodpecker-server.env.example
new file mode 100644
index 000000000..32418c677
--- /dev/null
+++ b/nfpm/woodpecker-server.env.example
@@ -0,0 +1,7 @@
+# Example for a woodpecker-server.env file
+
+# Check the documentation for the server:
+# https://woodpecker-ci.org/docs/administration/server-config
+
+# Add all required environment variables for your setup in the form of VARIABLE=value
+VARIABLE=value
diff --git a/nfpm/woodpecker-server.service b/nfpm/woodpecker-server.service
new file mode 100644
index 000000000..3968ee5d5
--- /dev/null
+++ b/nfpm/woodpecker-server.service
@@ -0,0 +1,19 @@
+[Unit]
+Description=WoodpeckerCI server
+Documentation=https://woodpecker-ci.org/docs/administration/server-config
+Requires=network.target
+After=network.target
+ConditionFileNotEmpty=/etc/woodpecker/woodpecker-server.env
+ConditionPathExists=/etc/woodpecker/woodpecker-server.env
+
+[Service]
+Type=simple
+EnvironmentFile=/etc/woodpecker/woodpecker-server.env
+User=woodpecker
+Group=woodpecker
+ExecStart=/usr/local/bin/woodpecker-server
+WorkingDirectory=/var/lib/woodpecker/
+StateDirectory=woodpecker
+
+[Install]
+WantedBy=multi-user.target
diff --git a/pipeline/backend/common/script_posix.go b/pipeline/backend/common/script_posix.go
index 56bf06111..d22ac78ed 100644
--- a/pipeline/backend/common/script_posix.go
+++ b/pipeline/backend/common/script_posix.go
@@ -18,7 +18,7 @@ import (
"bytes"
"fmt"
- "github.com/alessio/shellescape"
+ "al.essio.dev/pkg/shellescape"
)
// generateScriptPosix is a helper function that generates a step script
diff --git a/pipeline/backend/common/script_test.go b/pipeline/backend/common/script_test.go
index 37911713e..b532f7451 100644
--- a/pipeline/backend/common/script_test.go
+++ b/pipeline/backend/common/script_test.go
@@ -1,3 +1,17 @@
+// 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 common
import (
diff --git a/pipeline/backend/docker/convert.go b/pipeline/backend/docker/convert.go
index a862418ad..d67672274 100644
--- a/pipeline/backend/docker/convert.go
+++ b/pipeline/backend/docker/convert.go
@@ -41,6 +41,7 @@ func (e *docker) toConfig(step *types.Step) *container.Config {
WorkingDir: step.WorkingDir,
AttachStdout: true,
AttachStderr: true,
+ Volumes: toVol(step.Volumes),
}
configEnv := make(map[string]string)
maps.Copy(configEnv, step.Environment)
@@ -59,9 +60,6 @@ func (e *docker) toConfig(step *types.Step) *container.Config {
if len(configEnv) != 0 {
config.Env = toEnv(configEnv)
}
- if len(step.Volumes) != 0 {
- config.Volumes = toVol(step.Volumes)
- }
return config
}
@@ -127,7 +125,10 @@ func toHostConfig(step *types.Step) *container.HostConfig {
// helper function that converts a slice of volume paths to a set of
// unique volume names.
func toVol(paths []string) map[string]struct{} {
- set := map[string]struct{}{}
+ if len(paths) == 0 {
+ return nil
+ }
+ set := make(map[string]struct{})
for _, path := range paths {
parts, err := splitVolumeParts(path)
if err != nil {
@@ -146,7 +147,9 @@ func toVol(paths []string) map[string]struct{} {
func toEnv(env map[string]string) []string {
var envs []string
for k, v := range env {
- envs = append(envs, k+"="+v)
+ if k != "" {
+ envs = append(envs, k+"="+v)
+ }
}
return envs
}
diff --git a/pipeline/backend/docker/convert_test.go b/pipeline/backend/docker/convert_test.go
index b114398f6..998c731b5 100644
--- a/pipeline/backend/docker/convert_test.go
+++ b/pipeline/backend/docker/convert_test.go
@@ -19,8 +19,8 @@ import (
"sort"
"testing"
- "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
+ "github.com/docker/docker/api/types/system"
"github.com/stretchr/testify/assert"
backend "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
@@ -91,8 +91,82 @@ func TestSplitVolumeParts(t *testing.T) {
}
}
+// dummy vars to test against.
+var (
+ testCmdStep = &backend.Step{
+ Name: "hello",
+ UUID: "f51821af-4cb8-435e-a3c2-3a684185d828",
+ Type: backend.StepTypeCommands,
+ Commands: []string{"echo \"hello world\"", "ls"},
+ Image: "alpine",
+ Environment: map[string]string{"SHELL": "/bin/zsh"},
+ }
+
+ testPluginStep = &backend.Step{
+ Name: "lint",
+ UUID: "d841ee40-e66e-4275-bb3f-55bf89744b21",
+ Type: backend.StepTypePlugin,
+ Image: "mstruebing/editorconfig-checker",
+ Environment: make(map[string]string),
+ }
+
+ testEngine = &docker{
+ info: system.Info{
+ Architecture: "x86_64",
+ OSType: "linux",
+ DefaultRuntime: "runc",
+ DockerRootDir: "/var/lib/docker",
+ OperatingSystem: "Archlinux",
+ Name: "SOME_HOSTNAME",
+ },
+ }
+)
+
+func TestToContainerName(t *testing.T) {
+ assert.EqualValues(t, "wp_f51821af-4cb8-435e-a3c2-3a684185d828", toContainerName(testCmdStep))
+ assert.EqualValues(t, "wp_d841ee40-e66e-4275-bb3f-55bf89744b21", toContainerName(testPluginStep))
+}
+
+func TestStepToConfig(t *testing.T) {
+ // StepTypeCommands
+ conf := testEngine.toConfig(testCmdStep)
+ 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)
+ assert.EqualValues(t, testCmdStep.UUID, conf.Labels["wp_uuid"])
+ }
+
+ // StepTypePlugin
+ conf = testEngine.toConfig(testPluginStep)
+ if assert.NotNil(t, conf) {
+ assert.Nil(t, conf.Cmd)
+ assert.EqualValues(t, testPluginStep.UUID, conf.Labels["wp_uuid"])
+ }
+}
+
+func TestToEnv(t *testing.T) {
+ assert.Nil(t, toEnv(nil))
+ assert.EqualValues(t, []string{"A=B"}, toEnv(map[string]string{"A": "B"}))
+ assert.ElementsMatch(t, []string{"A=B=C", "T=T"}, toEnv(map[string]string{"A": "B=C", "": "Z", "T": "T"}))
+}
+
+func TestToVol(t *testing.T) {
+ assert.Nil(t, toVol(nil))
+ assert.EqualValues(t, map[string]struct{}{"/test": {}}, toVol([]string{"test:/test"}))
+}
+
+func TestEncodeAuthToBase64(t *testing.T) {
+ res, err := encodeAuthToBase64(backend.Auth{})
+ assert.NoError(t, err)
+ assert.EqualValues(t, "e30=", res)
+
+ res, err = encodeAuthToBase64(backend.Auth{Username: "user", Password: "pwd"})
+ assert.NoError(t, err)
+ assert.EqualValues(t, "eyJ1c2VybmFtZSI6InVzZXIiLCJwYXNzd29yZCI6InB3ZCJ9", res)
+}
+
func TestToConfigSmall(t *testing.T) {
- engine := docker{info: types.Info{OSType: "linux/riscv64"}}
+ engine := docker{info: system.Info{OSType: "linux/riscv64"}}
conf := engine.toConfig(&backend.Step{
Name: "test",
@@ -122,7 +196,7 @@ func TestToConfigSmall(t *testing.T) {
}
func TestToConfigFull(t *testing.T) {
- engine := docker{info: types.Info{OSType: "linux/riscv64"}}
+ engine := docker{info: system.Info{OSType: "linux/riscv64"}}
conf := engine.toConfig(&backend.Step{
Name: "test",
diff --git a/pipeline/backend/docker/docker.go b/pipeline/backend/docker/docker.go
index 7b7d31326..bb5484c31 100644
--- a/pipeline/backend/docker/docker.go
+++ b/pipeline/backend/docker/docker.go
@@ -22,8 +22,10 @@ import (
"path/filepath"
"strings"
- "github.com/docker/docker/api/types"
+ "github.com/docker/docker/api/types/container"
+ "github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/network"
+ "github.com/docker/docker/api/types/system"
"github.com/docker/docker/api/types/volume"
tls_config "github.com/docker/go-connections/tlsconfig"
"github.com/moby/moby/client"
@@ -31,7 +33,7 @@ import (
std_copy "github.com/moby/moby/pkg/stdcopy"
"github.com/moby/term"
"github.com/rs/zerolog/log"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
backend "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
"go.woodpecker-ci.org/woodpecker/v2/shared/utils"
@@ -42,7 +44,7 @@ type docker struct {
enableIPv6 bool
network string
volumes []string
- info types.Info
+ info system.Info
}
const (
@@ -63,7 +65,7 @@ func (e *docker) Name() string {
}
func (e *docker) IsAvailable(ctx context.Context) bool {
- if c, ok := ctx.Value(backend.CliContext).(*cli.Context); ok {
+ if c, ok := ctx.Value(backend.CliCommand).(*cli.Command); ok {
if c.IsSet("backend-docker-host") {
return true
}
@@ -101,7 +103,7 @@ func (e *docker) Flags() []cli.Flag {
// Load new client for Docker Backend using environment variables.
func (e *docker) Load(ctx context.Context) (*backend.BackendInfo, error) {
- c, ok := ctx.Value(backend.CliContext).(*cli.Context)
+ c, ok := ctx.Value(backend.CliCommand).(*cli.Command)
if !ok {
return nil, backend.ErrNoCliContextFound
}
@@ -171,9 +173,9 @@ func (e *docker) SetupWorkflow(ctx context.Context, conf *backend.Config, taskUU
networkDriver = networkDriverNAT
}
for _, n := range conf.Networks {
- _, err := e.client.NetworkCreate(ctx, n.Name, types.NetworkCreate{
+ _, err := e.client.NetworkCreate(ctx, n.Name, network.CreateOptions{
Driver: networkDriver,
- EnableIPv6: e.enableIPv6,
+ EnableIPv6: &e.enableIPv6,
})
if err != nil {
return err
@@ -190,7 +192,7 @@ func (e *docker) StartStep(ctx context.Context, step *backend.Step, taskUUID str
containerName := toContainerName(step)
// create pull options with encoded authorization credentials.
- pullOpts := types.ImagePullOptions{}
+ pullOpts := image.PullOptions{}
if step.AuthConfig.Username != "" && step.AuthConfig.Password != "" {
pullOpts.RegistryAuth, _ = encodeAuthToBase64(step.AuthConfig)
}
@@ -257,7 +259,7 @@ func (e *docker) StartStep(ctx context.Context, step *backend.Step, taskUUID str
}
}
- return e.client.ContainerStart(ctx, containerName, startOpts)
+ return e.client.ContainerStart(ctx, containerName, container.StartOptions{})
}
func (e *docker) WaitStep(ctx context.Context, step *backend.Step, taskUUID string) (*backend.State, error) {
@@ -286,7 +288,13 @@ func (e *docker) WaitStep(ctx context.Context, step *backend.Step, taskUUID stri
func (e *docker) TailStep(ctx context.Context, step *backend.Step, taskUUID string) (io.ReadCloser, error) {
log.Trace().Str("taskUUID", taskUUID).Msgf("tail logs of step %s", step.Name)
- logs, err := e.client.ContainerLogs(ctx, toContainerName(step), logsOpts)
+ logs, err := e.client.ContainerLogs(ctx, toContainerName(step), container.LogsOptions{
+ Follow: true,
+ ShowStdout: true,
+ ShowStderr: true,
+ Details: false,
+ Timestamps: false,
+ })
if err != nil {
return nil, err
}
@@ -344,23 +352,11 @@ func (e *docker) DestroyWorkflow(ctx context.Context, conf *backend.Config, task
return nil
}
-var (
- startOpts = types.ContainerStartOptions{}
-
- removeOpts = types.ContainerRemoveOptions{
- RemoveVolumes: true,
- RemoveLinks: false,
- Force: false,
- }
-
- logsOpts = types.ContainerLogsOptions{
- Follow: true,
- ShowStdout: true,
- ShowStderr: true,
- Details: false,
- Timestamps: false,
- }
-)
+var removeOpts = container.RemoveOptions{
+ RemoveVolumes: true,
+ RemoveLinks: false,
+ Force: false,
+}
func isErrContainerNotFoundOrNotRunning(err error) bool {
// Error response from daemon: Cannot kill container: ...: No such container: ...
diff --git a/pipeline/backend/docker/flags.go b/pipeline/backend/docker/flags.go
index 293bbdfba..379cf5996 100644
--- a/pipeline/backend/docker/flags.go
+++ b/pipeline/backend/docker/flags.go
@@ -15,44 +15,44 @@
package docker
import (
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
)
var Flags = []cli.Flag{
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_DOCKER_HOST", "DOCKER_HOST"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_DOCKER_HOST", "DOCKER_HOST"),
Name: "backend-docker-host",
Usage: "path to docker socket or url to the docker server",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_DOCKER_API_VERSION", "DOCKER_API_VERSION"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_DOCKER_API_VERSION", "DOCKER_API_VERSION"),
Name: "backend-docker-api-version",
Usage: "the version of the API to reach, leave empty for latest.",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_DOCKER_CERT_PATH", "DOCKER_CERT_PATH"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_DOCKER_CERT_PATH", "DOCKER_CERT_PATH"),
Name: "backend-docker-cert",
Usage: "path to load the TLS certificates for connecting to docker server",
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_DOCKER_TLS_VERIFY", "DOCKER_TLS_VERIFY"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_DOCKER_TLS_VERIFY", "DOCKER_TLS_VERIFY"),
Name: "backend-docker-tls-verify",
Usage: "enable or disable TLS verification for connecting to docker server",
Value: true,
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_DOCKER_ENABLE_IPV6"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_DOCKER_ENABLE_IPV6"),
Name: "backend-docker-ipv6",
Usage: "backend docker enable IPV6",
Value: false,
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_DOCKER_NETWORK"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_DOCKER_NETWORK"),
Name: "backend-docker-network",
Usage: "backend docker network",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_DOCKER_VOLUMES"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_DOCKER_VOLUMES"),
Name: "backend-docker-volumes",
Usage: "backend docker volumes (comma separated)",
},
diff --git a/pipeline/backend/dummy/dummy.go b/pipeline/backend/dummy/dummy.go
new file mode 100644
index 000000000..cdf08c8aa
--- /dev/null
+++ b/pipeline/backend/dummy/dummy.go
@@ -0,0 +1,240 @@
+// 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.
+
+//go:build test
+// +build test
+
+package dummy
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/rs/zerolog/log"
+ "github.com/urfave/cli/v3"
+
+ backend "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
+)
+
+type dummy struct {
+ kv sync.Map
+}
+
+const (
+ // Step names to control behavior of dummy backend.
+ WorkflowSetupFailUUID = "WorkflowSetupShouldFail"
+ EnvKeyStepSleep = "SLEEP"
+ EnvKeyStepType = "EXPECT_TYPE"
+ EnvKeyStepStartFail = "STEP_START_FAIL"
+ EnvKeyStepExitCode = "STEP_EXIT_CODE"
+ EnvKeyStepTailFail = "STEP_TAIL_FAIL"
+ EnvKeyStepOOMKilled = "STEP_OOM_KILLED"
+
+ // Internal const.
+ stepStateStarted = "started"
+ stepStateDone = "done"
+ testServiceTimeout = 1 * time.Second
+)
+
+// New returns a dummy backend.
+func New() backend.Backend {
+ return &dummy{
+ kv: sync.Map{},
+ }
+}
+
+func (e *dummy) Name() string {
+ return "dummy"
+}
+
+func (e *dummy) IsAvailable(_ context.Context) bool {
+ return true
+}
+
+func (e *dummy) Flags() []cli.Flag {
+ return nil
+}
+
+// Load new client for Docker Backend using environment variables.
+func (e *dummy) Load(_ context.Context) (*backend.BackendInfo, error) {
+ return &backend.BackendInfo{
+ Platform: "dummy",
+ }, nil
+}
+
+func (e *dummy) SetupWorkflow(_ context.Context, _ *backend.Config, taskUUID string) error {
+ if taskUUID == WorkflowSetupFailUUID {
+ return fmt.Errorf("expected fail to setup workflow")
+ }
+ log.Trace().Str("taskUUID", taskUUID).Msg("create workflow environment")
+ e.kv.Store("task_"+taskUUID, "setup")
+ return nil
+}
+
+func (e *dummy) StartStep(_ context.Context, step *backend.Step, taskUUID string) error {
+ log.Trace().Str("taskUUID", taskUUID).Msgf("start step %s", step.Name)
+
+ // internal state checks
+ _, exist := e.kv.Load("task_" + taskUUID)
+ if !exist {
+ return fmt.Errorf("expect env of workflow %s to exist but found none to destroy", taskUUID)
+ }
+ stepState, stepExist := e.kv.Load(fmt.Sprintf("task_%s_step_%s", taskUUID, step.UUID))
+ if stepExist {
+ // Detect issues like https://github.com/woodpecker-ci/woodpecker/issues/3494
+ return fmt.Errorf("StartStep detected already started step '%s' (%s) in state: %s", step.Name, step.UUID, stepState)
+ }
+
+ if stepStartFail, _ := strconv.ParseBool(step.Environment[EnvKeyStepStartFail]); stepStartFail {
+ return fmt.Errorf("expected fail to start step")
+ }
+
+ expectStepType, testStepType := step.Environment[EnvKeyStepType]
+ if testStepType && string(step.Type) != expectStepType {
+ return fmt.Errorf("expected step type '%s' but got '%s'", expectStepType, step.Type)
+ }
+
+ e.kv.Store(fmt.Sprintf("task_%s_step_%s", taskUUID, step.UUID), stepStateStarted)
+ return nil
+}
+
+func (e *dummy) WaitStep(ctx context.Context, step *backend.Step, taskUUID string) (*backend.State, error) {
+ log.Trace().Str("taskUUID", taskUUID).Msgf("wait for step %s", step.Name)
+
+ _, exist := e.kv.Load("task_" + taskUUID)
+ if !exist {
+ err := fmt.Errorf("expect env of workflow %s to exist but found none to destroy", taskUUID)
+ return &backend.State{Error: err}, err
+ }
+
+ // check state
+ stepState, stepExist := e.kv.Load(fmt.Sprintf("task_%s_step_%s", taskUUID, step.UUID))
+ if !stepExist {
+ err := fmt.Errorf("WaitStep expect step '%s' (%s) to be created but found none", step.Name, step.UUID)
+ return &backend.State{Error: err}, err
+ }
+ if stepState != stepStateStarted {
+ err := fmt.Errorf("WaitStep expect step '%s' (%s) to be '%s' but it is: %s", step.Name, step.UUID, stepStateStarted, stepState)
+ return &backend.State{Error: err}, err
+ }
+
+ // extend wait time logic
+ if sleep, sleepExist := step.Environment[EnvKeyStepSleep]; sleepExist {
+ toSleep, err := time.ParseDuration(sleep)
+ if err != nil {
+ err = fmt.Errorf("WaitStep fail to parse sleep duration: %w", err)
+ return &backend.State{Error: err}, err
+ }
+ time.Sleep(toSleep)
+ } else {
+ if step.Type == backend.StepTypeService {
+ select {
+ case <-time.NewTimer(testServiceTimeout).C:
+ err := fmt.Errorf("WaitStep fail due to timeout of service after 1 second")
+ return &backend.State{Error: err}, err
+ case <-ctx.Done():
+ // context for service closed ... we can move forward
+ }
+ } else {
+ time.Sleep(time.Nanosecond)
+ }
+ }
+
+ e.kv.Store(fmt.Sprintf("task_%s_step_%s", taskUUID, step.UUID), stepStateDone)
+
+ oomKilled, _ := strconv.ParseBool(step.Environment[EnvKeyStepOOMKilled])
+ exitCode := 0
+
+ if code, exist := step.Environment[EnvKeyStepExitCode]; exist {
+ exitCode, _ = strconv.Atoi(strings.TrimSpace(code))
+ }
+
+ return &backend.State{
+ ExitCode: exitCode,
+ Exited: true,
+ OOMKilled: oomKilled,
+ }, nil
+}
+
+func (e *dummy) TailStep(_ context.Context, step *backend.Step, taskUUID string) (io.ReadCloser, error) {
+ log.Trace().Str("taskUUID", taskUUID).Msgf("tail logs of step %s", step.Name)
+
+ _, exist := e.kv.Load("task_" + taskUUID)
+ if !exist {
+ return nil, fmt.Errorf("expect env of workflow %s to exist but found none to destroy", taskUUID)
+ }
+
+ // check state
+ stepState, stepExist := e.kv.Load(fmt.Sprintf("task_%s_step_%s", taskUUID, step.UUID))
+ if !stepExist {
+ return nil, fmt.Errorf("WaitStep expect step '%s' (%s) to be created but found none", step.Name, step.UUID)
+ }
+ if stepState != stepStateStarted {
+ return nil, fmt.Errorf("WaitStep expect step '%s' (%s) to be '%s' but it is: %s", step.Name, step.UUID, stepStateStarted, stepState)
+ }
+
+ if tailShouldFail, _ := strconv.ParseBool(step.Environment[EnvKeyStepTailFail]); tailShouldFail {
+ return nil, fmt.Errorf("expected fail to read stdout of step")
+ }
+
+ return io.NopCloser(strings.NewReader(dummyExecStepOutput(step))), nil
+}
+
+func (e *dummy) DestroyStep(_ context.Context, step *backend.Step, taskUUID string) error {
+ log.Trace().Str("taskUUID", taskUUID).Msgf("stop step %s", step.Name)
+
+ _, exist := e.kv.Load("task_" + taskUUID)
+ if !exist {
+ return fmt.Errorf("expect env of workflow %s to exist but found none to destroy", taskUUID)
+ }
+
+ // check state
+ stepState, stepExist := e.kv.Load(fmt.Sprintf("task_%s_step_%s", taskUUID, step.UUID))
+ if !stepExist {
+ return fmt.Errorf("WaitStep expect step '%s' (%s) to be created but found none", step.Name, step.UUID)
+ }
+ if stepState != stepStateDone {
+ return fmt.Errorf("WaitStep expect step '%s' (%s) to be '%s' but it is: %s", step.Name, step.UUID, stepStateDone, stepState)
+ }
+
+ e.kv.Delete(fmt.Sprintf("task_%s_step_%s", taskUUID, step.UUID))
+ return nil
+}
+
+func (e *dummy) DestroyWorkflow(_ context.Context, _ *backend.Config, taskUUID string) error {
+ log.Trace().Str("taskUUID", taskUUID).Msgf("delete workflow environment")
+
+ _, exist := e.kv.Load("task_" + taskUUID)
+ if !exist {
+ return fmt.Errorf("expect env of workflow %s to exist but found none to destroy", taskUUID)
+ }
+ e.kv.Delete("task_" + taskUUID)
+ return nil
+}
+
+func dummyExecStepOutput(step *backend.Step) string {
+ return fmt.Sprintf(`StepName: %s
+StepType: %s
+StepUUID: %s
+StepCommands:
+------------------
+%s
+------------------
+`, step.Name, step.Type, step.UUID, strings.Join(step.Commands, "\n"))
+}
diff --git a/pipeline/backend/dummy/dummy_test.go b/pipeline/backend/dummy/dummy_test.go
new file mode 100644
index 000000000..f0c3d8586
--- /dev/null
+++ b/pipeline/backend/dummy/dummy_test.go
@@ -0,0 +1,168 @@
+// 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 dummy_test
+
+import (
+ "context"
+ "io"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+
+ "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/dummy"
+ "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
+)
+
+func TestSmalPipelineDummyRun(t *testing.T) {
+ dummyEngine := dummy.New()
+ ctx := context.Background()
+
+ assert.True(t, dummyEngine.IsAvailable(ctx))
+ assert.EqualValues(t, "dummy", dummyEngine.Name())
+ _, err := dummyEngine.Load(ctx)
+ assert.NoError(t, err)
+
+ assert.Error(t, dummyEngine.SetupWorkflow(ctx, nil, dummy.WorkflowSetupFailUUID))
+
+ t.Run("expect fail of step func with non setup workflow", func(t *testing.T) {
+ step := &types.Step{Name: "step1", UUID: "SID_1"}
+ nonExistWorkflowID := "WID_NONE"
+
+ err := dummyEngine.StartStep(ctx, step, nonExistWorkflowID)
+ assert.Error(t, err)
+
+ _, err = dummyEngine.TailStep(ctx, step, nonExistWorkflowID)
+ assert.Error(t, err)
+
+ _, err = dummyEngine.WaitStep(ctx, step, nonExistWorkflowID)
+ assert.Error(t, err)
+
+ err = dummyEngine.DestroyStep(ctx, step, nonExistWorkflowID)
+ assert.Error(t, err)
+ })
+
+ t.Run("step exec successfully", func(t *testing.T) {
+ step := &types.Step{
+ Name: "step1",
+ UUID: "SID_1",
+ Type: types.StepTypeCommands,
+ Environment: map[string]string{},
+ Commands: []string{"echo ja", "echo nein"},
+ }
+ workflowUUID := "WID_1"
+
+ assert.NoError(t, dummyEngine.SetupWorkflow(ctx, nil, workflowUUID))
+
+ assert.NoError(t, dummyEngine.StartStep(ctx, step, workflowUUID))
+
+ reader, err := dummyEngine.TailStep(ctx, step, workflowUUID)
+ assert.NoError(t, err)
+ log, err := io.ReadAll(reader)
+ assert.NoError(t, err)
+ assert.EqualValues(t, `StepName: step1
+StepType: commands
+StepUUID: SID_1
+StepCommands:
+------------------
+echo ja
+echo nein
+------------------
+`, string(log))
+
+ state, err := dummyEngine.WaitStep(ctx, step, workflowUUID)
+ assert.NoError(t, err)
+ assert.NoError(t, state.Error)
+ assert.EqualValues(t, 0, state.ExitCode)
+
+ assert.NoError(t, dummyEngine.DestroyStep(ctx, step, workflowUUID))
+
+ assert.NoError(t, dummyEngine.DestroyWorkflow(ctx, nil, workflowUUID))
+ })
+
+ t.Run("step exec error", func(t *testing.T) {
+ step := &types.Step{
+ Name: "dummy",
+ UUID: "SID_2",
+ Type: types.StepTypePlugin,
+ Environment: map[string]string{dummy.EnvKeyStepType: "plugin", dummy.EnvKeyStepExitCode: "1"},
+ }
+ workflowUUID := "WID_1"
+
+ assert.NoError(t, dummyEngine.SetupWorkflow(ctx, nil, workflowUUID))
+
+ assert.NoError(t, dummyEngine.StartStep(ctx, step, workflowUUID))
+
+ _, err := dummyEngine.TailStep(ctx, step, workflowUUID)
+ assert.NoError(t, err)
+
+ state, err := dummyEngine.WaitStep(ctx, step, workflowUUID)
+ assert.NoError(t, err)
+ assert.NoError(t, state.Error)
+ assert.EqualValues(t, 1, state.ExitCode)
+
+ assert.NoError(t, dummyEngine.DestroyStep(ctx, step, workflowUUID))
+
+ assert.NoError(t, dummyEngine.DestroyWorkflow(ctx, nil, workflowUUID))
+ })
+
+ t.Run("step tail error", func(t *testing.T) {
+ step := &types.Step{
+ Name: "dummy",
+ UUID: "SID_2",
+ Environment: map[string]string{dummy.EnvKeyStepTailFail: "true"},
+ }
+ workflowUUID := "WID_1"
+
+ assert.NoError(t, dummyEngine.SetupWorkflow(ctx, nil, workflowUUID))
+
+ assert.NoError(t, dummyEngine.StartStep(ctx, step, workflowUUID))
+
+ _, err := dummyEngine.TailStep(ctx, step, workflowUUID)
+ assert.Error(t, err)
+
+ _, err = dummyEngine.WaitStep(ctx, step, workflowUUID)
+ assert.NoError(t, err)
+
+ assert.NoError(t, dummyEngine.DestroyStep(ctx, step, workflowUUID))
+
+ assert.NoError(t, dummyEngine.DestroyWorkflow(ctx, nil, workflowUUID))
+ })
+
+ t.Run("step start fail", func(t *testing.T) {
+ step := &types.Step{
+ Name: "dummy",
+ UUID: "SID_2",
+ Type: types.StepTypeService,
+ Environment: map[string]string{dummy.EnvKeyStepType: "service", dummy.EnvKeyStepStartFail: "true"},
+ }
+ workflowUUID := "WID_1"
+
+ assert.NoError(t, dummyEngine.SetupWorkflow(ctx, nil, workflowUUID))
+
+ assert.Error(t, dummyEngine.StartStep(ctx, step, workflowUUID))
+
+ _, err := dummyEngine.TailStep(ctx, step, workflowUUID)
+ assert.Error(t, err)
+
+ state, err := dummyEngine.WaitStep(ctx, step, workflowUUID)
+ assert.Error(t, err)
+ assert.Error(t, state.Error)
+ assert.EqualValues(t, 0, state.ExitCode)
+
+ assert.Error(t, dummyEngine.DestroyStep(ctx, step, workflowUUID))
+
+ assert.NoError(t, dummyEngine.DestroyWorkflow(ctx, nil, workflowUUID))
+ })
+}
diff --git a/pipeline/backend/kubernetes/backend_options.go b/pipeline/backend/kubernetes/backend_options.go
index da3644670..fa64da9f1 100644
--- a/pipeline/backend/kubernetes/backend_options.go
+++ b/pipeline/backend/kubernetes/backend_options.go
@@ -16,6 +16,7 @@ type BackendOptions struct {
NodeSelector map[string]string `mapstructure:"nodeSelector"`
Tolerations []Toleration `mapstructure:"tolerations"`
SecurityContext *SecurityContext `mapstructure:"securityContext"`
+ Secrets []SecretRef `mapstructure:"secrets"`
}
// Resources defines two maps for kubernetes resource definitions.
@@ -65,6 +66,19 @@ type SecProfile struct {
type SecProfileType string
+// SecretRef defines Kubernetes secret reference.
+type SecretRef struct {
+ Name string `mapstructure:"name"`
+ Key string `mapstructure:"key"`
+ Target SecretTarget `mapstructure:"target"`
+}
+
+// SecretTarget defines secret mount target.
+type SecretTarget struct {
+ Env string `mapstructure:"env"`
+ File string `mapstructure:"file"`
+}
+
const (
SecProfileTypeRuntimeDefault SecProfileType = "RuntimeDefault"
SecProfileTypeLocalhost SecProfileType = "Localhost"
diff --git a/pipeline/backend/kubernetes/backend_options_test.go b/pipeline/backend/kubernetes/backend_options_test.go
index 3d5a73f32..3d868ced1 100644
--- a/pipeline/backend/kubernetes/backend_options_test.go
+++ b/pipeline/backend/kubernetes/backend_options_test.go
@@ -44,6 +44,22 @@ func Test_parseBackendOptions(t *testing.T) {
"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",
+ },
+ },
+ },
},
},
})
@@ -73,5 +89,17 @@ func Test_parseBackendOptions(t *testing.T) {
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"},
+ },
+ },
}, got)
}
diff --git a/pipeline/backend/kubernetes/flags.go b/pipeline/backend/kubernetes/flags.go
index 219595f09..910f52624 100644
--- a/pipeline/backend/kubernetes/flags.go
+++ b/pipeline/backend/kubernetes/flags.go
@@ -15,73 +15,78 @@
package kubernetes
import (
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
)
var Flags = []cli.Flag{
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_K8S_NAMESPACE"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_K8S_NAMESPACE"),
Name: "backend-k8s-namespace",
Usage: "backend k8s namespace",
Value: "woodpecker",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_K8S_VOLUME_SIZE"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_K8S_VOLUME_SIZE"),
Name: "backend-k8s-volume-size",
Usage: "backend k8s volume size (default 10G)",
Value: "10G",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_K8S_STORAGE_CLASS"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_K8S_STORAGE_CLASS"),
Name: "backend-k8s-storage-class",
Usage: "backend k8s storage class",
Value: "",
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_K8S_STORAGE_RWX"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_K8S_STORAGE_RWX"),
Name: "backend-k8s-storage-rwx",
Usage: "backend k8s storage access mode, should ReadWriteMany (RWX) instead of ReadWriteOnce (RWO) be used? (default: true)",
Value: true,
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_K8S_POD_LABELS"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_K8S_POD_LABELS"),
Name: "backend-k8s-pod-labels",
Usage: "backend k8s additional Agent-wide worker pod labels",
Value: "",
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_K8S_POD_LABELS_ALLOW_FROM_STEP"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_K8S_POD_LABELS_ALLOW_FROM_STEP"),
Name: "backend-k8s-pod-labels-allow-from-step",
Usage: "whether to allow using labels from step's backend options",
Value: false,
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_K8S_POD_ANNOTATIONS"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_K8S_POD_ANNOTATIONS"),
Name: "backend-k8s-pod-annotations",
Usage: "backend k8s additional Agent-wide worker pod annotations",
Value: "",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_K8S_POD_NODE_SELECTOR"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_K8S_POD_NODE_SELECTOR"),
Name: "backend-k8s-pod-node-selector",
Usage: "backend k8s Agent-wide worker pod node selector",
Value: "",
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_K8S_POD_ANNOTATIONS_ALLOW_FROM_STEP"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_K8S_POD_ANNOTATIONS_ALLOW_FROM_STEP"),
Name: "backend-k8s-pod-annotations-allow-from-step",
Usage: "whether to allow using annotations from step's backend options",
Value: false,
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_K8S_SECCTX_NONROOT"}, // cspell:words secctx nonroot
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_K8S_SECCTX_NONROOT"), // cspell:words secctx nonroot
Name: "backend-k8s-secctx-nonroot",
Usage: "`run as non root` Kubernetes security context option",
},
&cli.StringSliceFlag{
- EnvVars: []string{"WOODPECKER_BACKEND_K8S_PULL_SECRET_NAMES"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_K8S_PULL_SECRET_NAMES"),
Name: "backend-k8s-pod-image-pull-secret-names",
Usage: "backend k8s pull secret names for private registries",
- Value: cli.NewStringSlice("regcred"),
+ },
+ &cli.BoolFlag{
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_K8S_ALLOW_NATIVE_SECRETS"),
+ Name: "backend-k8s-allow-native-secrets",
+ Usage: "whether to allow existing Kubernetes secrets to be referenced from steps",
+ Value: false,
},
}
diff --git a/pipeline/backend/kubernetes/kubernetes.go b/pipeline/backend/kubernetes/kubernetes.go
index dc04403ff..7cde9f68c 100644
--- a/pipeline/backend/kubernetes/kubernetes.go
+++ b/pipeline/backend/kubernetes/kubernetes.go
@@ -25,7 +25,7 @@ import (
"time"
"github.com/rs/zerolog/log"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"gopkg.in/yaml.v3"
v1 "k8s.io/api/core/v1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -65,6 +65,7 @@ type config struct {
PodNodeSelector map[string]string
ImagePullSecretNames []string
SecurityContext SecurityContextConfig
+ NativeSecretsAllowFromStep bool
}
type SecurityContextConfig struct {
RunAsNonRoot bool
@@ -82,7 +83,7 @@ func newDefaultDeleteOptions() meta_v1.DeleteOptions {
func configFromCliContext(ctx context.Context) (*config, error) {
if ctx != nil {
- if c, ok := ctx.Value(types.CliContext).(*cli.Context); ok {
+ if c, ok := ctx.Value(types.CliCommand).(*cli.Command); ok {
config := config{
Namespace: c.String("backend-k8s-namespace"),
StorageClass: c.String("backend-k8s-storage-class"),
@@ -97,10 +98,7 @@ func configFromCliContext(ctx context.Context) (*config, error) {
SecurityContext: SecurityContextConfig{
RunAsNonRoot: c.Bool("backend-k8s-secctx-nonroot"), // cspell:words secctx nonroot
},
- }
- // TODO: remove in next major
- if len(config.ImagePullSecretNames) == 1 && config.ImagePullSecretNames[0] == "regcred" {
- log.Warn().Msg("WOODPECKER_BACKEND_K8S_PULL_SECRET_NAMES is set to the default ('regcred'). It will default to empty in Woodpecker 3.0. Set it explicitly before then.")
+ NativeSecretsAllowFromStep: c.Bool("backend-k8s-allow-native-secrets"),
}
// Unmarshal label and annotation settings here to ensure they're valid on startup
if labels := c.String("backend-k8s-pod-labels"); labels != "" {
@@ -252,7 +250,7 @@ func (e *kube) WaitStep(ctx context.Context, step *types.Step, taskUUID string)
}
if pod.Name == podName {
- if isImagePullBackOffState(pod) {
+ if isImagePullBackOffState(pod) || isInvalidImageName(pod) {
finished <- true
}
@@ -284,7 +282,7 @@ func (e *kube) WaitStep(ctx context.Context, step *types.Step, taskUUID string)
return nil, err
}
- if isImagePullBackOffState(pod) {
+ if isImagePullBackOffState(pod) || isInvalidImageName(pod) {
return nil, fmt.Errorf("could not pull image for pod %s", podName)
}
@@ -328,7 +326,7 @@ func (e *kube) TailStep(ctx context.Context, step *types.Step, taskUUID string)
}
if pod.Name == podName {
- if isImagePullBackOffState(pod) {
+ if isImagePullBackOffState(pod) || isInvalidImageName(pod) {
up <- true
}
switch pod.Status.Phase {
@@ -393,7 +391,6 @@ func (e *kube) DestroyStep(ctx context.Context, step *types.Step, taskUUID strin
func (e *kube) DestroyWorkflow(ctx context.Context, conf *types.Config, taskUUID string) error {
log.Trace().Str("taskUUID", taskUUID).Msg("deleting Kubernetes primitives")
- // Use noContext because the ctx sent to this function will be canceled/done in case of error or canceled by user.
for _, stage := range conf.Stages {
for _, step := range stage.Steps {
err := stopPod(ctx, e, step, defaultDeleteOptions)
diff --git a/pipeline/backend/kubernetes/pod.go b/pipeline/backend/kubernetes/pod.go
index b240d794a..53efbc8cd 100644
--- a/pipeline/backend/kubernetes/pod.go
+++ b/pipeline/backend/kubernetes/pod.go
@@ -38,17 +38,23 @@ const (
func mkPod(step *types.Step, config *config, podName, goos string, options BackendOptions) (*v1.Pod, error) {
var err error
+ nsp := newNativeSecretsProcessor(config, options.Secrets)
+ err = nsp.process()
+ if err != nil {
+ return nil, err
+ }
+
meta, err := podMeta(step, config, options, podName)
if err != nil {
return nil, err
}
- spec, err := podSpec(step, config, options)
+ spec, err := podSpec(step, config, options, nsp)
if err != nil {
return nil, err
}
- container, err := podContainer(step, podName, goos, options)
+ container, err := podContainer(step, podName, goos, options, nsp)
if err != nil {
return nil, err
}
@@ -78,7 +84,7 @@ func podMeta(step *types.Step, config *config, options BackendOptions, podName s
meta := meta_v1.ObjectMeta{
Name: podName,
Namespace: config.Namespace,
- Annotations: podAnnotations(config, options, podName),
+ Annotations: podAnnotations(config, options),
}
meta.Labels, err = podLabels(step, config, options)
@@ -120,7 +126,7 @@ func stepLabel(step *types.Step) (string, error) {
return toDNSName(step.Name)
}
-func podAnnotations(config *config, options BackendOptions, podName string) map[string]string {
+func podAnnotations(config *config, options BackendOptions) map[string]string {
annotations := make(map[string]string)
if len(options.Annotations) > 0 {
@@ -135,38 +141,35 @@ func podAnnotations(config *config, options BackendOptions, podName string) map[
log.Trace().Msgf("using annotations from the configuration: %v", config.PodAnnotations)
maps.Copy(annotations, config.PodAnnotations)
}
- securityContext := options.SecurityContext
- if securityContext != nil {
- key, value := apparmorAnnotation(podName, securityContext.ApparmorProfile)
- if key != nil && value != nil {
- annotations[*key] = *value
- }
- }
return annotations
}
-func podSpec(step *types.Step, config *config, options BackendOptions) (v1.PodSpec, error) {
+func podSpec(step *types.Step, config *config, options BackendOptions, nsp nativeSecretsProcessor) (v1.PodSpec, error) {
var err error
spec := v1.PodSpec{
RestartPolicy: v1.RestartPolicyNever,
RuntimeClassName: options.RuntimeClassName,
ServiceAccountName: options.ServiceAccountName,
- ImagePullSecrets: imagePullSecretsReferences(config.ImagePullSecretNames),
HostAliases: hostAliases(step.ExtraHosts),
NodeSelector: nodeSelector(options.NodeSelector, config.PodNodeSelector, step.Environment["CI_SYSTEM_PLATFORM"]),
Tolerations: tolerations(options.Tolerations),
SecurityContext: podSecurityContext(options.SecurityContext, config.SecurityContext, step.Privileged),
}
- spec.Volumes, err = volumes(step.Volumes)
+ spec.Volumes, err = pvcVolumes(step.Volumes)
if err != nil {
return spec, err
}
+ log.Trace().Msgf("using the image pull secrets: %v", config.ImagePullSecretNames)
+ spec.ImagePullSecrets = secretsReferences(config.ImagePullSecretNames)
+
+ spec.Volumes = append(spec.Volumes, nsp.volumes...)
+
return spec, nil
}
-func podContainer(step *types.Step, podName, goos string, options BackendOptions) (v1.Container, error) {
+func podContainer(step *types.Step, podName, goos string, options BackendOptions, nsp nativeSecretsProcessor) (v1.Container, error) {
var err error
container := v1.Container{
Name: podName,
@@ -201,10 +204,14 @@ func podContainer(step *types.Step, podName, goos string, options BackendOptions
return container, err
}
+ container.EnvFrom = append(container.EnvFrom, nsp.envFromSources...)
+ container.Env = append(container.Env, nsp.envVars...)
+ container.VolumeMounts = append(container.VolumeMounts, nsp.mounts...)
+
return container, nil
}
-func volumes(volumes []string) ([]v1.Volume, error) {
+func pvcVolumes(volumes []string) ([]v1.Volume, error) {
var vols []v1.Volume
for _, v := range volumes {
@@ -212,13 +219,13 @@ func volumes(volumes []string) ([]v1.Volume, error) {
if err != nil {
return nil, err
}
- vols = append(vols, volume(volumeName))
+ vols = append(vols, pvcVolume(volumeName))
}
return vols, nil
}
-func volume(name string) v1.Volume {
+func pvcVolume(name string) v1.Volume {
pvcSource := v1.PersistentVolumeClaimVolumeSource{
ClaimName: name,
ReadOnly: false,
@@ -285,22 +292,6 @@ func hostAlias(extraHost types.HostAlias) v1.HostAlias {
}
}
-func imagePullSecretsReferences(imagePullSecretNames []string) []v1.LocalObjectReference {
- log.Trace().Msgf("using the image pull secrets: %v", imagePullSecretNames)
-
- secretReferences := make([]v1.LocalObjectReference, len(imagePullSecretNames))
- for i, imagePullSecretName := range imagePullSecretNames {
- secretReferences[i] = imagePullSecretsReference(imagePullSecretName)
- }
- return secretReferences
-}
-
-func imagePullSecretsReference(imagePullSecretName string) v1.LocalObjectReference {
- return v1.LocalObjectReference{
- Name: imagePullSecretName,
- }
-}
-
func resourceRequirements(resources Resources) (v1.ResourceRequirements, error) {
var err error
requirements := v1.ResourceRequirements{}
@@ -379,11 +370,12 @@ func toleration(backendToleration Toleration) v1.Toleration {
func podSecurityContext(sc *SecurityContext, secCtxConf SecurityContextConfig, stepPrivileged bool) *v1.PodSecurityContext {
var (
- nonRoot *bool
- user *int64
- group *int64
- fsGroup *int64
- seccomp *v1.SeccompProfile
+ nonRoot *bool
+ user *int64
+ group *int64
+ fsGroup *int64
+ seccomp *v1.SeccompProfile
+ apparmor *v1.AppArmorProfile
)
if secCtxConf.RunAsNonRoot {
@@ -412,6 +404,7 @@ func podSecurityContext(sc *SecurityContext, secCtxConf SecurityContextConfig, s
}
seccomp = seccompProfile(sc.SeccompProfile)
+ apparmor = apparmorProfile(sc.ApparmorProfile)
}
if nonRoot == nil && user == nil && group == nil && fsGroup == nil && seccomp == nil {
@@ -419,11 +412,12 @@ func podSecurityContext(sc *SecurityContext, secCtxConf SecurityContextConfig, s
}
securityContext := &v1.PodSecurityContext{
- RunAsNonRoot: nonRoot,
- RunAsUser: user,
- RunAsGroup: group,
- FSGroup: fsGroup,
- SeccompProfile: seccomp,
+ RunAsNonRoot: nonRoot,
+ RunAsUser: user,
+ RunAsGroup: group,
+ FSGroup: fsGroup,
+ SeccompProfile: seccomp,
+ AppArmorProfile: apparmor,
}
log.Trace().Msgf("pod security context that will be used: %v", securityContext)
return securityContext
@@ -445,6 +439,22 @@ func seccompProfile(scp *SecProfile) *v1.SeccompProfile {
return seccompProfile
}
+func apparmorProfile(scp *SecProfile) *v1.AppArmorProfile {
+ if scp == nil || len(scp.Type) == 0 {
+ return nil
+ }
+ log.Trace().Msgf("using AppArmor profile: %v", scp)
+
+ apparmorProfile := &v1.AppArmorProfile{
+ Type: v1.AppArmorProfileType(scp.Type),
+ }
+ if len(scp.LocalhostProfile) > 0 {
+ apparmorProfile.LocalhostProfile = &scp.LocalhostProfile
+ }
+
+ return apparmorProfile
+}
+
func containerSecurityContext(sc *SecurityContext, stepPrivileged bool) *v1.SecurityContext {
if !stepPrivileged {
return nil
@@ -473,36 +483,6 @@ func containerSecurityContext(sc *SecurityContext, stepPrivileged bool) *v1.Secu
return nil
}
-func apparmorAnnotation(containerName string, scp *SecProfile) (*string, *string) {
- if scp == nil {
- return nil, nil
- }
- log.Trace().Msgf("using AppArmor profile: %v", scp)
-
- var (
- profileType string
- profilePath string
- )
-
- if scp.Type == SecProfileTypeRuntimeDefault {
- profileType = "runtime"
- profilePath = "default"
- }
-
- if scp.Type == SecProfileTypeLocalhost {
- profileType = "localhost"
- profilePath = scp.LocalhostProfile
- }
-
- if len(profileType) == 0 {
- return nil, nil
- }
-
- key := v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + containerName
- value := profileType + "/" + profilePath
- return &key, &value
-}
-
func mapToEnvVars(m map[string]string) []v1.EnvVar {
var ev []v1.EnvVar
for k, v := range m {
diff --git a/pipeline/backend/kubernetes/pod_test.go b/pipeline/backend/kubernetes/pod_test.go
index db0da7488..4ea4cc687 100644
--- a/pipeline/backend/kubernetes/pod_test.go
+++ b/pipeline/backend/kubernetes/pod_test.go
@@ -65,7 +65,7 @@ func TestStepLabel(t *testing.T) {
}
func TestTinyPod(t *testing.T) {
- expected := `
+ const expected = `
{
"metadata": {
"name": "wp-01he8bebctabr3kgk0qj36d2me-0",
@@ -149,7 +149,7 @@ func TestTinyPod(t *testing.T) {
}
func TestFullPod(t *testing.T) {
- expected := `
+ const expected = `
{
"metadata": {
"name": "wp-01he8bebctabr3kgk0qj36d2me-0",
@@ -162,7 +162,6 @@ func TestFullPod(t *testing.T) {
},
"annotations": {
"apps.kubernetes.io/pod-index": "0",
- "container.apparmor.security.beta.kubernetes.io/wp-01he8bebctabr3kgk0qj36d2me-0": "localhost/k8s-apparmor-example-deny-write",
"kubernetes.io/limit-ranger": "LimitRanger plugin set: cpu, memory request and limit for container"
}
},
@@ -250,9 +249,13 @@ func TestFullPod(t *testing.T) {
"runAsGroup": 101,
"runAsNonRoot": true,
"fsGroup": 101,
+ "appArmorProfile": {
+ "type": "Localhost",
+ "localhostProfile": "k8s-apparmor-example-deny-write"
+ },
"seccompProfile": {
- "type": "Localhost",
- "localhostProfile": "profiles/audit.json"
+ "type": "Localhost",
+ "localhostProfile": "profiles/audit.json"
}
},
"imagePullSecrets": [
@@ -426,7 +429,7 @@ func TestPodPrivilege(t *testing.T) {
}
func TestScratchPod(t *testing.T) {
- expected := `
+ const expected = `
{
"metadata": {
"name": "wp-01he8bebctabr3kgk0qj36d2me-0",
@@ -467,6 +470,124 @@ func TestScratchPod(t *testing.T) {
assert.NoError(t, err)
ja := jsonassert.New(t)
- t.Log(string(podJSON))
+ ja.Assertf(string(podJSON), expected)
+}
+
+func TestSecrets(t *testing.T) {
+ const expected = `
+ {
+ "metadata": {
+ "name": "wp-3kgk0qj36d2me01he8bebctabr-0",
+ "namespace": "woodpecker",
+ "creationTimestamp": null,
+ "labels": {
+ "step": "test-secrets"
+ }
+ },
+ "spec": {
+ "volumes": [
+ {
+ "name": "workspace",
+ "persistentVolumeClaim": {
+ "claimName": "workspace"
+ }
+ },
+ {
+ "name": "reg-cred",
+ "secret": {
+ "secretName": "reg-cred"
+ }
+ }
+ ],
+ "containers": [
+ {
+ "name": "wp-3kgk0qj36d2me01he8bebctabr-0",
+ "image": "alpine",
+ "envFrom": [
+ {
+ "secretRef": {
+ "name": "ghcr-push-secret"
+ }
+ }
+ ],
+ "env": [
+ {
+ "name": "CGO",
+ "value": "0"
+ },
+ {
+ "name": "AWS_ACCESS_KEY_ID",
+ "valueFrom": {
+ "secretKeyRef": {
+ "name": "aws-ecr",
+ "key": "AWS_ACCESS_KEY_ID"
+ }
+ }
+ },
+ {
+ "name": "AWS_SECRET_ACCESS_KEY",
+ "valueFrom": {
+ "secretKeyRef": {
+ "name": "aws-ecr",
+ "key": "access-key"
+ }
+ }
+ }
+ ],
+ "resources": {},
+ "volumeMounts": [
+ {
+ "name": "workspace",
+ "mountPath": "/woodpecker/src"
+ },
+ {
+ "name": "reg-cred",
+ "mountPath": "~/.docker/config.json",
+ "subPath": ".dockerconfigjson",
+ "readOnly": true
+ }
+ ]
+ }
+ ],
+ "restartPolicy": "Never"
+ },
+ "status": {}
+ }`
+
+ pod, err := mkPod(&types.Step{
+ Name: "test-secrets",
+ Image: "alpine",
+ Environment: map[string]string{"CGO": "0"},
+ Volumes: []string{"workspace:/woodpecker/src"},
+ }, &config{
+ Namespace: "woodpecker",
+ NativeSecretsAllowFromStep: true,
+ }, "wp-3kgk0qj36d2me01he8bebctabr-0", "linux/amd64", BackendOptions{
+ Secrets: []SecretRef{
+ {
+ Name: "ghcr-push-secret",
+ },
+ {
+ Name: "aws-ecr",
+ Key: "AWS_ACCESS_KEY_ID",
+ },
+ {
+ Name: "aws-ecr",
+ Key: "access-key",
+ Target: SecretTarget{Env: "AWS_SECRET_ACCESS_KEY"},
+ },
+ {
+ Name: "reg-cred",
+ Key: ".dockerconfigjson",
+ Target: SecretTarget{File: "~/.docker/config.json"},
+ },
+ },
+ })
+ assert.NoError(t, err)
+
+ podJSON, err := json.Marshal(pod)
+ assert.NoError(t, err)
+
+ ja := jsonassert.New(t)
ja.Assertf(string(podJSON), expected)
}
diff --git a/pipeline/backend/kubernetes/secrets.go b/pipeline/backend/kubernetes/secrets.go
new file mode 100644
index 000000000..47fb401da
--- /dev/null
+++ b/pipeline/backend/kubernetes/secrets.go
@@ -0,0 +1,191 @@
+// 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 kubernetes
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/rs/zerolog/log"
+ v1 "k8s.io/api/core/v1"
+)
+
+type nativeSecretsProcessor struct {
+ config *config
+ secrets []SecretRef
+ envFromSources []v1.EnvFromSource
+ envVars []v1.EnvVar
+ volumes []v1.Volume
+ mounts []v1.VolumeMount
+}
+
+func newNativeSecretsProcessor(config *config, secrets []SecretRef) nativeSecretsProcessor {
+ return nativeSecretsProcessor{
+ config: config,
+ secrets: secrets,
+ }
+}
+
+func (nsp *nativeSecretsProcessor) isEnabled() bool {
+ return nsp.config.NativeSecretsAllowFromStep
+}
+
+func (nsp *nativeSecretsProcessor) process() error {
+ if len(nsp.secrets) > 0 {
+ if !nsp.isEnabled() {
+ log.Debug().Msg("Secret names were defined in backend options, but secret access is disallowed by instance configuration.")
+ return nil
+ }
+ } else {
+ return nil
+ }
+
+ for _, secret := range nsp.secrets {
+ switch {
+ case secret.isSimple():
+ simpleSecret, err := secret.toEnvFromSource()
+ if err != nil {
+ return err
+ }
+ nsp.envFromSources = append(nsp.envFromSources, simpleSecret)
+ case secret.isAdvanced():
+ advancedSecret, err := secret.toEnvVar()
+ if err != nil {
+ return err
+ }
+ nsp.envVars = append(nsp.envVars, advancedSecret)
+ case secret.isFile():
+ volume, err := secret.toVolume()
+ if err != nil {
+ return err
+ }
+ nsp.volumes = append(nsp.volumes, volume)
+
+ mount, err := secret.toVolumeMount()
+ if err != nil {
+ return err
+ }
+ nsp.mounts = append(nsp.mounts, mount)
+ }
+ }
+
+ return nil
+}
+
+func (sr SecretRef) isSimple() bool {
+ return len(sr.Key) == 0 && len(sr.Target.Env) == 0 && !sr.isFile()
+}
+
+func (sr SecretRef) isAdvanced() bool {
+ return (len(sr.Key) > 0 || len(sr.Target.Env) > 0) && !sr.isFile()
+}
+
+func (sr SecretRef) isFile() bool {
+ return len(sr.Target.File) > 0
+}
+
+func (sr SecretRef) toEnvFromSource() (v1.EnvFromSource, error) {
+ env := v1.EnvFromSource{}
+
+ if !sr.isSimple() {
+ return env, fmt.Errorf("secret '%s' is not simple reference", sr.Name)
+ }
+
+ env = v1.EnvFromSource{
+ SecretRef: &v1.SecretEnvSource{
+ LocalObjectReference: secretReference(sr.Name),
+ },
+ }
+
+ return env, nil
+}
+
+func (sr SecretRef) toEnvVar() (v1.EnvVar, error) {
+ envVar := v1.EnvVar{}
+
+ if !sr.isAdvanced() {
+ return envVar, fmt.Errorf("secret '%s' is not advanced reference", sr.Name)
+ }
+
+ envVar.ValueFrom = &v1.EnvVarSource{
+ SecretKeyRef: &v1.SecretKeySelector{
+ LocalObjectReference: secretReference(sr.Name),
+ Key: sr.Key,
+ },
+ }
+
+ if len(sr.Target.Env) > 0 {
+ envVar.Name = sr.Target.Env
+ } else {
+ envVar.Name = strings.ToUpper(sr.Key)
+ }
+
+ return envVar, nil
+}
+
+func (sr SecretRef) toVolume() (v1.Volume, error) {
+ var err error
+ volume := v1.Volume{}
+
+ if !sr.isFile() {
+ return volume, fmt.Errorf("secret '%s' is not file reference", sr.Name)
+ }
+
+ volume.Name, err = volumeName(sr.Name)
+ if err != nil {
+ return volume, err
+ }
+
+ volume.Secret = &v1.SecretVolumeSource{
+ SecretName: sr.Name,
+ }
+
+ return volume, nil
+}
+
+func (sr SecretRef) toVolumeMount() (v1.VolumeMount, error) {
+ var err error
+ mount := v1.VolumeMount{
+ ReadOnly: true,
+ }
+
+ if !sr.isFile() {
+ return mount, fmt.Errorf("secret '%s' is not file reference", sr.Name)
+ }
+
+ mount.Name, err = volumeName(sr.Name)
+ if err != nil {
+ return mount, err
+ }
+
+ mount.MountPath = sr.Target.File
+ mount.SubPath = sr.Key
+
+ return mount, nil
+}
+
+func secretsReferences(names []string) []v1.LocalObjectReference {
+ secretReferences := make([]v1.LocalObjectReference, len(names))
+ for i, imagePullSecretName := range names {
+ secretReferences[i] = secretReference(imagePullSecretName)
+ }
+ return secretReferences
+}
+
+func secretReference(name string) v1.LocalObjectReference {
+ return v1.LocalObjectReference{
+ Name: name,
+ }
+}
diff --git a/pipeline/backend/kubernetes/secrets_test.go b/pipeline/backend/kubernetes/secrets_test.go
new file mode 100644
index 000000000..fe0c76097
--- /dev/null
+++ b/pipeline/backend/kubernetes/secrets_test.go
@@ -0,0 +1,180 @@
+// 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 kubernetes
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ v1 "k8s.io/api/core/v1"
+)
+
+func TestNativeSecretsEnabled(t *testing.T) {
+ nsp := newNativeSecretsProcessor(&config{
+ NativeSecretsAllowFromStep: true,
+ }, nil)
+ assert.Equal(t, true, nsp.isEnabled())
+}
+
+func TestNativeSecretsDisabled(t *testing.T) {
+ nsp := newNativeSecretsProcessor(&config{
+ NativeSecretsAllowFromStep: false,
+ }, []SecretRef{
+ {
+ Name: "env-simple",
+ },
+ {
+ Name: "env-advanced",
+ Key: "key",
+ Target: SecretTarget{
+ Env: "ENV_VAR",
+ },
+ },
+ {
+ Name: "env-file",
+ Key: "cert",
+ Target: SecretTarget{
+ File: "/etc/ca/x3.cert",
+ },
+ },
+ })
+ assert.Equal(t, false, nsp.isEnabled())
+
+ err := nsp.process()
+ assert.NoError(t, err)
+ assert.Empty(t, nsp.envFromSources)
+ assert.Empty(t, nsp.envVars)
+ assert.Empty(t, nsp.volumes)
+ assert.Empty(t, nsp.mounts)
+}
+
+func TestSimpleSecret(t *testing.T) {
+ nsp := newNativeSecretsProcessor(&config{
+ NativeSecretsAllowFromStep: true,
+ }, []SecretRef{
+ {
+ Name: "test-secret",
+ },
+ })
+
+ err := nsp.process()
+ assert.NoError(t, err)
+ assert.Empty(t, nsp.envVars)
+ assert.Empty(t, nsp.volumes)
+ assert.Empty(t, nsp.mounts)
+ assert.Equal(t, []v1.EnvFromSource{
+ {
+ SecretRef: &v1.SecretEnvSource{
+ LocalObjectReference: v1.LocalObjectReference{Name: "test-secret"},
+ },
+ },
+ }, nsp.envFromSources)
+}
+
+func TestSecretWithKey(t *testing.T) {
+ nsp := newNativeSecretsProcessor(&config{
+ NativeSecretsAllowFromStep: true,
+ }, []SecretRef{
+ {
+ Name: "test-secret",
+ Key: "access_key",
+ },
+ })
+
+ err := nsp.process()
+ assert.NoError(t, err)
+ assert.Empty(t, nsp.envFromSources)
+ assert.Empty(t, nsp.volumes)
+ assert.Empty(t, nsp.mounts)
+ assert.Equal(t, []v1.EnvVar{
+ {
+ Name: "ACCESS_KEY",
+ ValueFrom: &v1.EnvVarSource{
+ SecretKeyRef: &v1.SecretKeySelector{
+ LocalObjectReference: v1.LocalObjectReference{Name: "test-secret"},
+ Key: "access_key",
+ },
+ },
+ },
+ }, nsp.envVars)
+}
+
+func TestSecretWithKeyMapping(t *testing.T) {
+ nsp := newNativeSecretsProcessor(&config{
+ NativeSecretsAllowFromStep: true,
+ }, []SecretRef{
+ {
+ Name: "test-secret",
+ Key: "aws-secret",
+ Target: SecretTarget{
+ Env: "AWS_SECRET_ACCESS_KEY",
+ },
+ },
+ })
+
+ err := nsp.process()
+ assert.NoError(t, err)
+ assert.Empty(t, nsp.envFromSources)
+ assert.Empty(t, nsp.volumes)
+ assert.Empty(t, nsp.mounts)
+ assert.Equal(t, []v1.EnvVar{
+ {
+ Name: "AWS_SECRET_ACCESS_KEY",
+ ValueFrom: &v1.EnvVarSource{
+ SecretKeyRef: &v1.SecretKeySelector{
+ LocalObjectReference: v1.LocalObjectReference{Name: "test-secret"},
+ Key: "aws-secret",
+ },
+ },
+ },
+ }, nsp.envVars)
+}
+
+func TestFileSecret(t *testing.T) {
+ nsp := newNativeSecretsProcessor(&config{
+ NativeSecretsAllowFromStep: true,
+ }, []SecretRef{
+ {
+ Name: "reg-cred",
+ Key: ".dockerconfigjson",
+ Target: SecretTarget{
+ File: "~/.docker/config.json",
+ },
+ },
+ })
+
+ err := nsp.process()
+ assert.NoError(t, err)
+ assert.Empty(t, nsp.envFromSources)
+ assert.Empty(t, nsp.envVars)
+ assert.Equal(t, []v1.Volume{
+ {
+ Name: "reg-cred",
+ VolumeSource: v1.VolumeSource{
+ Secret: &v1.SecretVolumeSource{
+ SecretName: "reg-cred",
+ },
+ },
+ },
+ }, nsp.volumes)
+ assert.Equal(t, []v1.VolumeMount{
+ {
+ Name: "reg-cred",
+ ReadOnly: true,
+ MountPath: "~/.docker/config.json",
+ SubPath: ".dockerconfigjson",
+ },
+ }, nsp.mounts)
+}
diff --git a/pipeline/backend/kubernetes/utils.go b/pipeline/backend/kubernetes/utils.go
index 1393c423b..ec601bccc 100644
--- a/pipeline/backend/kubernetes/utils.go
+++ b/pipeline/backend/kubernetes/utils.go
@@ -65,6 +65,18 @@ func isImagePullBackOffState(pod *v1.Pod) bool {
return false
}
+func isInvalidImageName(pod *v1.Pod) bool {
+ for _, containerState := range pod.Status.ContainerStatuses {
+ if containerState.State.Waiting != nil {
+ if containerState.State.Waiting.Reason == "InvalidImageName" {
+ return true
+ }
+ }
+ }
+
+ return false
+}
+
// getClientOutOfCluster returns a k8s client set to the request from outside of cluster.
func getClientOutOfCluster() (kubernetes.Interface, error) {
kubeConfigPath := os.Getenv("KUBECONFIG") // cspell:words KUBECONFIG
diff --git a/pipeline/backend/local/command.go b/pipeline/backend/local/command.go
index e36fe2451..917c8ccf3 100644
--- a/pipeline/backend/local/command.go
+++ b/pipeline/backend/local/command.go
@@ -21,7 +21,7 @@ import (
"os"
"strings"
- "github.com/alessio/shellescape"
+ "al.essio.dev/pkg/shellescape"
)
func (e *local) genCmdByShell(shell string, cmdList []string) (args []string, err error) {
diff --git a/pipeline/backend/local/flags.go b/pipeline/backend/local/flags.go
index 64ec61fb9..f4b621ea7 100644
--- a/pipeline/backend/local/flags.go
+++ b/pipeline/backend/local/flags.go
@@ -17,13 +17,13 @@ package local
import (
"os"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
)
var Flags = []cli.Flag{
&cli.StringFlag{
Name: "backend-local-temp-dir",
- EnvVars: []string{"WOODPECKER_BACKEND_LOCAL_TEMP_DIR"},
+ Sources: cli.EnvVars("WOODPECKER_BACKEND_LOCAL_TEMP_DIR"),
Usage: "set a different temp dir to clone workflows into",
Value: os.TempDir(),
},
diff --git a/pipeline/backend/local/local.go b/pipeline/backend/local/local.go
index 08f6abd16..5e11f68f0 100644
--- a/pipeline/backend/local/local.go
+++ b/pipeline/backend/local/local.go
@@ -27,7 +27,7 @@ import (
"sync"
"github.com/rs/zerolog/log"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"golang.org/x/text/encoding/unicode"
"golang.org/x/text/transform"
@@ -62,8 +62,14 @@ func (e *local) Name() string {
return "local"
}
-func (e *local) IsAvailable(context.Context) bool {
- return true
+func (e *local) IsAvailable(ctx context.Context) bool {
+ if c, ok := ctx.Value(types.CliCommand).(*cli.Command); ok {
+ if c.String("backend-engine") == e.Name() {
+ return true
+ }
+ }
+ _, inContainer := os.LookupEnv("WOODPECKER_IN_CONTAINER")
+ return !inContainer
}
func (e *local) Flags() []cli.Flag {
@@ -71,7 +77,7 @@ func (e *local) Flags() []cli.Flag {
}
func (e *local) Load(ctx context.Context) (*types.BackendInfo, error) {
- c, ok := ctx.Value(types.CliContext).(*cli.Context)
+ c, ok := ctx.Value(types.CliCommand).(*cli.Command)
if ok {
e.tempDir = c.String("backend-local-temp-dir")
}
diff --git a/pipeline/backend/types/backend.go b/pipeline/backend/types/backend.go
index 0ef6b6859..4687018f8 100644
--- a/pipeline/backend/types/backend.go
+++ b/pipeline/backend/types/backend.go
@@ -18,7 +18,7 @@ import (
"context"
"io"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
)
// Backend defines a container orchestration backend and is used
diff --git a/pipeline/backend/types/config.go b/pipeline/backend/types/config.go
index 16843a830..bf07e9e7a 100644
--- a/pipeline/backend/types/config.go
+++ b/pipeline/backend/types/config.go
@@ -22,10 +22,10 @@ type Config struct {
Secrets []*Secret `json:"secrets"` // secret definitions
}
-// CliContext is the context key to pass cli context to backends if needed.
-var CliContext ContextKey
+// CliCommand is the context key to pass cli context to backends if needed.
+var CliCommand contextKey
-// ContextKey is just an empty struct. It exists so CliContext can be
+// contextKey is just an empty struct. It exists so CliCommand can be
// an immutable public variable with a unique type. It's immutable
// because nobody else can create a ContextKey, being unexported.
-type ContextKey struct{}
+type contextKey struct{}
diff --git a/pipeline/const.go b/pipeline/const.go
index a4bec9789..473e961ab 100644
--- a/pipeline/const.go
+++ b/pipeline/const.go
@@ -14,4 +14,10 @@
package pipeline
-const ExitCodeKilled int = 137
+const (
+ ExitCodeKilled int = 137
+
+ // Store no more than 1mb in a log-line as 4mb is the limit of a grpc message
+ // and log-lines needs to be parsed by the browsers later on.
+ MaxLogLineLength int = 1 * 1024 * 1024 // 1mb
+)
diff --git a/pipeline/frontend/metadata/drone_compatibility.go b/pipeline/frontend/metadata/drone_compatibility.go
index 16dae443a..c6de5510d 100644
--- a/pipeline/frontend/metadata/drone_compatibility.go
+++ b/pipeline/frontend/metadata/drone_compatibility.go
@@ -20,6 +20,7 @@ func SetDroneEnviron(env map[string]string) {
// webhook
copyEnv("CI_COMMIT_BRANCH", "DRONE_BRANCH", env)
copyEnv("CI_COMMIT_PULL_REQUEST", "DRONE_PULL_REQUEST", env)
+ copyEnv("CI_COMMIT_PULL_REQUEST", "PULLREQUEST_DRONE_PULL_REQUEST", env)
copyEnv("CI_COMMIT_TAG", "DRONE_TAG", env)
copyEnv("CI_COMMIT_SOURCE_BRANCH", "DRONE_SOURCE_BRANCH", env)
copyEnv("CI_COMMIT_TARGET_BRANCH", "DRONE_TARGET_BRANCH", env)
@@ -27,18 +28,16 @@ func SetDroneEnviron(env map[string]string) {
copyEnv("CI_PIPELINE_NUMBER", "DRONE_BUILD_NUMBER", env)
copyEnv("CI_PIPELINE_PARENT", "DRONE_BUILD_PARENT", env)
copyEnv("CI_PIPELINE_EVENT", "DRONE_BUILD_EVENT", env)
- copyEnv("CI_PIPELINE_STATUS", "DRONE_BUILD_STATUS", env)
copyEnv("CI_PIPELINE_URL", "DRONE_BUILD_LINK", env)
copyEnv("CI_PIPELINE_CREATED", "DRONE_BUILD_CREATED", env)
copyEnv("CI_PIPELINE_STARTED", "DRONE_BUILD_STARTED", env)
- copyEnv("CI_PIPELINE_FINISHED", "DRONE_BUILD_FINISHED", env)
// commit
copyEnv("CI_COMMIT_SHA", "DRONE_COMMIT", env)
copyEnv("CI_COMMIT_SHA", "DRONE_COMMIT_SHA", env)
copyEnv("CI_PREV_COMMIT_SHA", "DRONE_COMMIT_BEFORE", env)
copyEnv("CI_COMMIT_REF", "DRONE_COMMIT_REF", env)
copyEnv("CI_COMMIT_BRANCH", "DRONE_COMMIT_BRANCH", env)
- copyEnv("CI_COMMIT_URL", "DRONE_COMMIT_LINK", env)
+ copyEnv("CI_PIPELINE_FORGE_URL", "DRONE_COMMIT_LINK", env)
copyEnv("CI_COMMIT_MESSAGE", "DRONE_COMMIT_MESSAGE", env)
copyEnv("CI_COMMIT_AUTHOR", "DRONE_COMMIT_AUTHOR", env)
copyEnv("CI_COMMIT_AUTHOR", "DRONE_COMMIT_AUTHOR_NAME", env)
@@ -58,6 +57,18 @@ func SetDroneEnviron(env map[string]string) {
// misc
copyEnv("CI_SYSTEM_HOST", "DRONE_SYSTEM_HOST", env)
copyEnv("CI_STEP_NUMBER", "DRONE_STEP_NUMBER", env)
+
+ env["DRONE_BUILD_STATUS"] = "success"
+
+ // some quirks
+
+ // Legacy env var to prevent the plugin from throwing an error
+ // when converting an empty string to a number
+ //
+ // plugins affected: "plugins/manifest"
+ if env["CI_COMMIT_PULL_REQUEST"] == "" {
+ env["PULLREQUEST_DRONE_PULL_REQUEST"] = "0"
+ }
}
func copyEnv(woodpecker, drone string, env map[string]string) {
diff --git a/pipeline/frontend/metadata/drone_compatibility_test.go b/pipeline/frontend/metadata/drone_compatibility_test.go
index c2334585c..e8bb86ab4 100644
--- a/pipeline/frontend/metadata/drone_compatibility_test.go
+++ b/pipeline/frontend/metadata/drone_compatibility_test.go
@@ -23,13 +23,14 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/metadata"
)
-func TestSetDroneEnviron(t *testing.T) {
+func TestSetDroneEnvironOnPull(t *testing.T) {
woodpeckerVars := `CI=woodpecker
CI_COMMIT_AUTHOR=6543
CI_COMMIT_AUTHOR_AVATAR=https://codeberg.org/avatars/09a234c768cb9bca78f6b2f82d6af173
CI_COMMIT_BRANCH=main
CI_COMMIT_MESSAGE=fix testscript
CI_COMMIT_PULL_REQUEST=9
+CI_COMMIT_PULL_REQUEST_LABELS=tests,bugfix
CI_COMMIT_REF=refs/pull/9/head
CI_COMMIT_REFSPEC=fix_fail-on-err:main
CI_COMMIT_SHA=a778b069d9f5992786d2db9be493b43868cfce76
@@ -38,10 +39,8 @@ CI_COMMIT_TARGET_BRANCH=main
CI_MACHINE=7939910e431b
CI_PIPELINE_CREATED=1685749339
CI_PIPELINE_EVENT=pull_request
-CI_PIPELINE_FINISHED=1685749350
CI_PIPELINE_NUMBER=41
CI_PIPELINE_STARTED=1685749339
-CI_PIPELINE_STATUS=success
CI_PREV_COMMIT_AUTHOR=6543
CI_PREV_COMMIT_AUTHOR_AVATAR=https://codeberg.org/avatars/09a234c768cb9bca78f6b2f82d6af173
CI_PREV_COMMIT_BRANCH=main
@@ -61,10 +60,8 @@ CI_REPO_DEFAULT_BRANCH=main
CI_REPO_NAME=todo-checker
CI_REPO_OWNER=Epsilon_02
CI_REPO_SCM=git
-CI_STEP_FINISHED=1685749350
CI_STEP_NAME=wp_01h1z7v5d1tskaqjexw0ng6w7d_0_step_3
CI_STEP_STARTED=1685749339
-CI_STEP_STATUS=success
CI_SYSTEM_PLATFORM=linux/amd64
CI_SYSTEM_HOST=ci.codeberg.org
CI_SYSTEM_NAME=woodpecker
@@ -76,7 +73,6 @@ CI_WORKSPACE=/woodpecker/src/codeberg.org/Epsilon_02/todo-checker`
droneVars := `DRONE_BRANCH=main
DRONE_BUILD_CREATED=1685749339
DRONE_BUILD_EVENT=pull_request
-DRONE_BUILD_FINISHED=1685749350
DRONE_BUILD_NUMBER=41
DRONE_BUILD_STARTED=1685749339
DRONE_BUILD_STATUS=success
@@ -99,7 +95,126 @@ DRONE_REPO_OWNER=Epsilon_02
DRONE_REPO_SCM=git
DRONE_SOURCE_BRANCH=fix_fail-on-err
DRONE_SYSTEM_HOST=ci.codeberg.org
-DRONE_TARGET_BRANCH=main`
+DRONE_TARGET_BRANCH=main
+PULLREQUEST_DRONE_PULL_REQUEST=9`
+
+ env := convertListToEnvMap(t, woodpeckerVars)
+ metadata.SetDroneEnviron(env)
+ // filter only new added env vars
+ for k := range convertListToEnvMap(t, woodpeckerVars) {
+ delete(env, k)
+ }
+ assert.EqualValues(t, convertListToEnvMap(t, droneVars), env)
+}
+
+func TestSetDroneEnvironOnPush(t *testing.T) {
+ woodpeckerVars := `CI_COMMIT_AUTHOR=test
+CI_COMMIT_AUTHOR_AVATAR=http://1.2.3.4:3000/avatars/dd46a756faad4727fb679320751f6dea
+CI_COMMIT_AUTHOR_EMAIL=test@noreply.localhost
+CI_COMMIT_BRANCH=main
+CI_COMMIT_MESSAGE=revert 9b2aed1392fc097ef7b027712977722fb004d463
+CI_COMMIT_PULL_REQUEST=
+CI_COMMIT_PULL_REQUEST_LABELS=
+CI_COMMIT_REF=refs/heads/main
+CI_COMMIT_REFSPEC=
+CI_COMMIT_SHA=8826c98181353075bbeee8f99b400496488e3523
+CI_COMMIT_SOURCE_BRANCH=
+CI_COMMIT_TAG=
+CI_COMMIT_TARGET_BRANCH=
+CI_FORGE_TYPE=gitea
+CI_FORGE_URL=http://1.2.3.4:3000
+CI_MACHINE=hagalaz
+CI_PIPELINE_CREATED=1721328737
+CI_PIPELINE_DEPLOY_TARGET=
+CI_PIPELINE_DEPLOY_TASK=
+CI_PIPELINE_EVENT=push
+CI_PIPELINE_FILES=[".woodpecker.yaml"]
+CI_PIPELINE_FORGE_URL=http://1.2.3.4:3000/test/woodpecker-test/commit/8826c98181353075bbeee8f99b400496488e3523
+CI_PIPELINE_NUMBER=24
+CI_PIPELINE_PARENT=23
+CI_PIPELINE_STARTED=1721328737
+CI_PIPELINE_URL=http://1.2.3.4:8000/repos/2/pipeline/24
+CI_PREV_COMMIT_AUTHOR=test
+CI_PREV_COMMIT_AUTHOR_AVATAR=http://1.2.3.4:3000/avatars/dd46a756faad4727fb679320751f6dea
+CI_PREV_COMMIT_AUTHOR_EMAIL=test@noreply.localhost
+CI_PREV_COMMIT_BRANCH=main
+CI_PREV_COMMIT_MESSAGE=revert 9b2aed1392fc097ef7b027712977722fb004d463
+CI_PREV_COMMIT_REF=refs/heads/main
+CI_PREV_COMMIT_REFSPEC=
+CI_PREV_COMMIT_SHA=8826c98181353075bbeee8f99b400496488e3523
+CI_PREV_COMMIT_URL=http://1.2.3.4:3000/test/woodpecker-test/commit/8826c98181353075bbeee8f99b400496488e3523
+CI_PREV_COMMIT_SOURCE_BRANCH=
+CI_PREV_COMMIT_TARGET_BRANCH=
+CI_PREV_PIPELINE_CREATED=1721086039
+CI_PREV_PIPELINE_DEPLOY_TARGET=
+CI_PREV_PIPELINE_DEPLOY_TASK=
+CI_PREV_PIPELINE_EVENT=push
+CI_PREV_PIPELINE_FINISHED=1721086056
+CI_PREV_PIPELINE_FORGE_URL=http://1.2.3.4:3000/test/woodpecker-test/commit/8826c98181353075bbeee8f99b400496488e3523
+CI_PREV_PIPELINE_NUMBER=23
+CI_PREV_PIPELINE_PARENT=0
+CI_PREV_PIPELINE_STARTED=1721086039
+CI_PREV_PIPELINE_STATUS=failure
+CI_PREV_PIPELINE_URL=http://1.2.3.4:8000/repos/2/pipeline/23
+CI_REPO=test/woodpecker-test
+CI_REPO_CLONE_SSH_URL=user@1.2.3.4:test/woodpecker-test.git
+CI_REPO_CLONE_URL=http://1.2.3.4:3000/test/woodpecker-test.git
+CI_REPO_DEFAULT_BRANCH=main
+CI_REPO_NAME=woodpecker-test
+CI_REPO_OWNER=test
+CI_REPO_PRIVATE=false
+CI_REPO_REMOTE_ID=4
+CI_REPO_SCM=git
+CI_REPO_TRUSTED=false
+CI_REPO_URL=http://1.2.3.4:3000/test/woodpecker-test
+CI_STEP_NAME=
+CI_STEP_NUMBER=0
+CI_STEP_STARTED=1721328737
+CI_STEP_URL=http://1.2.3.4:8000/repos/2/pipeline/24
+CI_SYSTEM_HOST=1.2.3.4:8000
+CI_SYSTEM_NAME=woodpecker
+CI_SYSTEM_PLATFORM=linux/amd64
+CI_SYSTEM_URL=http://1.2.3.4:8000
+CI_SYSTEM_VERSION=2.7.0
+CI_WORKFLOW_NAME=woodpecker
+CI_WORKFLOW_NUMBER=1
+CI_WORKSPACE=/usr/local/src/1.2.3.4/test/woodpecker-test`
+
+ droneVars := `DRONE_BRANCH=main
+DRONE_BUILD_CREATED=1721328737
+DRONE_BUILD_EVENT=push
+DRONE_BUILD_LINK=http://1.2.3.4:8000/repos/2/pipeline/24
+DRONE_BUILD_NUMBER=24
+DRONE_BUILD_PARENT=23
+DRONE_BUILD_STARTED=1721328737
+DRONE_BUILD_STATUS=success
+DRONE_COMMIT=8826c98181353075bbeee8f99b400496488e3523
+DRONE_COMMIT_AUTHOR=test
+DRONE_COMMIT_AUTHOR_AVATAR=http://1.2.3.4:3000/avatars/dd46a756faad4727fb679320751f6dea
+DRONE_COMMIT_AUTHOR_EMAIL=test@noreply.localhost
+DRONE_COMMIT_AUTHOR_NAME=test
+DRONE_COMMIT_BEFORE=8826c98181353075bbeee8f99b400496488e3523
+DRONE_COMMIT_BRANCH=main
+DRONE_COMMIT_LINK=http://1.2.3.4:3000/test/woodpecker-test/commit/8826c98181353075bbeee8f99b400496488e3523
+DRONE_COMMIT_MESSAGE=revert 9b2aed1392fc097ef7b027712977722fb004d463
+DRONE_COMMIT_REF=refs/heads/main
+DRONE_COMMIT_SHA=8826c98181353075bbeee8f99b400496488e3523
+DRONE_GIT_HTTP_URL=http://1.2.3.4:3000/test/woodpecker-test.git
+DRONE_PULL_REQUEST=
+DRONE_REMOTE_URL=http://1.2.3.4:3000/test/woodpecker-test.git
+DRONE_REPO=test/woodpecker-test
+DRONE_REPO_BRANCH=main
+DRONE_REPO_LINK=http://1.2.3.4:3000/test/woodpecker-test
+DRONE_REPO_NAME=woodpecker-test
+DRONE_REPO_OWNER=test
+DRONE_REPO_PRIVATE=false
+DRONE_REPO_SCM=git
+DRONE_SOURCE_BRANCH=
+DRONE_STEP_NUMBER=0
+DRONE_SYSTEM_HOST=1.2.3.4:8000
+DRONE_TAG=
+DRONE_TARGET_BRANCH=
+PULLREQUEST_DRONE_PULL_REQUEST=0`
env := convertListToEnvMap(t, woodpeckerVars)
metadata.SetDroneEnviron(env)
@@ -114,7 +229,7 @@ func convertListToEnvMap(t *testing.T, list string) map[string]string {
result := make(map[string]string)
for _, s := range strings.Split(list, "\n") {
before, after, _ := strings.Cut(strings.TrimSpace(s), "=")
- if before == "" || after == "" {
+ if before == "" {
t.Fatal("helper function got invalid test data")
}
result[before] = after
diff --git a/pipeline/frontend/metadata/environment.go b/pipeline/frontend/metadata/environment.go
index 782ccfce1..1a018867f 100644
--- a/pipeline/frontend/metadata/environment.go
+++ b/pipeline/frontend/metadata/environment.go
@@ -30,26 +30,33 @@ var (
maxChangedFiles = 500
)
-// Environ returns the metadata as a map of environment variables.
-func (m *Metadata) Environ() map[string]string {
+func getSourceTargetBranches(refspec string) (string, string) {
var (
sourceBranch string
targetBranch string
)
- branchParts := strings.Split(m.Curr.Commit.Refspec, ":")
+ branchParts := strings.Split(refspec, ":")
if len(branchParts) == 2 { //nolint:mnd
sourceBranch = branchParts[0]
targetBranch = branchParts[1]
}
+ 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": "git",
+ "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,
@@ -76,22 +83,18 @@ func (m *Metadata) Environ() map[string]string {
"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.Target,
- "CI_PIPELINE_DEPLOY_TASK": m.Curr.Task,
- "CI_PIPELINE_STATUS": m.Curr.Status,
+ "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_PIPELINE_FINISHED": strconv.FormatInt(m.Curr.Finished, 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_STATUS": "", // will be set by agent
- "CI_STEP_STARTED": "", // will be set by agent
- "CI_STEP_FINISHED": "", // will be set by agent
- "CI_STEP_URL": m.getPipelineWebURL(m.Curr, m.Step.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,
@@ -102,14 +105,16 @@ func (m *Metadata) Environ() map[string]string {
"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.Target,
- "CI_PREV_PIPELINE_DEPLOY_TASK": m.Prev.Task,
+ "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),
@@ -123,9 +128,6 @@ func (m *Metadata) Environ() map[string]string {
"CI_FORGE_TYPE": m.Forge.Type,
"CI_FORGE_URL": m.Forge.URL,
-
- // TODO: Deprecated, remove in 3.x
- "CI_COMMIT_URL": m.Curr.ForgeURL,
}
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/")
diff --git a/pipeline/frontend/metadata/types.go b/pipeline/frontend/metadata/types.go
index ef2299479..9d3529fd9 100644
--- a/pipeline/frontend/metadata/types.go
+++ b/pipeline/frontend/metadata/types.go
@@ -29,35 +29,33 @@ type (
// Repo defines runtime metadata for a repository.
Repo struct {
- ID int64 `json:"id,omitempty"`
- Name string `json:"name,omitempty"`
- Owner string `json:"owner,omitempty"`
- RemoteID string `json:"remote_id,omitempty"`
- ForgeURL string `json:"forge_url,omitempty"`
- CloneURL string `json:"clone_url,omitempty"`
- CloneSSHURL string `json:"clone_url_ssh,omitempty"`
- Private bool `json:"private,omitempty"`
- Secrets []Secret `json:"secrets,omitempty"`
- Branch string `json:"default_branch,omitempty"`
- Trusted bool `json:"trusted,omitempty"`
+ ID int64 `json:"id,omitempty"`
+ Name string `json:"name,omitempty"`
+ Owner string `json:"owner,omitempty"`
+ RemoteID string `json:"remote_id,omitempty"`
+ ForgeURL string `json:"forge_url,omitempty"`
+ SCM string `json:"scm,omitempty"`
+ CloneURL string `json:"clone_url,omitempty"`
+ CloneSSHURL string `json:"clone_url_ssh,omitempty"`
+ Private bool `json:"private,omitempty"`
+ Branch string `json:"default_branch,omitempty"`
+ Trusted bool `json:"trusted,omitempty"`
}
// Pipeline defines runtime metadata for a pipeline.
Pipeline struct {
- Number int64 `json:"number,omitempty"`
- Created int64 `json:"created,omitempty"`
- Started int64 `json:"started,omitempty"`
- Finished int64 `json:"finished,omitempty"`
- Timeout int64 `json:"timeout,omitempty"`
- Status string `json:"status,omitempty"`
- Event string `json:"event,omitempty"`
- ForgeURL string `json:"forge_url,omitempty"`
- Target string `json:"target,omitempty"`
- Task string `json:"task,omitempty"`
- Trusted bool `json:"trusted,omitempty"`
- Commit Commit `json:"commit,omitempty"`
- Parent int64 `json:"parent,omitempty"`
- Cron string `json:"cron,omitempty"`
+ Number int64 `json:"number,omitempty"`
+ Created int64 `json:"created,omitempty"`
+ Started int64 `json:"started,omitempty"`
+ Finished int64 `json:"finished,omitempty"`
+ Status string `json:"status,omitempty"`
+ Event string `json:"event,omitempty"`
+ ForgeURL string `json:"forge_url,omitempty"`
+ DeployTo string `json:"target,omitempty"`
+ DeployTask string `json:"task,omitempty"`
+ Commit Commit `json:"commit,omitempty"`
+ Parent int64 `json:"parent,omitempty"`
+ Cron string `json:"cron,omitempty"`
}
// Commit defines runtime metadata for a commit.
@@ -93,14 +91,6 @@ type (
Number int `json:"number,omitempty"`
}
- // Secret defines a runtime secret.
- Secret struct {
- Name string `json:"name,omitempty"`
- Value string `json:"value,omitempty"`
- Mount string `json:"mount,omitempty"`
- Mask bool `json:"mask,omitempty"`
- }
-
// System defines runtime metadata for a ci/cd system.
System struct {
Name string `json:"name,omitempty"`
diff --git a/pipeline/frontend/yaml/compiler/compiler.go b/pipeline/frontend/yaml/compiler/compiler.go
index 5db566513..dd9654b1c 100644
--- a/pipeline/frontend/yaml/compiler/compiler.go
+++ b/pipeline/frontend/yaml/compiler/compiler.go
@@ -16,6 +16,7 @@ package compiler
import (
"fmt"
+ "path"
backend_types "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/metadata"
@@ -48,7 +49,7 @@ func (s *Secret) Available(event string, container *yaml_types.Container) error
return fmt.Errorf("secret %q only allowed to be used by plugins by step %q", s.Name, container.Name)
}
- if onlyAllowSecretForPlugins && !utils.MatchImage(container.Image, s.AllowedPlugins...) {
+ if onlyAllowSecretForPlugins && !utils.MatchImageDynamic(container.Image, s.AllowedPlugins...) {
return fmt.Errorf("secret %q is not allowed to be used with image %q by step %q", s.Name, container.Image, container.Name)
}
@@ -91,30 +92,33 @@ type ResourceLimit struct {
// Compiler compiles the yaml.
type Compiler struct {
- local bool
- escalated []string
- prefix string
- volumes []string
- networks []string
- env map[string]string
- cloneEnv map[string]string
- base string
- path string
- metadata metadata.Metadata
- registries []Registry
- secrets map[string]Secret
- reslimit ResourceLimit
- defaultCloneImage string
- trustedPipeline bool
- netrcOnlyTrusted bool
+ local bool
+ escalated []string
+ prefix string
+ volumes []string
+ networks []string
+ env map[string]string
+ cloneEnv map[string]string
+ workspaceBase string
+ workspacePath string
+ metadata metadata.Metadata
+ registries []Registry
+ secrets map[string]Secret
+ reslimit ResourceLimit
+ defaultClonePlugin string
+ trustedClonePlugins []string
+ trustedPipeline bool
+ netrcOnlyTrusted bool
}
// New creates a new Compiler with options.
func New(opts ...Option) *Compiler {
compiler := &Compiler{
- env: map[string]string{},
- cloneEnv: map[string]string{},
- secrets: map[string]Secret{},
+ env: map[string]string{},
+ cloneEnv: map[string]string{},
+ secrets: map[string]Secret{},
+ defaultClonePlugin: constant.DefaultClonePlugin,
+ trustedClonePlugins: constant.TrustedClonePlugins,
}
for _, opt := range opts {
opt(compiler)
@@ -156,26 +160,21 @@ func (c *Compiler) Compile(conf *yaml_types.Workflow) (*backend_types.Config, er
// overrides the default workspace paths when specified
// in the YAML file.
if len(conf.Workspace.Base) != 0 {
- c.base = conf.Workspace.Base
+ c.workspaceBase = path.Clean(conf.Workspace.Base)
}
if len(conf.Workspace.Path) != 0 {
- c.path = conf.Workspace.Path
- }
-
- cloneImage := constant.DefaultCloneImage
- if len(c.defaultCloneImage) > 0 {
- cloneImage = c.defaultCloneImage
+ c.workspacePath = path.Clean(conf.Workspace.Path)
}
// add default clone step
- if !c.local && len(conf.Clone.ContainerList) == 0 && !conf.SkipClone {
+ if !c.local && len(conf.Clone.ContainerList) == 0 && !conf.SkipClone && len(c.defaultClonePlugin) != 0 {
cloneSettings := map[string]any{"depth": "0"}
if c.metadata.Curr.Event == metadata.EventTag {
cloneSettings["tags"] = "true"
}
container := &yaml_types.Container{
Name: defaultCloneName,
- Image: cloneImage,
+ Image: c.defaultClonePlugin,
Settings: cloneSettings,
Environment: make(map[string]any),
}
@@ -207,7 +206,7 @@ func (c *Compiler) Compile(conf *yaml_types.Workflow) (*backend_types.Config, er
}
// only inject netrc if it's a trusted repo or a trusted plugin
- if !c.netrcOnlyTrusted || c.trustedPipeline || (container.IsPlugin() && container.IsTrustedCloneImage()) {
+ if !c.netrcOnlyTrusted || c.trustedPipeline || (container.IsPlugin() && container.IsTrustedCloneImage(c.trustedClonePlugins)) {
for k, v := range c.cloneEnv {
step.Environment[k] = v
}
@@ -264,7 +263,7 @@ func (c *Compiler) Compile(conf *yaml_types.Workflow) (*backend_types.Config, er
}
// inject netrc if it's a trusted repo or a trusted clone-plugin
- if c.trustedPipeline || (container.IsPlugin() && container.IsTrustedCloneImage()) {
+ if c.trustedPipeline || (container.IsPlugin() && container.IsTrustedCloneImage(c.trustedClonePlugins)) {
for k, v := range c.cloneEnv {
step.Environment[k] = v
}
@@ -274,7 +273,6 @@ func (c *Compiler) Compile(conf *yaml_types.Workflow) (*backend_types.Config, er
step: step,
position: pos,
name: container.Name,
- group: container.Group,
dependsOn: container.DependsOn,
})
}
diff --git a/pipeline/frontend/yaml/compiler/compiler_test.go b/pipeline/frontend/yaml/compiler/compiler_test.go
index 41e055b36..242229c61 100644
--- a/pipeline/frontend/yaml/compiler/compiler_test.go
+++ b/pipeline/frontend/yaml/compiler/compiler_test.go
@@ -61,13 +61,14 @@ func TestSecretAvailable(t *testing.T) {
}
func TestCompilerCompile(t *testing.T) {
+ repoURL := "https://github.com/octocat/hello-world"
compiler := New(
WithMetadata(metadata.Metadata{
Repo: metadata.Repo{
Owner: "octacat",
Name: "hello-world",
Private: true,
- ForgeURL: "https://github.com/octocat/hello-world",
+ ForgeURL: repoURL,
CloneURL: "https://github.com/octocat/hello-world.git",
},
}),
@@ -76,6 +77,8 @@ func TestCompilerCompile(t *testing.T) {
"COLORED": "true",
}),
WithPrefix("test"),
+ // we use "/test" as custom workspace base to ensure the enforcement of the pluginWorkspaceBase is applied
+ WithWorkspaceFromURL("/test", repoURL),
)
defaultNetworks := []*backend_types.Network{{
@@ -89,10 +92,11 @@ func TestCompilerCompile(t *testing.T) {
Steps: []*backend_types.Step{{
Name: "clone",
Type: backend_types.StepTypeClone,
- Image: constant.DefaultCloneImage,
+ Image: constant.DefaultClonePlugin,
OnSuccess: true,
Failure: "fail",
- Volumes: []string{defaultVolumes[0].Name + ":"},
+ Volumes: []string{defaultVolumes[0].Name + ":/woodpecker"},
+ WorkingDir: "/woodpecker/src/github.com/octocat/hello-world",
Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"clone"}}},
ExtraHosts: []backend_types.HostAlias{},
}},
@@ -137,7 +141,8 @@ func TestCompilerCompile(t *testing.T) {
Image: "dummy_img",
OnSuccess: true,
Failure: "fail",
- Volumes: []string{defaultVolumes[0].Name + ":"},
+ Volumes: []string{defaultVolumes[0].Name + ":/woodpecker"},
+ WorkingDir: "/woodpecker/src/github.com/octocat/hello-world",
Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"dummy"}}},
ExtraHosts: []backend_types.HostAlias{},
}},
@@ -145,60 +150,65 @@ func TestCompilerCompile(t *testing.T) {
},
},
{
- name: "workflow with three steps and one group",
+ name: "workflow with three steps",
fronConf: &yaml_types.Workflow{Steps: yaml_types.ContainerList{ContainerList: []*yaml_types.Container{{
Name: "echo env",
Image: "bash",
Commands: []string{"env"},
}, {
Name: "parallel echo 1",
- Group: "parallel",
Image: "bash",
Commands: []string{"echo 1"},
}, {
Name: "parallel echo 2",
- Group: "parallel",
Image: "bash",
Commands: []string{"echo 2"},
}}}},
backConf: &backend_types.Config{
Networks: defaultNetworks,
Volumes: defaultVolumes,
- Stages: []*backend_types.Stage{defaultCloneStage, {
- Steps: []*backend_types.Step{{
- Name: "echo env",
- Type: backend_types.StepTypeCommands,
- Image: "bash",
- Commands: []string{"env"},
- OnSuccess: true,
- Failure: "fail",
- Volumes: []string{defaultVolumes[0].Name + ":"},
- Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"echo env"}}},
- ExtraHosts: []backend_types.HostAlias{},
- }},
- }, {
- Steps: []*backend_types.Step{{
- Name: "parallel echo 1",
- Type: backend_types.StepTypeCommands,
- Image: "bash",
- Commands: []string{"echo 1"},
- OnSuccess: true,
- Failure: "fail",
- Volumes: []string{defaultVolumes[0].Name + ":"},
- Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"parallel echo 1"}}},
- ExtraHosts: []backend_types.HostAlias{},
+ Stages: []*backend_types.Stage{
+ defaultCloneStage, {
+ Steps: []*backend_types.Step{{
+ Name: "echo env",
+ Type: backend_types.StepTypeCommands,
+ Image: "bash",
+ Commands: []string{"env"},
+ OnSuccess: true,
+ Failure: "fail",
+ Volumes: []string{defaultVolumes[0].Name + ":/test"},
+ WorkingDir: "/test/src/github.com/octocat/hello-world",
+ Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"echo env"}}},
+ ExtraHosts: []backend_types.HostAlias{},
+ }},
}, {
- Name: "parallel echo 2",
- Type: backend_types.StepTypeCommands,
- Image: "bash",
- Commands: []string{"echo 2"},
- OnSuccess: true,
- Failure: "fail",
- Volumes: []string{defaultVolumes[0].Name + ":"},
- Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"parallel echo 2"}}},
- ExtraHosts: []backend_types.HostAlias{},
- }},
- }},
+ Steps: []*backend_types.Step{{
+ Name: "parallel echo 1",
+ Type: backend_types.StepTypeCommands,
+ Image: "bash",
+ Commands: []string{"echo 1"},
+ OnSuccess: true,
+ Failure: "fail",
+ Volumes: []string{defaultVolumes[0].Name + ":/test"},
+ WorkingDir: "/test/src/github.com/octocat/hello-world",
+ Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"parallel echo 1"}}},
+ ExtraHosts: []backend_types.HostAlias{},
+ }},
+ }, {
+ Steps: []*backend_types.Step{{
+ Name: "parallel echo 2",
+ Type: backend_types.StepTypeCommands,
+ Image: "bash",
+ Commands: []string{"echo 2"},
+ OnSuccess: true,
+ Failure: "fail",
+ Volumes: []string{defaultVolumes[0].Name + ":/test"},
+ WorkingDir: "/test/src/github.com/octocat/hello-world",
+ Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"parallel echo 2"}}},
+ ExtraHosts: []backend_types.HostAlias{},
+ }},
+ },
+ },
},
},
{
@@ -228,7 +238,8 @@ func TestCompilerCompile(t *testing.T) {
Commands: []string{"env"},
OnSuccess: true,
Failure: "fail",
- Volumes: []string{defaultVolumes[0].Name + ":"},
+ Volumes: []string{defaultVolumes[0].Name + ":/test"},
+ WorkingDir: "/test/src/github.com/octocat/hello-world",
Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"echo env"}}},
ExtraHosts: []backend_types.HostAlias{},
}, {
@@ -238,7 +249,8 @@ func TestCompilerCompile(t *testing.T) {
Commands: []string{"echo 2"},
OnSuccess: true,
Failure: "fail",
- Volumes: []string{defaultVolumes[0].Name + ":"},
+ Volumes: []string{defaultVolumes[0].Name + ":/test"},
+ WorkingDir: "/test/src/github.com/octocat/hello-world",
Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"echo 2"}}},
ExtraHosts: []backend_types.HostAlias{},
}},
@@ -250,7 +262,8 @@ func TestCompilerCompile(t *testing.T) {
Commands: []string{"echo 1"},
OnSuccess: true,
Failure: "fail",
- Volumes: []string{defaultVolumes[0].Name + ":"},
+ Volumes: []string{defaultVolumes[0].Name + ":/test"},
+ WorkingDir: "/test/src/github.com/octocat/hello-world",
Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"echo 1"}}},
ExtraHosts: []backend_types.HostAlias{},
}},
@@ -263,7 +276,7 @@ func TestCompilerCompile(t *testing.T) {
Name: "step",
Image: "bash",
Commands: []string{"env"},
- Secrets: yaml_types.Secrets{Secrets: []*yaml_types.Secret{{Source: "missing", Target: "missing"}}},
+ Secrets: []string{"missing"},
}}}},
backConf: nil,
expectedErr: "secret \"missing\" not found",
diff --git a/pipeline/frontend/yaml/compiler/convert.go b/pipeline/frontend/yaml/compiler/convert.go
index 92d68fe45..bab841d8a 100644
--- a/pipeline/frontend/yaml/compiler/convert.go
+++ b/pipeline/frontend/yaml/compiler/convert.go
@@ -30,6 +30,13 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/utils"
)
+const (
+ // The pluginWorkspaceBase should not be changed, only if you are sure what you do.
+ pluginWorkspaceBase = "/woodpecker"
+ // DefaultWorkspaceBase is set if not altered by the user.
+ DefaultWorkspaceBase = pluginWorkspaceBase
+)
+
func (c *Compiler) createProcess(container *yaml_types.Container, stepType backend_types.StepType) (*backend_types.Step, error) {
var (
uuid = ulid.Make()
@@ -37,12 +44,17 @@ func (c *Compiler) createProcess(container *yaml_types.Container, stepType backe
detached bool
workingDir string
- workspace = fmt.Sprintf("%s_default:%s", c.prefix, c.base)
privileged = container.Privileged
networkMode = container.NetworkMode
- // network = container.Network
)
+ workspaceBase := c.workspaceBase
+ if container.IsPlugin() {
+ // plugins have a predefined workspace base to not tamper with entrypoint executables
+ workspaceBase = pluginWorkspaceBase
+ }
+ workspaceVolume := fmt.Sprintf("%s_default:%s", c.prefix, workspaceBase)
+
networks := []backend_types.Conn{
{
Name: fmt.Sprintf("%s_default", c.prefix),
@@ -67,7 +79,7 @@ func (c *Compiler) createProcess(container *yaml_types.Container, stepType backe
var volumes []string
if !c.local {
- volumes = append(volumes, workspace)
+ volumes = append(volumes, workspaceVolume)
}
volumes = append(volumes, c.volumes...)
for _, volume := range container.Volumes.Volumes {
@@ -78,15 +90,13 @@ func (c *Compiler) createProcess(container *yaml_types.Container, stepType backe
environment := map[string]string{}
maps.Copy(environment, c.env)
- environment["CI_WORKSPACE"] = path.Join(c.base, c.path)
+ environment["CI_WORKSPACE"] = path.Join(workspaceBase, c.workspacePath)
if stepType == backend_types.StepTypeService || container.Detached {
detached = true
}
- if !detached || len(container.Commands) != 0 {
- workingDir = c.stepWorkingDir(container)
- }
+ workingDir = c.stepWorkingDir(container)
getSecretValue := func(name string) (string, error) {
name = strings.ToLower(name)
@@ -115,18 +125,20 @@ func (c *Compiler) createProcess(container *yaml_types.Container, stepType backe
return nil, err
}
- for _, requested := range container.Secrets.Secrets {
- secretValue, err := getSecretValue(requested.Source)
+ for _, requested := range container.Secrets {
+ secretValue, err := getSecretValue(requested)
if err != nil {
return nil, err
}
- environment[requested.Target] = secretValue
- // TODO: deprecated, remove in 3.x
- environment[strings.ToUpper(requested.Target)] = secretValue
+ if !environmentAllowed(requested, stepType) {
+ continue
+ }
+
+ environment[requested] = secretValue
}
- if utils.MatchImage(container.Image, c.escalated...) && container.IsPlugin() {
+ if utils.MatchImageDynamic(container.Image, c.escalated...) && container.IsPlugin() {
privileged = true
}
@@ -222,7 +234,11 @@ func (c *Compiler) stepWorkingDir(container *yaml_types.Container) string {
if path.IsAbs(container.Directory) {
return container.Directory
}
- return path.Join(c.base, c.path, container.Directory)
+ base := c.workspaceBase
+ if container.IsPlugin() {
+ base = pluginWorkspaceBase
+ }
+ return path.Join(base, c.workspacePath, container.Directory)
}
func convertPort(portDef string) (backend_types.Port, error) {
diff --git a/pipeline/frontend/yaml/compiler/dag.go b/pipeline/frontend/yaml/compiler/dag.go
index 461807259..deb673e4c 100644
--- a/pipeline/frontend/yaml/compiler/dag.go
+++ b/pipeline/frontend/yaml/compiler/dag.go
@@ -24,7 +24,6 @@ type dagCompilerStep struct {
step *backend_types.Step
position int
name string
- group string
dependsOn []string
}
@@ -51,25 +50,16 @@ func (c dagCompiler) compile() ([]*backend_types.Stage, error) {
if c.isDAG() {
return c.compileByDependsOn()
}
- return c.compileByGroup()
+ return c.compileSequence()
}
-func (c dagCompiler) compileByGroup() ([]*backend_types.Stage, error) {
+func (c dagCompiler) compileSequence() ([]*backend_types.Stage, error) {
stages := make([]*backend_types.Stage, 0, len(c.steps))
- var currentStage *backend_types.Stage
- var currentGroup string
for _, s := range c.steps {
- // create a new stage if current step is in a new group compared to last one
- if currentStage == nil || currentGroup != s.group || s.group == "" {
- currentGroup = s.group
-
- currentStage = new(backend_types.Stage)
- stages = append(stages, currentStage)
- }
-
- // add step to current stage
- currentStage.Steps = append(currentStage.Steps, s.step)
+ stages = append(stages, &backend_types.Stage{
+ Steps: []*backend_types.Step{s.step},
+ })
}
return stages, nil
diff --git a/pipeline/frontend/yaml/compiler/dag_test.go b/pipeline/frontend/yaml/compiler/dag_test.go
index 51dd3b5a6..620b67776 100644
--- a/pipeline/frontend/yaml/compiler/dag_test.go
+++ b/pipeline/frontend/yaml/compiler/dag_test.go
@@ -85,7 +85,6 @@ func TestConvertDAGToStages(t *testing.T) {
"echo env": {
position: 0,
name: "echo env",
- group: "",
step: &backend_types.Step{
UUID: "01HJDPEW6R7J0JBE3F1T7Q0TYX",
Type: "commands",
@@ -96,7 +95,6 @@ func TestConvertDAGToStages(t *testing.T) {
"echo 1": {
position: 1,
name: "echo 1",
- group: "",
dependsOn: []string{"echo env", "echo 2"},
step: &backend_types.Step{
UUID: "01HJDPF770QGRZER8RF79XVS4M",
@@ -108,7 +106,6 @@ func TestConvertDAGToStages(t *testing.T) {
"echo 2": {
position: 2,
name: "echo 2",
- group: "",
step: &backend_types.Step{
UUID: "01HJDPFF5RMEYZW0YTGR1Y1ZR0",
Type: "commands",
diff --git a/pipeline/frontend/yaml/compiler/environment.go b/pipeline/frontend/yaml/compiler/environment.go
new file mode 100644
index 000000000..f9061df45
--- /dev/null
+++ b/pipeline/frontend/yaml/compiler/environment.go
@@ -0,0 +1,53 @@
+// 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 compiler
+
+import backend_types "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
+
+/* cSpell:disable */
+
+var binaryVars = []string{
+ "PATH", // Specifies directories to search for executable files
+ "PATH_SEPARATOR", // Defines the separator used in the PATH variable
+ "COMMAND_MODE", // (macOS): Can affect how certain commands are interpreted
+ "DYLD_FALLBACK_FRAMEWORK_PATH", // (macOS): Specifies additional locations to search for frameworks
+ "DYLD_FALLBACK_LIBRARY_PATH", // (macOS): Specifies additional locations to search for libraries
+}
+
+var libraryVars = []string{
+ "LD_PRELOAD", // Specifies shared libraries to be loaded before all others
+ "LD_LIBRARY_PATH", // Specifies directories to search for shared libraries before the standard locations
+ "LD_AUDIT", // Specifies a shared object to be used for auditing
+ "LD_BIND_NOW", // Forces all relocations to be processed immediately
+ "LD_PROFILE", // Specifies a shared object to be used for profiling
+ "LIBPATH", // (AIX): Similar to LD_LIBRARY_PATH on AIX systems
+ "DYLD_INSERT_LIBRARIES", // (macOS): Similar to LD_PRELOAD on macOS
+ "DYLD_LIBRARY_PATH", // (macOS): Similar to LD_LIBRARY_PATH on macOS
+}
+
+/* cSpell:enable */
+
+func environmentAllowed(envKey string, stepType backend_types.StepType) bool {
+ switch stepType {
+ case backend_types.StepTypePlugin,
+ backend_types.StepTypeClone:
+ for _, v := range append(binaryVars, libraryVars...) {
+ if envKey == v {
+ return false
+ }
+ }
+ }
+ return true
+}
diff --git a/pipeline/frontend/yaml/compiler/option.go b/pipeline/frontend/yaml/compiler/option.go
index d222ffaa9..c25b555ec 100644
--- a/pipeline/frontend/yaml/compiler/option.go
+++ b/pipeline/frontend/yaml/compiler/option.go
@@ -97,8 +97,8 @@ func WithNetrc(username, password, machine string) Option {
// plugin steps in the pipeline.
func WithWorkspace(base, path string) Option {
return func(compiler *Compiler) {
- compiler.base = base
- compiler.path = path
+ compiler.workspaceBase = base
+ compiler.workspacePath = path
}
}
@@ -172,9 +172,15 @@ func WithResourceLimit(swap, mem, shmSize, cpuQuota, cpuShares int64, cpuSet str
}
}
-func WithDefaultCloneImage(cloneImage string) Option {
+func WithDefaultClonePlugin(cloneImage string) Option {
return func(compiler *Compiler) {
- compiler.defaultCloneImage = cloneImage
+ compiler.defaultClonePlugin = cloneImage
+ }
+}
+
+func WithTrustedClonePlugins(images []string) Option {
+ return func(compiler *Compiler) {
+ compiler.trustedClonePlugins = images
}
}
diff --git a/pipeline/frontend/yaml/compiler/option_test.go b/pipeline/frontend/yaml/compiler/option_test.go
index 4f8e08e5d..a865ef254 100644
--- a/pipeline/frontend/yaml/compiler/option_test.go
+++ b/pipeline/frontend/yaml/compiler/option_test.go
@@ -20,6 +20,7 @@ import (
"github.com/stretchr/testify/assert"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/metadata"
+ "go.woodpecker-ci.org/woodpecker/v2/shared/constant"
)
func TestWithWorkspace(t *testing.T) {
@@ -29,8 +30,8 @@ func TestWithWorkspace(t *testing.T) {
"src/github.com/octocat/hello-world",
),
)
- assert.Equal(t, "/pipeline", compiler.base)
- assert.Equal(t, "src/github.com/octocat/hello-world", compiler.path)
+ assert.Equal(t, "/pipeline", compiler.workspaceBase)
+ assert.Equal(t, "src/github.com/octocat/hello-world", compiler.workspacePath)
}
func TestWithEscalated(t *testing.T) {
@@ -166,9 +167,17 @@ func TestWithEnviron(t *testing.T) {
assert.Equal(t, "true", compiler.env["SHOW"])
}
-func TestWithDefaultCloneImage(t *testing.T) {
+func TestDefaultClonePlugin(t *testing.T) {
compiler := New(
- WithDefaultCloneImage("not-an-image"),
+ WithDefaultClonePlugin("not-an-image"),
)
- assert.Equal(t, "not-an-image", compiler.defaultCloneImage)
+ assert.Equal(t, "not-an-image", compiler.defaultClonePlugin)
+}
+
+func TestWithTrustedClonePlugins(t *testing.T) {
+ compiler := New(WithTrustedClonePlugins([]string{"not-an-image"}))
+ assert.ElementsMatch(t, []string{"not-an-image"}, compiler.trustedClonePlugins)
+
+ compiler = New()
+ assert.ElementsMatch(t, constant.TrustedClonePlugins, compiler.trustedClonePlugins)
}
diff --git a/pipeline/frontend/yaml/constraint/constraint.go b/pipeline/frontend/yaml/constraint/constraint.go
index 48145266f..28c29f2ab 100644
--- a/pipeline/frontend/yaml/constraint/constraint.go
+++ b/pipeline/frontend/yaml/constraint/constraint.go
@@ -18,6 +18,7 @@ import (
"fmt"
"maps"
"path"
+ "slices"
"strings"
"github.com/bmatcuk/doublestar/v4"
@@ -37,20 +38,18 @@ type (
}
Constraint struct {
- Ref List
- Repo List
- Instance List
- Platform List
- Environment List
- Branch List
- Cron List
- Status List
- Matrix Map
- Local yamlBaseTypes.BoolTrue
- Path Path
- Evaluate string `yaml:"evaluate,omitempty"`
- // TODO: change to StringOrSlice in 3.x
- Event List
+ Ref List
+ Repo List
+ Instance List
+ Platform List
+ Branch List
+ Cron List
+ Status List
+ Matrix Map
+ Local yamlBaseTypes.BoolTrue
+ Path Path
+ Evaluate string `yaml:"evaluate,omitempty"`
+ Event yamlBaseTypes.StringOrSlice
}
// List defines a runtime constraint for exclude & include string slices.
@@ -164,8 +163,7 @@ func (c *Constraint) Match(m metadata.Metadata, global bool, env map[string]stri
}
match = match && c.Platform.Match(m.Sys.Platform) &&
- c.Environment.Match(m.Curr.Target) &&
- c.Event.Match(m.Curr.Event) &&
+ (len(c.Event) == 0 || slices.Contains(c.Event, m.Curr.Event)) &&
c.Repo.Match(path.Join(m.Repo.Owner, m.Repo.Name)) &&
c.Ref.Match(m.Curr.Commit.Ref) &&
c.Instance.Match(m.Sys.Host)
diff --git a/pipeline/frontend/yaml/linter/linter.go b/pipeline/frontend/yaml/linter/linter.go
index 7120d2ad8..6b88d8e98 100644
--- a/pipeline/frontend/yaml/linter/linter.go
+++ b/pipeline/frontend/yaml/linter/linter.go
@@ -24,11 +24,15 @@ import (
errorTypes "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors/types"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/linter/schema"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/types"
+ "go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/utils"
+ "go.woodpecker-ci.org/woodpecker/v2/shared/constant"
)
// A Linter lints a pipeline configuration.
type Linter struct {
- trusted bool
+ trusted bool
+ privilegedPlugins *[]string
+ trustedClonePlugins *[]string
}
// New creates a new Linter with options.
@@ -71,6 +75,10 @@ func (l *Linter) lintFile(config *WorkflowConfig) error {
linterErr = multierr.Append(linterErr, newLinterError("Invalid or missing steps section", config.File, "steps", false))
}
+ if err := l.lintCloneSteps(config); err != nil {
+ linterErr = multierr.Append(linterErr, err)
+ }
+
if err := l.lintContainers(config, "clone"); err != nil {
linterErr = multierr.Append(linterErr, err)
}
@@ -94,6 +102,29 @@ func (l *Linter) lintFile(config *WorkflowConfig) error {
return linterErr
}
+func (l *Linter) lintCloneSteps(config *WorkflowConfig) error {
+ if len(config.Workflow.Clone.ContainerList) == 0 {
+ return nil
+ }
+
+ trustedClonePlugins := constant.TrustedClonePlugins
+ if l.trustedClonePlugins != nil {
+ trustedClonePlugins = *l.trustedClonePlugins
+ }
+
+ var linterErr error
+ for _, container := range config.Workflow.Clone.ContainerList {
+ if !utils.MatchImageDynamic(container.Image, trustedClonePlugins...) {
+ linterErr = multierr.Append(linterErr,
+ newLinterError(
+ "Specified clone image does not match allow list, netrc will not be injected",
+ config.File, fmt.Sprintf("clone.%s", container.Name), true),
+ )
+ }
+ }
+ return linterErr
+}
+
func (l *Linter) lintContainers(config *WorkflowConfig, area string) error {
var linterErr error
@@ -117,7 +148,10 @@ func (l *Linter) lintContainers(config *WorkflowConfig, area string) error {
linterErr = multierr.Append(linterErr, err)
}
}
- if err := l.lintCommands(config, container, area); err != nil {
+ if err := l.lintSettings(config, container, area); err != nil {
+ linterErr = multierr.Append(linterErr, err)
+ }
+ if err := l.lintPrivilegedPlugins(config, container, area); err != nil {
linterErr = multierr.Append(linterErr, err)
}
}
@@ -132,16 +166,37 @@ func (l *Linter) lintImage(config *WorkflowConfig, c *types.Container, area stri
return nil
}
-func (l *Linter) lintCommands(config *WorkflowConfig, c *types.Container, field string) error {
- if len(c.Commands) == 0 {
+func (l *Linter) lintPrivilegedPlugins(config *WorkflowConfig, c *types.Container, area string) error {
+ // lint for conflicts of https://github.com/woodpecker-ci/woodpecker/pull/3918
+ if utils.MatchImage(c.Image, "plugins/docker", "plugins/gcr", "plugins/ecr", "woodpeckerci/plugin-docker-buildx") {
+ msg := fmt.Sprintf("Cannot use once by default privileged plugin '%s', if needed add it too WOODPECKER_PLUGINS_PRIVILEGED", c.Image)
+ // check first if user did not add them back
+ if l.privilegedPlugins != nil && !utils.MatchImageDynamic(c.Image, *l.privilegedPlugins...) {
+ return newLinterError(msg, config.File, fmt.Sprintf("%s.%s", area, c.Name), false)
+ } else if l.privilegedPlugins == nil {
+ // if linter has no info of current privileged plugins, it's just a warning
+ return newLinterError(msg, config.File, fmt.Sprintf("%s.%s", area, c.Name), true)
+ }
+ }
+
+ return nil
+}
+
+func (l *Linter) lintSettings(config *WorkflowConfig, c *types.Container, field string) error {
+ if len(c.Settings) == 0 {
return nil
}
- if len(c.Settings) != 0 {
- var keys []string
- for key := range c.Settings {
- keys = append(keys, key)
- }
- return newLinterError(fmt.Sprintf("Cannot configure both commands and custom attributes %v", keys), config.File, fmt.Sprintf("%s.%s", field, c.Name), false)
+ if len(c.Commands) != 0 {
+ return newLinterError("Cannot configure both commands and settings", config.File, fmt.Sprintf("%s.%s", field, c.Name), false)
+ }
+ if len(c.Entrypoint) != 0 {
+ return newLinterError("Cannot configure both entrypoint and settings", config.File, fmt.Sprintf("%s.%s", field, c.Name), false)
+ }
+ if len(c.Environment) != 0 {
+ return newLinterError("Should not configure both environment and settings", config.File, fmt.Sprintf("%s.%s", field, c.Name), true)
+ }
+ if len(c.Secrets) != 0 {
+ return newLinterError("Should not configure both secrets and settings", config.File, fmt.Sprintf("%s.%s", field, c.Name), true)
}
return nil
}
@@ -170,10 +225,7 @@ func (l *Linter) lintTrusted(config *WorkflowConfig, c *types.Container, area st
if len(c.NetworkMode) != 0 {
errors = append(errors, "Insufficient privileges to use network_mode")
}
- if c.Networks.Networks != nil && len(c.Networks.Networks) != 0 {
- errors = append(errors, "Insufficient privileges to use networks")
- }
- if c.Volumes.Volumes != nil && len(c.Volumes.Volumes) != 0 {
+ if len(c.Volumes.Volumes) != 0 {
errors = append(errors, "Insufficient privileges to use volumes")
}
if len(c.Tmpfs) != 0 {
@@ -216,142 +268,7 @@ func (l *Linter) lintDeprecations(config *WorkflowConfig) (err error) {
return err
}
- if parsed.PipelineDoNotUseIt.ContainerList != nil {
- err = multierr.Append(err, &errorTypes.PipelineError{
- Type: errorTypes.PipelineErrorTypeDeprecation,
- Message: "Please use 'steps:' instead of deprecated 'pipeline:' list",
- Data: errors.DeprecationErrorData{
- File: config.File,
- Field: "pipeline",
- Docs: "https://woodpecker-ci.org/docs/next/migrations#next-200",
- },
- IsWarning: true,
- })
- }
-
- if parsed.PlatformDoNotUseIt != "" {
- err = multierr.Append(err, &errorTypes.PipelineError{
- Type: errorTypes.PipelineErrorTypeDeprecation,
- Message: "Please use labels instead of deprecated 'platform' filters",
- Data: errors.DeprecationErrorData{
- File: config.File,
- Field: "platform",
- Docs: "https://woodpecker-ci.org/docs/next/migrations#next-200",
- },
- IsWarning: true,
- })
- }
-
- if parsed.BranchesDoNotUseIt != nil {
- err = multierr.Append(err, &errorTypes.PipelineError{
- Type: errorTypes.PipelineErrorTypeDeprecation,
- Message: "Please use global when instead of deprecated 'branches' filter",
- Data: errors.DeprecationErrorData{
- File: config.File,
- Field: "branches",
- Docs: "https://woodpecker-ci.org/docs/next/migrations#next-200",
- },
- IsWarning: true,
- })
- }
-
- for _, step := range parsed.Steps.ContainerList {
- if step.Group != "" {
- err = multierr.Append(err, &errorTypes.PipelineError{
- Type: errorTypes.PipelineErrorTypeDeprecation,
- Message: "Please use depends_on instead of deprecated 'group' setting",
- Data: errors.DeprecationErrorData{
- File: config.File,
- Field: "steps." + step.Name + ".group",
- Docs: "https://woodpecker-ci.org/docs/next/usage/workflow-syntax#depends_on",
- },
- IsWarning: true,
- })
- }
- }
-
- for i, c := range parsed.When.Constraints {
- if len(c.Event.Exclude) != 0 {
- err = multierr.Append(err, &errorTypes.PipelineError{
- Type: errorTypes.PipelineErrorTypeDeprecation,
- Message: "Please only use allow lists for events",
- Data: errors.DeprecationErrorData{
- File: config.File,
- Field: fmt.Sprintf("when[%d].event", i),
- Docs: "https://woodpecker-ci.org/docs/usage/workflow-syntax#event-1",
- },
- IsWarning: true,
- })
- }
- }
-
- for _, step := range parsed.Steps.ContainerList {
- for i, c := range step.When.Constraints {
- if len(c.Event.Exclude) != 0 {
- err = multierr.Append(err, &errorTypes.PipelineError{
- Type: errorTypes.PipelineErrorTypeDeprecation,
- Message: "Please only use allow lists for events",
- Data: errors.DeprecationErrorData{
- File: config.File,
- Field: fmt.Sprintf("steps.%s.when[%d].event", step.Name, i),
- Docs: "https://woodpecker-ci.org/docs/usage/workflow-syntax#event",
- },
- IsWarning: true,
- })
- }
- }
- }
-
- for _, step := range parsed.Steps.ContainerList {
- for i, c := range step.Secrets.Secrets {
- if c.Source != c.Target {
- err = multierr.Append(err, &errorTypes.PipelineError{
- Type: errorTypes.PipelineErrorTypeDeprecation,
- Message: "Secrets alternative names are deprecated, use environment with from_secret",
- Data: errors.DeprecationErrorData{
- File: config.File,
- Field: fmt.Sprintf("steps.%s.secrets[%d]", step.Name, i),
- Docs: "https://woodpecker-ci.org/docs/usage/secrets#use-secrets-in-settings-and-environment",
- },
- IsWarning: true,
- })
- }
- }
- }
-
- for i, c := range parsed.When.Constraints {
- if !c.Environment.IsEmpty() {
- err = multierr.Append(err, &errorTypes.PipelineError{
- Type: errorTypes.PipelineErrorTypeDeprecation,
- Message: "environment filters are deprecated, use evaluate with CI_PIPELINE_DEPLOY_TARGET",
- Data: errors.DeprecationErrorData{
- File: config.File,
- Field: fmt.Sprintf("when[%d].environment", i),
- Docs: "https://woodpecker-ci.org/docs/usage/workflow-syntax#evaluate",
- },
- IsWarning: true,
- })
- }
- }
-
- for _, step := range parsed.Steps.ContainerList {
- for i, c := range step.When.Constraints {
- if !c.Environment.IsEmpty() {
- err = multierr.Append(err, &errorTypes.PipelineError{
- Type: errorTypes.PipelineErrorTypeDeprecation,
- Message: "environment filters are deprecated, use evaluate with CI_PIPELINE_DEPLOY_TARGET",
- Data: errors.DeprecationErrorData{
- File: config.File,
- Field: fmt.Sprintf("steps.%s.when[%d].environment", step.Name, i),
- Docs: "https://woodpecker-ci.org/docs/usage/workflow-syntax#evaluate",
- },
- IsWarning: true,
- })
- }
- }
- }
-
- return err
+ return nil
}
func (l *Linter) lintBadHabits(config *WorkflowConfig) (err error) {
@@ -363,7 +280,7 @@ func (l *Linter) lintBadHabits(config *WorkflowConfig) (err error) {
rootEventFilters := len(parsed.When.Constraints) > 0
for _, c := range parsed.When.Constraints {
- if len(c.Event.Include) == 0 {
+ if len(c.Event) == 0 {
rootEventFilters = false
break
}
@@ -377,7 +294,7 @@ func (l *Linter) lintBadHabits(config *WorkflowConfig) (err error) {
} else {
stepEventIndex := -1
for i, c := range step.When.Constraints {
- if len(c.Event.Include) == 0 {
+ if len(c.Event) == 0 {
stepEventIndex = i
break
}
diff --git a/pipeline/frontend/yaml/linter/linter_test.go b/pipeline/frontend/yaml/linter/linter_test.go
index 84afb44d8..3c0e73417 100644
--- a/pipeline/frontend/yaml/linter/linter_test.go
+++ b/pipeline/frontend/yaml/linter/linter_test.go
@@ -39,7 +39,7 @@ steps:
- go build
- go test
publish:
- image: plugins/docker
+ image: woodpeckerci/plugin-kaniko
settings:
repo: foo/bar
foo: bar
@@ -61,7 +61,7 @@ steps:
- go build
- go test
- name: publish
- image: plugins/docker
+ image: woodpeckerci/plugin-kaniko
settings:
repo: foo/bar
foo: bar
@@ -145,10 +145,6 @@ func TestLintErrors(t *testing.T) {
from: "steps: { build: { image: golang, network_mode: host } }",
want: "Insufficient privileges to use network_mode",
},
- {
- from: "steps: { build: { image: golang, networks: [ outside, default ] } }",
- want: "Insufficient privileges to use networks",
- },
{
from: "steps: { build: { image: golang, volumes: [ '/opt/data:/var/lib/mysql' ] } }",
want: "Insufficient privileges to use volumes",
@@ -157,6 +153,30 @@ func TestLintErrors(t *testing.T) {
from: "steps: { build: { image: golang, network_mode: 'container:name' } }",
want: "Insufficient privileges to use network_mode",
},
+ {
+ from: "steps: { build: { image: golang, settings: { test: 'true' }, commands: [ 'echo ja', 'echo nein' ] } }",
+ want: "Cannot configure both commands and settings",
+ },
+ {
+ from: "steps: { build: { image: golang, settings: { test: 'true' }, entrypoint: [ '/bin/fish' ] } }",
+ want: "Cannot configure both entrypoint and settings",
+ },
+ {
+ from: "steps: { build: { image: golang, settings: { test: 'true' }, environment: { 'TEST': 'true' } } }",
+ want: "Should not configure both environment and settings",
+ },
+ {
+ from: "{pipeline: { build: { image: golang, settings: { test: 'true' } } }, when: { branch: main, event: push } }",
+ want: "Additional property pipeline is not allowed",
+ },
+ {
+ from: "{steps: { build: { image: plugins/docker, settings: { test: 'true' } } }, when: { branch: main, event: push } } }",
+ want: "Cannot use once by default privileged plugin 'plugins/docker', if needed add it too WOODPECKER_PLUGINS_PRIVILEGED",
+ },
+ {
+ from: "{steps: { build: { image: golang, settings: { test: 'true' } } }, when: { branch: main, event: push }, clone: { git: { image: some-other/plugin-git:v1.1.0 } } }",
+ want: "Specified clone image does not match allow list, netrc will not be injected",
+ },
}
for _, test := range testdata {
diff --git a/pipeline/frontend/yaml/linter/option.go b/pipeline/frontend/yaml/linter/option.go
index 0fe2af76f..ca9a3afd9 100644
--- a/pipeline/frontend/yaml/linter/option.go
+++ b/pipeline/frontend/yaml/linter/option.go
@@ -23,3 +23,17 @@ func WithTrusted(trusted bool) Option {
linter.trusted = trusted
}
}
+
+// PrivilegedPlugins adds the list of privileged plugins.
+func PrivilegedPlugins(plugins []string) Option {
+ return func(linter *Linter) {
+ linter.privilegedPlugins = &plugins
+ }
+}
+
+// WithTrustedClonePlugins adds the list of trusted clone plugins.
+func WithTrustedClonePlugins(plugins []string) Option {
+ return func(linter *Linter) {
+ linter.trustedClonePlugins = &plugins
+ }
+}
diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-array-syntax.yaml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-array-syntax.yaml
index a21b77261..569e5529c 100644
--- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-array-syntax.yaml
+++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-array-syntax.yaml
@@ -1,5 +1,3 @@
-version: 1
-
clone:
- name: git
image: woodpeckerci/plugin-git
diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-branches-array.yaml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-branches-array.yaml
deleted file mode 100644
index d530db055..000000000
--- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-branches-array.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-branches: [main, pages]
-
-steps:
- build:
- image: golang
- commands:
- - go test
diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-branches-exclude-include.yaml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-branches-exclude-include.yaml
deleted file mode 100644
index 03b534d23..000000000
--- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-branches-exclude-include.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-branches:
- include: main
- exclude: [develop, feature/*]
-
-steps:
- build:
- image: golang
- commands:
- - go test
diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-branches.yaml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-branches.yaml
deleted file mode 100644
index 75b72bbcf..000000000
--- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-branches.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-branches: main
-
-steps:
- build:
- image: golang
- commands:
- - go test
diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-broken-plugin.yaml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-broken-plugin.yaml
new file mode 100644
index 000000000..886dee977
--- /dev/null
+++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-broken-plugin.yaml
@@ -0,0 +1,8 @@
+steps:
+ publish:
+ image: plugins/docker
+ settings:
+ repo: foo/bar
+ tags: latest
+ environment:
+ CGO: 0
diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-broken-plugin2.yaml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-broken-plugin2.yaml
new file mode 100644
index 000000000..2dbba2e90
--- /dev/null
+++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-broken-plugin2.yaml
@@ -0,0 +1,8 @@
+steps:
+ publish:
+ image: plugins/docker
+ settings:
+ repo: foo/bar
+ tags: latest
+ commands:
+ - env
diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-platform.yaml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-platform.yaml
deleted file mode 100644
index 7b4abf027..000000000
--- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-platform.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-platform: linux/amd64
-
-steps:
- build:
- image: golang:latest
- commands:
- - go test
diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-service.yaml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-service.yaml
index 03564e9fc..16429df75 100644
--- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-service.yaml
+++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-service.yaml
@@ -10,3 +10,4 @@ services:
image: mysql
cache:
image: redis
+ directory: /tmp/
diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-step.yaml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-step.yaml
index fc63e8d6e..da6ada4f2 100644
--- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-step.yaml
+++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-step.yaml
@@ -18,7 +18,7 @@ steps:
image: alpine
entrypoint: ['some_entry', '--some-flag']
- singla-entrypoint:
+ single-entrypoint:
image: alpine
entrypoint: some_entry
@@ -38,15 +38,6 @@ steps:
commands:
- go test
- environment-array:
- image: golang
- environment:
- - CGO=0
- - GOOS=linux
- - GOARCH=amd64
- commands:
- - go test
-
secrets:
image: docker
commands:
@@ -54,14 +45,7 @@ steps:
- echo $DOCKER_PASSWORD
secrets:
- docker_username
- - source: docker_prod_password
- target: docker_password
-
- group:
- group: test
- image: golang
- commands:
- - go test
+ - docker_prod_password
detached:
image: redis
diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-when.yaml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-when.yaml
index b08385a77..a8235b65e 100644
--- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-when.yaml
+++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-when.yaml
@@ -19,6 +19,9 @@ steps:
- echo "test"
when:
event: push
+ branch:
+ include: main
+ exclude: [develop, feature/*]
when-event-array:
image: alpine
@@ -34,14 +37,6 @@ steps:
- deployment
- release
- when-event-exclude-pull_request_closed:
- image: alpine
- commands:
- - echo "test"
- when:
- event:
- exclude: pull_request_closed
-
when-ref:
image: alpine
commands:
@@ -75,7 +70,6 @@ steps:
commands:
- echo "test"
when:
- environment: production
event: deployment
when-matrix:
diff --git a/pipeline/frontend/yaml/linter/schema/schema.json b/pipeline/frontend/yaml/linter/schema/schema.json
index f735c0ea3..6128ce15b 100644
--- a/pipeline/frontend/yaml/linter/schema/schema.json
+++ b/pipeline/frontend/yaml/linter/schema/schema.json
@@ -20,19 +20,12 @@
"skip_clone": {
"type": "boolean"
},
- "branches": {
- "$ref": "#/definitions/branches"
- },
"when": {
- "$ref": "#/definitions/pipeline_when"
+ "$ref": "#/definitions/workflow_when"
},
"steps": {
"$ref": "#/definitions/step_list"
},
- "pipeline": {
- "$ref": "#/definitions/step_list",
- "description": "deprecated, use steps"
- },
"services": {
"$ref": "#/definitions/services"
},
@@ -42,9 +35,6 @@
"matrix": {
"$ref": "#/definitions/matrix"
},
- "platform": {
- "$ref": "#/definitions/platform"
- },
"labels": {
"$ref": "#/definitions/labels"
},
@@ -61,10 +51,6 @@
"items": {
"type": "string"
}
- },
- "version": {
- "type": "number",
- "default": 1
}
},
"definitions": {
@@ -128,55 +114,6 @@
"type": ["boolean", "string", "number", "array", "object"]
}
},
- "branches": {
- "description": "deprecated, use when.branch",
- "oneOf": [
- {
- "type": "array",
- "items": {
- "type": "string"
- },
- "minProperties": 1
- },
- {
- "type": "string"
- },
- {
- "type": "object",
- "additionalProperties": false,
- "properties": {
- "exclude": {
- "oneOf": [
- {
- "type": "array",
- "items": {
- "type": "string"
- },
- "minLength": 1
- },
- {
- "type": "string"
- }
- ]
- },
- "include": {
- "oneOf": [
- {
- "type": "array",
- "items": {
- "type": "string"
- },
- "minLength": 1
- },
- {
- "type": "string"
- }
- ]
- }
- }
- }
- ]
- },
"step_list": {
"description": "The steps section defines a list of steps which will be executed serially, in the order in which they are defined. Read more: https://woodpecker-ci.org/docs/usage/workflow-syntax#steps",
"oneOf": [
@@ -196,22 +133,22 @@
}
]
},
- "pipeline_when": {
- "description": "Whole pipelines can be skipped based on conditions. Read more: https://woodpecker-ci.org/docs/usage/workflow-syntax#when---global-workflow-conditions",
+ "workflow_when": {
+ "description": "Whole workflow can be skipped based on conditions. Read more: https://woodpecker-ci.org/docs/usage/workflow-syntax#when---global-workflow-conditions",
"oneOf": [
{
"type": "array",
"minLength": 1,
"items": {
- "$ref": "#/definitions/pipeline_when_condition"
+ "$ref": "#/definitions/workflow_when_condition"
}
},
{
- "$ref": "#/definitions/pipeline_when_condition"
+ "$ref": "#/definitions/workflow_when_condition"
}
]
},
- "pipeline_when_condition": {
+ "workflow_when_condition": {
"type": "object",
"additionalProperties": false,
"properties": {
@@ -226,18 +163,7 @@
"event": {
"description": "Read more: https://woodpecker-ci.org/docs/usage/workflow-syntax#event",
"default": [],
- "oneOf": [
- {
- "type": "array",
- "minLength": 1,
- "items": {
- "$ref": "#/definitions/event_enum"
- }
- },
- {
- "$ref": "#/definitions/event_enum"
- }
- ]
+ "$ref": "#/definitions/event_constraint_list"
},
"ref": {
"description": "Read more: https://woodpecker-ci.org/docs/usage/workflow-syntax#ref",
@@ -251,10 +177,6 @@
"description": "Execute a step only on a specific platform. Read more: https://woodpecker-ci.org/docs/usage/workflow-syntax#platform",
"$ref": "#/definitions/constraint_list"
},
- "environment": {
- "description": "Execute a step only for a specific environment. Read more: https://woodpecker-ci.org/docs/usage/workflow-syntax#environment",
- "$ref": "#/definitions/constraint_list"
- },
"instance": {
"description": "Read more: https://woodpecker-ci.org/docs/usage/workflow-syntax#instance",
"$ref": "#/definitions/constraint_list"
@@ -304,10 +226,43 @@
}
},
"step": {
+ "description": "A step of your workflow executes either arbitrary commands or uses a plugin. Read more: https://woodpecker-ci.org/docs/usage/workflow-syntax#steps",
+ "anyOf": [
+ {
+ "$ref": "#/definitions/commands_step"
+ },
+ {
+ "$ref": "#/definitions/plugin_step"
+ }
+ ]
+ },
+ "commands_step": {
"description": "Every step of your pipeline executes arbitrary commands inside a specified docker container. Read more: https://woodpecker-ci.org/docs/usage/workflow-syntax#steps",
"type": "object",
"additionalProperties": false,
"required": ["image"],
+ "allOf": [
+ {
+ "if": {
+ "properties": {
+ "detach": {
+ "const": true
+ }
+ }
+ },
+ "then": {},
+ "else": {
+ "anyOf": [
+ {
+ "required": ["commands"]
+ },
+ {
+ "required": ["entrypoint"]
+ }
+ ]
+ }
+ }
+ ],
"properties": {
"name": {
"description": "The name of the step. Can be used if using the array style steps list.",
@@ -334,19 +289,12 @@
"secrets": {
"$ref": "#/definitions/step_secrets"
},
- "settings": {
- "$ref": "#/definitions/step_settings"
- },
"when": {
"$ref": "#/definitions/step_when"
},
"volumes": {
"$ref": "#/definitions/step_volumes"
},
- "group": {
- "description": "deprecated, use depends_on",
- "type": "string"
- },
"depends_on": {
"description": "Execute a step after another step has finished.",
"oneOf": [
@@ -392,6 +340,67 @@
}
}
},
+ "plugin_step": {
+ "description": "Plugins let you execute predefined functions in a more secure context. Read more: https://woodpecker-ci.org/docs/usage/plugins/overview",
+ "type": "object",
+ "additionalProperties": false,
+ "required": ["image"],
+ "properties": {
+ "name": {
+ "description": "The name of the step. Can be used if using the array style steps list.",
+ "type": "string"
+ },
+ "image": {
+ "$ref": "#/definitions/step_image"
+ },
+ "privileged": {
+ "$ref": "#/definitions/step_privileged"
+ },
+ "pull": {
+ "$ref": "#/definitions/step_pull"
+ },
+ "directory": {
+ "$ref": "#/definitions/step_directory"
+ },
+ "settings": {
+ "$ref": "#/definitions/step_settings"
+ },
+ "when": {
+ "$ref": "#/definitions/step_when"
+ },
+ "volumes": {
+ "$ref": "#/definitions/step_volumes"
+ },
+ "depends_on": {
+ "description": "Execute a step after another step has finished.",
+ "oneOf": [
+ {
+ "type": "array",
+ "minLength": 1,
+ "items": {
+ "type": "string"
+ }
+ },
+ {
+ "type": "string"
+ }
+ ]
+ },
+ "detach": {
+ "description": "Detach a step to run in background until pipeline finishes. Read more: https://woodpecker-ci.org/docs/usage/services#detachment",
+ "type": "boolean"
+ },
+ "failure": {
+ "description": "How to handle the failure of this step. Read more: https://woodpecker-ci.org/docs/usage/workflow-syntax#failure",
+ "type": "string",
+ "enum": ["fail", "ignore"],
+ "default": "fail"
+ },
+ "backend_options": {
+ "$ref": "#/definitions/step_backend_options"
+ }
+ }
+ },
"step_when": {
"description": "Steps can be skipped based on conditions. Read more: https://woodpecker-ci.org/docs/usage/workflow-syntax#when---conditional-execution",
"oneOf": [
@@ -452,10 +461,6 @@
"description": "Execute a step only on a specific platform. Read more: https://woodpecker-ci.org/docs/usage/workflow-syntax#platform",
"$ref": "#/definitions/constraint_list"
},
- "environment": {
- "description": "Execute a step only for a specific environment. Read more: https://woodpecker-ci.org/docs/usage/workflow-syntax#environment",
- "$ref": "#/definitions/constraint_list"
- },
"matrix": {
"description": "Read more: https://woodpecker-ci.org/docs/usage/matrix-workflows",
"type": "object",
@@ -525,40 +530,6 @@
"items": {
"$ref": "#/definitions/event_enum"
}
- },
- {
- "type": "object",
- "additionalProperties": false,
- "properties": {
- "include": {
- "oneOf": [
- {
- "$ref": "#/definitions/event_enum"
- },
- {
- "type": "array",
- "minLength": 1,
- "items": {
- "$ref": "#/definitions/event_enum"
- }
- }
- ]
- },
- "exclude": {
- "oneOf": [
- {
- "$ref": "#/definitions/event_enum"
- },
- {
- "type": "array",
- "minLength": 1,
- "items": {
- "$ref": "#/definitions/event_enum"
- }
- }
- ]
- }
- }
}
]
},
@@ -640,43 +611,16 @@
},
"step_environment": {
"description": "Pass environment variables to a pipeline step. Read more: https://woodpecker-ci.org/docs/usage/environment",
- "oneOf": [
- {
- "type": "array",
- "items": {
- "type": "string"
- },
- "minLength": 1
- },
- {
- "type": "object",
- "additionalProperties": {
- "type": ["boolean", "string", "number", "array", "object"]
- }
- }
- ]
+ "type": "object",
+ "additionalProperties": {
+ "type": ["boolean", "string", "number", "array", "object"]
+ }
},
"step_secrets": {
"description": "Pass secrets to a pipeline step at runtime. Read more: https://woodpecker-ci.org/docs/usage/secrets",
"type": "array",
"items": {
- "oneOf": [
- {
- "type": "string"
- },
- {
- "type": "object",
- "required": ["source", "target"],
- "properties": {
- "source": {
- "type": "string"
- },
- "target": {
- "type": "string"
- }
- }
- }
- ]
+ "type": "string"
},
"minLength": 1
},
@@ -730,6 +674,14 @@
"runtimeClassName": {
"description": "Read more: https://woodpecker-ci.org/docs/administration/backends/kubernetes#runtimeclassname",
"type": "string"
+ },
+ "secrets": {
+ "description": "The secrets section defines a list of references to the native Kubernetes secrets",
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/step_kubernetes_secret"
+ },
+ "minLength": 1
}
}
},
@@ -810,6 +762,41 @@
"type": "string"
}
},
+ "step_kubernetes_secret": {
+ "description": "A reference to a native Kubernetes secret",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "name": {
+ "description": "The name of the secret. Can be used if using the array style secrets list.",
+ "type": "string"
+ },
+ "key": {
+ "description": "The key of the secret to select from.",
+ "type": "string"
+ },
+ "target": {
+ "$ref": "#/definitions/step_kubernetes_secret_target"
+ }
+ }
+ },
+ "step_kubernetes_secret_target": {
+ "description": "A target which a native Kubernetes secret maps to.",
+ "oneOf": [
+ {
+ "env": {
+ "description": "The name of the environment variable which secret maps to.",
+ "type": "string"
+ }
+ },
+ {
+ "file": {
+ "description": "The filename (path) which secret maps to.",
+ "type": "string"
+ }
+ }
+ ]
+ },
"services": {
"description": "Read more: https://woodpecker-ci.org/docs/usage/services",
"oneOf": [
@@ -855,6 +842,9 @@
"environment": {
"$ref": "#/definitions/step_environment"
},
+ "directory": {
+ "$ref": "#/definitions/step_directory"
+ },
"secrets": {
"$ref": "#/definitions/step_secrets"
},
@@ -912,11 +902,6 @@
"minLength": 1
}
},
- "platform": {
- "description": "deprecated, use labels.platform",
- "type": "string",
- "additionalProperties": false
- },
"labels": {
"description": "Configures the labels used for the agent selection. Read more: https://woodpecker-ci.org/docs/usage/workflow-syntax#labels",
"type": "object",
diff --git a/pipeline/frontend/yaml/linter/schema/schema_test.go b/pipeline/frontend/yaml/linter/schema/schema_test.go
index d423a9e3d..2a5526e24 100644
--- a/pipeline/frontend/yaml/linter/schema/schema_test.go
+++ b/pipeline/frontend/yaml/linter/schema/schema_test.go
@@ -32,18 +32,6 @@ func TestSchema(t *testing.T) {
testFile string
fail bool
}{
- {
- name: "Branches",
- testFile: ".woodpecker/test-branches.yaml",
- },
- {
- name: "Branches Array",
- testFile: ".woodpecker/test-branches-array.yaml",
- },
- {
- name: "Branches exclude & include",
- testFile: ".woodpecker/test-branches-exclude-include.yaml",
- },
{
name: "Clone",
testFile: ".woodpecker/test-clone.yaml",
@@ -84,10 +72,6 @@ func TestSchema(t *testing.T) {
name: "Workspace",
testFile: ".woodpecker/test-workspace.yaml",
},
- {
- name: "Platform",
- testFile: ".woodpecker/test-platform.yaml",
- },
{
name: "Labels",
testFile: ".woodpecker/test-labels.yaml",
@@ -116,6 +100,16 @@ func TestSchema(t *testing.T) {
testFile: ".woodpecker/test-custom-backend.yaml",
fail: false,
},
+ {
+ name: "Broken Plugin by environment",
+ testFile: ".woodpecker/test-broken-plugin.yaml",
+ fail: true,
+ },
+ {
+ name: "Broken Plugin by commands",
+ testFile: ".woodpecker/test-broken-plugin2.yaml",
+ fail: true,
+ },
}
for _, tt := range testTable {
diff --git a/pipeline/frontend/yaml/parse.go b/pipeline/frontend/yaml/parse.go
index 8607dd537..e9a6255fe 100644
--- a/pipeline/frontend/yaml/parse.go
+++ b/pipeline/frontend/yaml/parse.go
@@ -15,11 +15,8 @@
package yaml
import (
- "fmt"
-
"codeberg.org/6543/xyaml"
- "go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/constraint"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/types"
)
@@ -30,37 +27,6 @@ func ParseBytes(b []byte) (*types.Workflow, error) {
if err != nil {
return nil, err
}
-
- // support deprecated branch filter
- if out.BranchesDoNotUseIt != nil {
- switch {
- case out.When.Constraints == nil:
- out.When.Constraints = []constraint.Constraint{{Branch: *out.BranchesDoNotUseIt}}
- case len(out.When.Constraints) == 1 && out.When.Constraints[0].Branch.IsEmpty():
- out.When.Constraints[0].Branch = *out.BranchesDoNotUseIt
- default:
- return nil, fmt.Errorf("could not apply deprecated branches filter into global when filter")
- }
- out.BranchesDoNotUseIt = nil
- }
-
- // support deprecated pipeline keyword
- if len(out.PipelineDoNotUseIt.ContainerList) != 0 && len(out.Steps.ContainerList) == 0 {
- out.Steps.ContainerList = out.PipelineDoNotUseIt.ContainerList
- }
-
- // support deprecated platform filter
- if out.PlatformDoNotUseIt != "" {
- if out.Labels == nil {
- out.Labels = make(map[string]string)
- }
- if _, set := out.Labels["platform"]; !set {
- out.Labels["platform"] = out.PlatformDoNotUseIt
- }
- out.PlatformDoNotUseIt = ""
- }
- out.PipelineDoNotUseIt.ContainerList = nil
-
return out, nil
}
diff --git a/pipeline/frontend/yaml/parse_test.go b/pipeline/frontend/yaml/parse_test.go
index 5402cd03c..3dec23cd1 100644
--- a/pipeline/frontend/yaml/parse_test.go
+++ b/pipeline/frontend/yaml/parse_test.go
@@ -15,6 +15,7 @@
package yaml
import (
+ "slices"
"testing"
"github.com/franela/goblin"
@@ -35,7 +36,7 @@ func TestParse(t *testing.T) {
g.Fail(err)
}
- g.Assert(out.When.Constraints[0].Event.Match("tester")).Equal(true)
+ g.Assert(slices.Contains(out.When.Constraints[0].Event, "tester")).Equal(true)
g.Assert(out.Workspace.Base).Equal("/go")
g.Assert(out.Workspace.Path).Equal("src/github.com/octocat/hello-world")
@@ -85,7 +86,7 @@ func TestParse(t *testing.T) {
g.Assert(len(out.Steps.ContainerList[0].When.Constraints)).Equal(0)
g.Assert(out.Steps.ContainerList[1].Name).Equal("notify_success")
g.Assert(out.Steps.ContainerList[1].Image).Equal("plugins/slack")
- g.Assert(out.Steps.ContainerList[1].When.Constraints[0].Event.Include).Equal([]string{"success"})
+ g.Assert(out.Steps.ContainerList[1].When.Constraints[0].Event).Equal(yaml_base_types.StringOrSlice{"success"})
})
matchConfig, err := ParseString(sampleYaml)
@@ -139,10 +140,11 @@ func TestParse(t *testing.T) {
}
func TestParseLegacy(t *testing.T) {
- sampleYamlPipelineLegacy := `
-platform: linux/amd64
+ sampleYamlPipeline := `
+labels:
+ platform: linux/amd64
-pipeline:
+steps:
say hello:
image: bash
commands: echo hello
@@ -164,7 +166,7 @@ pipeline:
commands: meh!
`
- workflow1, err := ParseString(sampleYamlPipelineLegacy)
+ workflow1, err := ParseString(sampleYamlPipeline)
if !assert.NoError(t, err) {
return
}
diff --git a/pipeline/frontend/yaml/types/base/map.go b/pipeline/frontend/yaml/types/base/map.go
deleted file mode 100644
index 2cdd35b8b..000000000
--- a/pipeline/frontend/yaml/types/base/map.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2023 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 base
-
-import (
- "errors"
- "fmt"
- "strings"
-)
-
-// SliceOrMap represents a map of strings, string slice are converted into a map.
-type SliceOrMap map[string]any
-
-// UnmarshalYAML implements the Unmarshaler interface.
-func (s *SliceOrMap) UnmarshalYAML(unmarshal func(any) error) error {
- var sliceType []any
- if err := unmarshal(&sliceType); err == nil {
- parts := map[string]any{}
- for _, s := range sliceType {
- if str, ok := s.(string); ok {
- str := strings.TrimSpace(str)
- key, val, _ := strings.Cut(str, "=")
- parts[key] = val
- } else {
- return fmt.Errorf("cannot unmarshal '%v' of type %T into a string value", s, s)
- }
- }
- *s = parts
- return nil
- }
-
- var mapType map[string]any
- if err := unmarshal(&mapType); err == nil {
- *s = mapType
- return nil
- }
-
- return errors.New("failed to unmarshal SliceOrMap")
-}
diff --git a/pipeline/frontend/yaml/types/base/map_test.go b/pipeline/frontend/yaml/types/base/map_test.go
deleted file mode 100644
index 750fd1714..000000000
--- a/pipeline/frontend/yaml/types/base/map_test.go
+++ /dev/null
@@ -1,58 +0,0 @@
-// 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 base
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
- "gopkg.in/yaml.v3"
-)
-
-type StructSliceOrMap struct {
- Foos SliceOrMap `yaml:"foos,omitempty"`
- Bars []string `yaml:"bars"`
-}
-
-func TestSliceOrMapYaml(t *testing.T) {
- str := `{foos: [bar=baz, far=faz]}`
-
- s := StructSliceOrMap{}
- assert.NoError(t, yaml.Unmarshal([]byte(str), &s))
-
- assert.Equal(t, SliceOrMap{"bar": "baz", "far": "faz"}, s.Foos)
-
- d, err := yaml.Marshal(&s)
- assert.NoError(t, err)
-
- s2 := StructSliceOrMap{}
- assert.NoError(t, yaml.Unmarshal(d, &s2))
-
- assert.Equal(t, SliceOrMap{"bar": "baz", "far": "faz"}, s2.Foos)
-}
-
-func TestStr2SliceOrMapPtrMap(t *testing.T) {
- s := map[string]*StructSliceOrMap{"udav": {
- Foos: SliceOrMap{"io.rancher.os.bar": "baz", "io.rancher.os.far": "true"},
- Bars: []string{},
- }}
- d, err := yaml.Marshal(&s)
- assert.NoError(t, err)
-
- s2 := map[string]*StructSliceOrMap{}
- assert.NoError(t, yaml.Unmarshal(d, &s2))
-
- assert.Equal(t, s, s2)
-}
diff --git a/pipeline/frontend/yaml/types/container.go b/pipeline/frontend/yaml/types/container.go
index 6de8ab9e7..9ebc8f12a 100644
--- a/pipeline/frontend/yaml/types/container.go
+++ b/pipeline/frontend/yaml/types/container.go
@@ -22,7 +22,6 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/constraint"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/types/base"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/utils"
- "go.woodpecker-ci.org/woodpecker/v2/shared/constant"
)
type (
@@ -39,7 +38,6 @@ type (
Detached bool `yaml:"detach,omitempty"`
Directory string `yaml:"directory,omitempty"`
Failure string `yaml:"failure,omitempty"`
- Group string `yaml:"group,omitempty"`
Image string `yaml:"image,omitempty"`
Name string `yaml:"name,omitempty"`
Pull bool `yaml:"pull,omitempty"`
@@ -49,10 +47,8 @@ type (
Ports []string `yaml:"ports,omitempty"`
DependsOn base.StringOrSlice `yaml:"depends_on,omitempty"`
- // TODO: make []string in 3.x
- Secrets Secrets `yaml:"secrets,omitempty"`
- // TODO: make map[string]any in 3.x
- Environment base.SliceOrMap `yaml:"environment,omitempty"`
+ Secrets []string `yaml:"secrets,omitempty"`
+ Environment map[string]any `yaml:"environment,omitempty"`
// Docker and Kubernetes Specific
Privileged bool `yaml:"privileged,omitempty"`
@@ -68,7 +64,6 @@ type (
MemLimit base.MemStringOrInt `yaml:"mem_limit,omitempty"`
MemSwapLimit base.MemStringOrInt `yaml:"memswap_limit,omitempty"`
NetworkMode string `yaml:"network_mode,omitempty"`
- Networks Networks `yaml:"networks,omitempty"`
ShmSize base.MemStringOrInt `yaml:"shm_size,omitempty"`
Tmpfs []string `yaml:"tmpfs,omitempty"`
}
@@ -123,9 +118,12 @@ func (c *ContainerList) UnmarshalYAML(value *yaml.Node) error {
}
func (c *Container) IsPlugin() bool {
- return len(c.Commands) == 0 && len(c.Entrypoint) == 0
+ return len(c.Commands) == 0 &&
+ len(c.Entrypoint) == 0 &&
+ len(c.Environment) == 0 &&
+ len(c.Secrets) == 0
}
-func (c *Container) IsTrustedCloneImage() bool {
- return c.IsPlugin() && utils.MatchImage(c.Image, constant.TrustedCloneImages...)
+func (c *Container) IsTrustedCloneImage(trustedClonePlugins []string) bool {
+ return c.IsPlugin() && utils.MatchImageDynamic(c.Image, trustedClonePlugins...)
}
diff --git a/pipeline/frontend/yaml/types/container_test.go b/pipeline/frontend/yaml/types/container_test.go
index 5d8fbb0cc..10de961c7 100644
--- a/pipeline/frontend/yaml/types/container_test.go
+++ b/pipeline/frontend/yaml/types/container_test.go
@@ -41,8 +41,8 @@ dns: 8.8.8.8
dns_search: example.com
entrypoint: [/bin/sh, -c]
environment:
- - RACK_ENV=development
- - SHOW=true
+ RACK_ENV: development
+ SHOW: true
extra_hosts:
- somehost:162.242.195.82
- otherhost:50.31.209.229
@@ -88,23 +88,17 @@ func TestUnmarshalContainer(t *testing.T) {
DNS: base.StringOrSlice{"8.8.8.8"},
DNSSearch: base.StringOrSlice{"example.com"},
Entrypoint: []string{"/bin/sh", "-c"},
- Environment: base.SliceOrMap{"RACK_ENV": "development", "SHOW": "true"},
+ Environment: map[string]any{"RACK_ENV": "development", "SHOW": true},
ExtraHosts: []string{"somehost:162.242.195.82", "otherhost:50.31.209.229", "ipv6:2001:db8::10"},
Image: "golang:latest",
MemLimit: base.MemStringOrInt(1024),
MemSwapLimit: base.MemStringOrInt(1024),
Name: "my-build-container",
- Networks: Networks{
- Networks: []*Network{
- {Name: "some-network"},
- {Name: "other-network"},
- },
- },
- NetworkMode: "bridge",
- Pull: true,
- Privileged: true,
- ShmSize: base.MemStringOrInt(1024),
- Tmpfs: base.StringOrSlice{"/var/lib/test"},
+ NetworkMode: "bridge",
+ Pull: true,
+ Privileged: true,
+ ShmSize: base.MemStringOrInt(1024),
+ Tmpfs: base.StringOrSlice{"/var/lib/test"},
Volumes: Volumes{
Volumes: []*Volume{
{Source: "", Destination: "/var/lib/mysql"},
@@ -120,9 +114,7 @@ func TestUnmarshalContainer(t *testing.T) {
},
},
{
- Event: constraint.List{
- Include: []string{"cron"},
- },
+ Event: base.StringOrSlice{"cron"},
Cron: constraint.List{
Include: []string{"job1"},
},
@@ -172,7 +164,6 @@ func TestUnmarshalContainers(t *testing.T) {
},
{
from: `publish-agent:
- group: bundle
image: print/env
settings:
repo: woodpeckerci/woodpecker-agent
@@ -185,16 +176,9 @@ func TestUnmarshalContainers(t *testing.T) {
event: push`,
want: []*Container{
{
- Name: "publish-agent",
- Image: "print/env",
- Group: "bundle",
- Secrets: Secrets{Secrets: []*Secret{{
- Source: "docker_username",
- Target: "docker_username",
- }, {
- Source: "docker_password",
- Target: "docker_password",
- }}},
+ Name: "publish-agent",
+ Image: "print/env",
+ Secrets: []string{"docker_username", "docker_password"},
Settings: map[string]any{
"repo": "woodpeckerci/woodpecker-agent",
"dockerfile": "docker/Dockerfile.agent",
@@ -204,7 +188,7 @@ func TestUnmarshalContainers(t *testing.T) {
When: constraint.When{
Constraints: []constraint.Constraint{
{
- Event: constraint.List{Include: []string{"push"}},
+ Event: base.StringOrSlice{"push"},
Branch: constraint.List{Include: []string{"${CI_REPO_DEFAULT_BRANCH}"}},
},
},
@@ -214,7 +198,6 @@ func TestUnmarshalContainers(t *testing.T) {
},
{
from: `publish-cli:
- group: docker
image: print/env
settings:
repo: woodpeckerci/woodpecker-cli
@@ -227,7 +210,6 @@ func TestUnmarshalContainers(t *testing.T) {
{
Name: "publish-cli",
Image: "print/env",
- Group: "docker",
Settings: map[string]any{
"repo": "woodpeckerci/woodpecker-cli",
"dockerfile": "docker/Dockerfile.cli",
@@ -236,7 +218,7 @@ func TestUnmarshalContainers(t *testing.T) {
When: constraint.When{
Constraints: []constraint.Constraint{
{
- Event: constraint.List{Include: []string{"push"}},
+ Event: base.StringOrSlice{"push"},
Branch: constraint.List{Include: []string{"${CI_REPO_DEFAULT_BRANCH}"}},
},
},
@@ -258,11 +240,11 @@ func TestUnmarshalContainers(t *testing.T) {
When: constraint.When{
Constraints: []constraint.Constraint{
{
- Event: constraint.List{Include: []string{"push"}},
+ Event: base.StringOrSlice{"push"},
Branch: constraint.List{Include: []string{"${CI_REPO_DEFAULT_BRANCH}"}},
},
{
- Event: constraint.List{Include: []string{"pull_request"}},
+ Event: base.StringOrSlice{"pull_request"},
},
},
},
diff --git a/pipeline/frontend/yaml/types/secret.go b/pipeline/frontend/yaml/types/secret.go
deleted file mode 100644
index 9958b41aa..000000000
--- a/pipeline/frontend/yaml/types/secret.go
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2023 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 types
-
-import "gopkg.in/yaml.v3"
-
-type (
- // Secrets defines a collection of secrets.
- Secrets struct {
- Secrets []*Secret
- }
-
- // Secret defines a container secret.
- Secret struct {
- Source string `yaml:"source"`
- Target string `yaml:"target"`
- }
-)
-
-// UnmarshalYAML implements the Unmarshaler interface.
-func (s *Secrets) UnmarshalYAML(value *yaml.Node) error {
- y, _ := yaml.Marshal(value)
-
- var secrets []string
- err := yaml.Unmarshal(y, &secrets)
- if err == nil {
- for _, str := range secrets {
- s.Secrets = append(s.Secrets, &Secret{
- Source: str,
- Target: str,
- })
- }
- return nil
- }
- return yaml.Unmarshal(y, &s.Secrets)
-}
diff --git a/pipeline/frontend/yaml/types/secret_test.go b/pipeline/frontend/yaml/types/secret_test.go
deleted file mode 100644
index fcfc6d212..000000000
--- a/pipeline/frontend/yaml/types/secret_test.go
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2023 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 types
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
- "gopkg.in/yaml.v3"
-)
-
-func TestUnmarshalSecrets(t *testing.T) {
- testdata := []struct {
- from string
- want []*Secret
- }{
- {
- from: "[ mysql_username, mysql_password]",
- want: []*Secret{
- {
- Source: "mysql_username",
- Target: "mysql_username",
- },
- {
- Source: "mysql_password",
- Target: "mysql_password",
- },
- },
- },
- {
- from: "[ { source: mysql_prod_username, target: mysql_username } ]",
- want: []*Secret{
- {
- Source: "mysql_prod_username",
- Target: "mysql_username",
- },
- },
- },
- {
- from: "[ { source: mysql_prod_username, target: mysql_username }, { source: redis_username, target: redis_username } ]",
- want: []*Secret{
- {
- Source: "mysql_prod_username",
- Target: "mysql_username",
- },
- {
- Source: "redis_username",
- Target: "redis_username",
- },
- },
- },
- }
-
- for _, test := range testdata {
- in := []byte(test.from)
- got := Secrets{}
- err := yaml.Unmarshal(in, &got)
- assert.NoError(t, err)
- assert.EqualValues(t, test.want, got.Secrets, "problem parsing secrets %q", test.from)
- }
-}
diff --git a/pipeline/frontend/yaml/types/workflow.go b/pipeline/frontend/yaml/types/workflow.go
index 4f291dec3..f1e753b3d 100644
--- a/pipeline/frontend/yaml/types/workflow.go
+++ b/pipeline/frontend/yaml/types/workflow.go
@@ -34,13 +34,6 @@ type (
// Undocumented
Networks WorkflowNetworks `yaml:"networks,omitempty"`
Volumes WorkflowVolumes `yaml:"volumes,omitempty"`
-
- // Deprecated
- PlatformDoNotUseIt string `yaml:"platform,omitempty"` // TODO: remove in next major version
- // Deprecated
- BranchesDoNotUseIt *constraint.List `yaml:"branches,omitempty"` // TODO: remove in next major version
- // Deprecated
- PipelineDoNotUseIt ContainerList `yaml:"pipeline,omitempty"` // TODO: remove in next major version
}
// Workspace defines a pipeline workspace.
diff --git a/pipeline/frontend/yaml/utils/image.go b/pipeline/frontend/yaml/utils/image.go
index 63054c21d..3462a58f1 100644
--- a/pipeline/frontend/yaml/utils/image.go
+++ b/pipeline/frontend/yaml/utils/image.go
@@ -14,7 +14,11 @@
package utils
-import "github.com/distribution/reference"
+import (
+ "strings"
+
+ "github.com/distribution/reference"
+)
// trimImage returns the short image name without tag.
func trimImage(name string) string {
@@ -57,6 +61,29 @@ func MatchImage(from string, to ...string) bool {
return false
}
+// MatchImageDynamic check if image is in list based on list.
+// If an list entry has a tag specified it only will match if both are the same, else the tag is ignored.
+func MatchImageDynamic(from string, to ...string) bool {
+ fullFrom := expandImage(from)
+ trimFrom := trimImage(from)
+ for _, match := range to {
+ if imageHasTag(match) {
+ if fullFrom == expandImage(match) {
+ return true
+ }
+ } else {
+ if trimFrom == trimImage(match) {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+func imageHasTag(name string) bool {
+ return strings.Contains(name, ":")
+}
+
// MatchHostname returns true if the image hostname
// matches the specified hostname.
func MatchHostname(image, hostname string) bool {
diff --git a/pipeline/frontend/yaml/utils/image_test.go b/pipeline/frontend/yaml/utils/image_test.go
index 17fab45d5..a1250a49d 100644
--- a/pipeline/frontend/yaml/utils/image_test.go
+++ b/pipeline/frontend/yaml/utils/image_test.go
@@ -113,6 +113,10 @@ func Test_expandImage(t *testing.T) {
from: "gcr.io/golang:1.0.0",
want: "gcr.io/golang:1.0.0",
},
+ {
+ from: "codeberg.org/6543/hello:latest@2c98dce11f78c2b4e40f513ca82f75035eb8cfa4957a6d8eb3f917ecaf77803",
+ want: "codeberg.org/6543/hello:latest@2c98dce11f78c2b4e40f513ca82f75035eb8cfa4957a6d8eb3f917ecaf77803",
+ },
// error cases, return input unmodified
{
from: "foo/bar?baz:boo",
@@ -124,6 +128,57 @@ func Test_expandImage(t *testing.T) {
}
}
+func Test_imageHasTag(t *testing.T) {
+ testdata := []struct {
+ from string
+ want bool
+ }{
+ {
+ from: "golang",
+ want: false,
+ },
+ {
+ from: "golang:latest",
+ want: true,
+ },
+ {
+ from: "golang:1.0.0",
+ want: true,
+ },
+ {
+ from: "library/golang",
+ want: false,
+ },
+ {
+ from: "library/golang:latest",
+ want: true,
+ },
+ {
+ from: "library/golang:1.0.0",
+ want: true,
+ },
+ {
+ from: "index.docker.io/library/golang:1.0.0",
+ want: true,
+ },
+ {
+ from: "gcr.io/golang",
+ want: false,
+ },
+ {
+ from: "gcr.io/golang:1.0.0",
+ want: true,
+ },
+ {
+ from: "codeberg.org/6543/hello:latest@2c98dce11f78c2b4e40f513ca82f75035eb8cfa4957a6d8eb3f917ecaf77803",
+ want: true,
+ },
+ }
+ for _, test := range testdata {
+ assert.Equal(t, test.want, imageHasTag(test.from))
+ }
+}
+
func Test_matchImage(t *testing.T) {
testdata := []struct {
from, to string
@@ -199,12 +254,67 @@ func Test_matchImage(t *testing.T) {
to: "gcr.io/golang",
want: false,
},
+ {
+ from: "woodpeckerci/plugin-kaniko",
+ to: "docker.io/woodpeckerci/plugin-kaniko",
+ want: true,
+ },
}
for _, test := range testdata {
assert.Equal(t, test.want, MatchImage(test.from, test.to))
}
}
+func Test_matchImageDynamic(t *testing.T) {
+ testdata := []struct {
+ name, from string
+ to []string
+ want bool
+ }{
+ {
+ name: "simple compare",
+ from: "golang",
+ to: []string{"golang"},
+ want: true,
+ },
+ {
+ name: "compare non-taged image whit list who tag requirement",
+ from: "golang",
+ to: []string{"golang:v3.0"},
+ want: false,
+ },
+ {
+ name: "compare taged image whit list who tag no requirement",
+ from: "golang:v3.0",
+ to: []string{"golang"},
+ want: true,
+ },
+ {
+ name: "compare taged image whit list who has image with no tag requirement",
+ from: "golang:1.0",
+ to: []string{"golang", "golang:2.0"},
+ want: true,
+ },
+ {
+ name: "compare taged image whit list who only has images with tag requirement",
+ from: "golang:1.0",
+ to: []string{"golang:latest", "golang:2.0"},
+ want: false,
+ },
+ {
+ name: "compare taged image whit list who only has images with tag requirement",
+ from: "golang:1.0",
+ to: []string{"golang:latest", "golang:1.0"},
+ want: true,
+ },
+ }
+ for _, test := range testdata {
+ if !assert.Equal(t, test.want, MatchImageDynamic(test.from, test.to...)) {
+ t.Logf("test data: '%s' -> '%s'", test.from, test.to)
+ }
+ }
+}
+
func Test_matchHostname(t *testing.T) {
testdata := []struct {
image, hostname string
diff --git a/pipeline/log/line_writer.go b/pipeline/log/line_writer.go
index e2a6fd2e4..ff8706f36 100644
--- a/pipeline/log/line_writer.go
+++ b/pipeline/log/line_writer.go
@@ -16,7 +16,6 @@
package log
import (
- "context"
"io"
"strings"
"sync"
@@ -40,7 +39,7 @@ type LineWriter struct {
}
// NewLineWriter returns a new line reader.
-func NewLineWriter(peer rpc.Peer, stepUUID string, secret ...string) io.WriteCloser {
+func NewLineWriter(peer rpc.Peer, stepUUID string, secret ...string) io.Writer {
lw := &LineWriter{
peer: peer,
stepUUID: stepUUID,
@@ -67,13 +66,6 @@ func (w *LineWriter) Write(p []byte) (n int, err error) {
w.num++
- if err := w.peer.Log(context.Background(), line); err != nil {
- return 0, err
- }
-
+ w.peer.EnqueueLog(line)
return len(data), nil
}
-
-func (w *LineWriter) Close() error {
- return nil
-}
diff --git a/pipeline/log/line_writer_test.go b/pipeline/log/line_writer_test.go
index 669f75973..8a2d6b120 100644
--- a/pipeline/log/line_writer_test.go
+++ b/pipeline/log/line_writer_test.go
@@ -27,18 +27,17 @@ import (
func TestLineWriter(t *testing.T) {
peer := mocks.NewPeer(t)
- peer.On("Log", mock.Anything, mock.Anything).Return(nil)
+ peer.On("EnqueueLog", mock.Anything)
secrets := []string{"world"}
lw := log.NewLineWriter(peer, "e9ea76a5-44a1-4059-9c4a-6956c478b26d", secrets...)
- defer lw.Close()
_, err := lw.Write([]byte("hello world\n"))
assert.NoError(t, err)
_, err = lw.Write([]byte("the previous line had no newline at the end"))
assert.NoError(t, err)
- peer.AssertCalled(t, "Log", mock.Anything, &rpc.LogEntry{
+ peer.AssertCalled(t, "EnqueueLog", &rpc.LogEntry{
StepUUID: "e9ea76a5-44a1-4059-9c4a-6956c478b26d",
Time: 0,
Type: rpc.LogEntryStdout,
@@ -46,7 +45,7 @@ func TestLineWriter(t *testing.T) {
Data: []byte("hello ********"),
})
- peer.AssertCalled(t, "Log", mock.Anything, &rpc.LogEntry{
+ peer.AssertCalled(t, "EnqueueLog", &rpc.LogEntry{
StepUUID: "e9ea76a5-44a1-4059-9c4a-6956c478b26d",
Time: 0,
Type: rpc.LogEntryStdout,
diff --git a/pipeline/log/utils.go b/pipeline/log/utils.go
index ade772c82..6c3e2dfe7 100644
--- a/pipeline/log/utils.go
+++ b/pipeline/log/utils.go
@@ -20,7 +20,7 @@ import (
"io"
)
-func writeChunks(dst io.WriteCloser, data []byte, size int) error {
+func writeChunks(dst io.Writer, data []byte, size int) error {
if len(data) <= size {
_, err := dst.Write(data)
return err
@@ -41,9 +41,8 @@ func writeChunks(dst io.WriteCloser, data []byte, size int) error {
return nil
}
-func CopyLineByLine(dst io.WriteCloser, src io.Reader, maxSize int) error {
+func CopyLineByLine(dst io.Writer, src io.Reader, maxSize int) error {
r := bufio.NewReader(src)
- defer dst.Close()
for {
// TODO: read til newline or maxSize directly
diff --git a/pipeline/log/utils_test.go b/pipeline/log/utils_test.go
index 2e21b01ef..cbc15b735 100644
--- a/pipeline/log/utils_test.go
+++ b/pipeline/log/utils_test.go
@@ -83,7 +83,7 @@ func TestCopyLineByLine(t *testing.T) {
assert.Lenf(t, writes, 2, "expected 2 writes, got: %v", writes)
// wait for the goroutine to write the data
- time.Sleep(time.Millisecond)
+ time.Sleep(10 * time.Millisecond)
writtenData := strings.Join(writes, "-")
assert.Equal(t, "12345\n-678\n", writtenData, "unexpected writtenData: %s", writtenData)
@@ -131,6 +131,8 @@ func TestCopyLineByLineSizeLimit(t *testing.T) {
if _, err := w.Write([]byte("67\n89")); err != nil {
t.Fatalf("unexpected error: %v", err)
}
+ // wait for writer to write
+ time.Sleep(time.Millisecond)
writes = testWriter.GetWrites()
assert.Lenf(t, testWriter.GetWrites(), 2, "expected 2 writes, got: %v", writes)
@@ -144,3 +146,18 @@ func TestCopyLineByLineSizeLimit(t *testing.T) {
wg.Wait()
}
+
+func TestStringReader(t *testing.T) {
+ r := io.NopCloser(strings.NewReader("123\n4567\n890"))
+
+ testWriter := &testWriter{
+ Mutex: &sync.Mutex{},
+ writes: make([]string, 0),
+ }
+
+ err := log.CopyLineByLine(testWriter, r, 1024)
+ assert.NoError(t, err)
+
+ writes := testWriter.GetWrites()
+ assert.Lenf(t, writes, 3, "expected 3 writes, got: %v", writes)
+}
diff --git a/pipeline/logger.go b/pipeline/logger.go
index c557e0e94..6eea180d1 100644
--- a/pipeline/logger.go
+++ b/pipeline/logger.go
@@ -21,4 +21,4 @@ import (
)
// Logger handles the process logging.
-type Logger func(*backend.Step, io.Reader) error
+type Logger func(*backend.Step, io.ReadCloser) error
diff --git a/pipeline/pipeline.go b/pipeline/pipeline.go
index 7267c6a57..2b732b444 100644
--- a/pipeline/pipeline.go
+++ b/pipeline/pipeline.go
@@ -38,7 +38,7 @@ type (
// Global state of the pipeline.
Pipeline struct {
// Pipeline time started
- Time int64 `json:"time"`
+ Started int64 `json:"time"`
// Current pipeline step
Step *backend.Step `json:"step"`
// Current pipeline error state
@@ -105,7 +105,11 @@ func (r *Runtime) Run(runnerCtx context.Context) error {
}
defer func() {
- if err := r.engine.DestroyWorkflow(runnerCtx, r.spec, r.taskUUID); err != nil {
+ ctx := runnerCtx //nolint:contextcheck
+ if ctx.Err() != nil {
+ ctx = GetShutdownCtx()
+ }
+ if err := r.engine.DestroyWorkflow(ctx, r.spec, r.taskUUID); err != nil {
logger.Error().Err(err).Msg("could not destroy engine")
}
}()
@@ -147,7 +151,7 @@ func (r *Runtime) traceStep(processState *backend.State, err error, step *backen
}
state := new(State)
- state.Pipeline.Time = r.started
+ state.Pipeline.Started = r.started
state.Pipeline.Step = step
state.Process = processState // empty
state.Pipeline.Error = r.err
@@ -254,9 +258,9 @@ func (r *Runtime) exec(step *backend.Step) (*backend.State, error) {
return nil, nil
}
- // Some pipeline backends, such as local, will close the pipe from Tail on Wait,
- // so first make sure all reading has finished.
+ // We wait until all data was logged. (Needed for some backends like local as WaitStep kills the log stream)
wg.Wait()
+
waitState, err := r.engine.WaitStep(r.ctx, step, r.taskUUID)
if err != nil {
if errors.Is(err, context.Canceled) {
diff --git a/pipeline/rpc/mocks/peer.go b/pipeline/rpc/mocks/peer.go
index 3409ca35d..c98456284 100644
--- a/pipeline/rpc/mocks/peer.go
+++ b/pipeline/rpc/mocks/peer.go
@@ -1,5 +1,8 @@
// Code generated by mockery. DO NOT EDIT.
+//go:build test
+// +build test
+
package mocks
import (
@@ -14,17 +17,17 @@ type Peer struct {
mock.Mock
}
-// Done provides a mock function with given fields: c, id, state
-func (_m *Peer) Done(c context.Context, id string, state rpc.State) error {
- ret := _m.Called(c, id, state)
+// Done provides a mock function with given fields: c, workflowID, state
+func (_m *Peer) Done(c context.Context, workflowID string, state rpc.WorkflowState) error {
+ ret := _m.Called(c, workflowID, state)
if len(ret) == 0 {
panic("no return value specified for Done")
}
var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, string, rpc.State) error); ok {
- r0 = rf(c, id, state)
+ if rf, ok := ret.Get(0).(func(context.Context, string, rpc.WorkflowState) error); ok {
+ r0 = rf(c, workflowID, state)
} else {
r0 = ret.Error(0)
}
@@ -32,9 +35,14 @@ func (_m *Peer) Done(c context.Context, id string, state rpc.State) error {
return r0
}
-// Extend provides a mock function with given fields: c, id
-func (_m *Peer) Extend(c context.Context, id string) error {
- ret := _m.Called(c, id)
+// EnqueueLog provides a mock function with given fields: logEntry
+func (_m *Peer) EnqueueLog(logEntry *rpc.LogEntry) {
+ _m.Called(logEntry)
+}
+
+// Extend provides a mock function with given fields: c, workflowID
+func (_m *Peer) Extend(c context.Context, workflowID string) error {
+ ret := _m.Called(c, workflowID)
if len(ret) == 0 {
panic("no return value specified for Extend")
@@ -42,7 +50,7 @@ func (_m *Peer) Extend(c context.Context, id string) error {
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
- r0 = rf(c, id)
+ r0 = rf(c, workflowID)
} else {
r0 = ret.Error(0)
}
@@ -50,35 +58,17 @@ func (_m *Peer) Extend(c context.Context, id string) error {
return r0
}
-// Init provides a mock function with given fields: c, id, state
-func (_m *Peer) Init(c context.Context, id string, state rpc.State) error {
- ret := _m.Called(c, id, state)
+// Init provides a mock function with given fields: c, workflowID, state
+func (_m *Peer) Init(c context.Context, workflowID string, state rpc.WorkflowState) error {
+ ret := _m.Called(c, workflowID, state)
if len(ret) == 0 {
panic("no return value specified for Init")
}
var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, string, rpc.State) error); ok {
- r0 = rf(c, id, state)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Log provides a mock function with given fields: c, logEntry
-func (_m *Peer) Log(c context.Context, logEntry *rpc.LogEntry) error {
- ret := _m.Called(c, logEntry)
-
- if len(ret) == 0 {
- panic("no return value specified for Log")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, *rpc.LogEntry) error); ok {
- r0 = rf(c, logEntry)
+ if rf, ok := ret.Get(0).(func(context.Context, string, rpc.WorkflowState) error); ok {
+ r0 = rf(c, workflowID, state)
} else {
r0 = ret.Error(0)
}
@@ -180,17 +170,17 @@ func (_m *Peer) UnregisterAgent(ctx context.Context) error {
return r0
}
-// Update provides a mock function with given fields: c, id, state
-func (_m *Peer) Update(c context.Context, id string, state rpc.State) error {
- ret := _m.Called(c, id, state)
+// Update provides a mock function with given fields: c, workflowID, state
+func (_m *Peer) Update(c context.Context, workflowID string, state rpc.StepState) error {
+ ret := _m.Called(c, workflowID, state)
if len(ret) == 0 {
panic("no return value specified for Update")
}
var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, string, rpc.State) error); ok {
- r0 = rf(c, id, state)
+ if rf, ok := ret.Get(0).(func(context.Context, string, rpc.StepState) error); ok {
+ r0 = rf(c, workflowID, state)
} else {
r0 = ret.Error(0)
}
@@ -228,9 +218,9 @@ func (_m *Peer) Version(c context.Context) (*rpc.Version, error) {
return r0, r1
}
-// Wait provides a mock function with given fields: c, id
-func (_m *Peer) Wait(c context.Context, id string) error {
- ret := _m.Called(c, id)
+// Wait provides a mock function with given fields: c, workflowID
+func (_m *Peer) Wait(c context.Context, workflowID string) error {
+ ret := _m.Called(c, workflowID)
if len(ret) == 0 {
panic("no return value specified for Wait")
@@ -238,7 +228,7 @@ func (_m *Peer) Wait(c context.Context, id string) error {
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
- r0 = rf(c, id)
+ r0 = rf(c, workflowID)
} else {
r0 = ret.Error(0)
}
diff --git a/pipeline/rpc/peer.go b/pipeline/rpc/peer.go
index 8025080b5..050a2ab11 100644
--- a/pipeline/rpc/peer.go
+++ b/pipeline/rpc/peer.go
@@ -27,11 +27,18 @@ type (
Labels map[string]string `json:"labels"`
}
- // State defines the step state.
- State struct {
+ // StepState defines the step state.
+ StepState struct {
StepUUID string `json:"step_uuid"`
+ Started int64 `json:"started"`
+ Finished int64 `json:"finished"`
Exited bool `json:"exited"`
ExitCode int `json:"exit_code"`
+ Error string `json:"error"`
+ }
+
+ // WorkflowState defines the workflow state.
+ WorkflowState struct {
Started int64 `json:"started"`
Finished int64 `json:"finished"`
Error string `json:"error"`
@@ -50,7 +57,7 @@ type (
}
)
-//go:generate mockery --name Peer --output mocks --case underscore
+//go:generate mockery --name Peer --output mocks --case underscore --note "+build test"
// Peer defines a peer-to-peer connection.
type Peer interface {
@@ -61,22 +68,22 @@ type Peer interface {
Next(c context.Context, f Filter) (*Workflow, error)
// Wait blocks until the workflow is complete
- Wait(c context.Context, id string) error
+ Wait(c context.Context, workflowID string) error
- // Init signals the step is initialized
- Init(c context.Context, id string, state State) error
+ // Init signals the workflow is initialized
+ Init(c context.Context, workflowID string, state WorkflowState) error
- // Done signals the step is complete
- Done(c context.Context, id string, state State) error
+ // Done signals the workflow is complete
+ Done(c context.Context, workflowID string, state WorkflowState) error
// Extend extends the workflow deadline
- Extend(c context.Context, id string) error
+ Extend(c context.Context, workflowID string) error
// Update updates the step state
- Update(c context.Context, id string, state State) error
+ Update(c context.Context, workflowID string, state StepState) error
- // Log writes the workflow log entry
- Log(c context.Context, logEntry *LogEntry) error
+ // EnqueueLog queues the step log entry for delayed sending
+ EnqueueLog(logEntry *LogEntry)
// RegisterAgent register our agent to the server
RegisterAgent(ctx context.Context, platform, backend, version string, capacity int) (int64, error)
diff --git a/pipeline/rpc/proto/version.go b/pipeline/rpc/proto/version.go
index b009af074..8f79192ce 100644
--- a/pipeline/rpc/proto/version.go
+++ b/pipeline/rpc/proto/version.go
@@ -16,4 +16,4 @@ package proto
// Version is the version of the woodpecker.proto file,
// IMPORTANT: increased by 1 each time it get changed.
-const Version int32 = 8
+const Version int32 = 10
diff --git a/pipeline/rpc/proto/woodpecker.pb.go b/pipeline/rpc/proto/woodpecker.pb.go
index 2bda93f06..dd3423175 100644
--- a/pipeline/rpc/proto/woodpecker.pb.go
+++ b/pipeline/rpc/proto/woodpecker.pb.go
@@ -16,7 +16,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.1
-// protoc v4.25.1
+// protoc v4.25.4
// source: woodpecker.proto
package proto
@@ -35,21 +35,21 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
-type State struct {
+type StepState struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
StepUuid string `protobuf:"bytes,1,opt,name=step_uuid,json=stepUuid,proto3" json:"step_uuid,omitempty"`
- Exited bool `protobuf:"varint,2,opt,name=exited,proto3" json:"exited,omitempty"`
- ExitCode int32 `protobuf:"varint,3,opt,name=exit_code,json=exitCode,proto3" json:"exit_code,omitempty"`
- Started int64 `protobuf:"varint,4,opt,name=started,proto3" json:"started,omitempty"`
- Finished int64 `protobuf:"varint,5,opt,name=finished,proto3" json:"finished,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"`
}
-func (x *State) Reset() {
- *x = State{}
+func (x *StepState) Reset() {
+ *x = StepState{}
if protoimpl.UnsafeEnabled {
mi := &file_woodpecker_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -57,13 +57,13 @@ func (x *State) Reset() {
}
}
-func (x *State) String() string {
+func (x *StepState) String() string {
return protoimpl.X.MessageStringOf(x)
}
-func (*State) ProtoMessage() {}
+func (*StepState) ProtoMessage() {}
-func (x *State) ProtoReflect() protoreflect.Message {
+func (x *StepState) ProtoReflect() protoreflect.Message {
mi := &file_woodpecker_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -75,47 +75,110 @@ func (x *State) ProtoReflect() protoreflect.Message {
return mi.MessageOf(x)
}
-// Deprecated: Use State.ProtoReflect.Descriptor instead.
-func (*State) Descriptor() ([]byte, []int) {
+// Deprecated: Use StepState.ProtoReflect.Descriptor instead.
+func (*StepState) Descriptor() ([]byte, []int) {
return file_woodpecker_proto_rawDescGZIP(), []int{0}
}
-func (x *State) GetStepUuid() string {
+func (x *StepState) GetStepUuid() string {
if x != nil {
return x.StepUuid
}
return ""
}
-func (x *State) GetExited() bool {
- if x != nil {
- return x.Exited
- }
- return false
-}
-
-func (x *State) GetExitCode() int32 {
- if x != nil {
- return x.ExitCode
- }
- return 0
-}
-
-func (x *State) GetStarted() int64 {
+func (x *StepState) GetStarted() int64 {
if x != nil {
return x.Started
}
return 0
}
-func (x *State) GetFinished() int64 {
+func (x *StepState) GetFinished() int64 {
if x != nil {
return x.Finished
}
return 0
}
-func (x *State) GetError() string {
+func (x *StepState) GetExited() bool {
+ if x != nil {
+ return x.Exited
+ }
+ return false
+}
+
+func (x *StepState) GetExitCode() int32 {
+ if x != nil {
+ return x.ExitCode
+ }
+ return 0
+}
+
+func (x *StepState) GetError() string {
+ if x != nil {
+ return x.Error
+ }
+ return ""
+}
+
+type WorkflowState struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ 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"`
+}
+
+func (x *WorkflowState) Reset() {
+ *x = WorkflowState{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_woodpecker_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *WorkflowState) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*WorkflowState) ProtoMessage() {}
+
+func (x *WorkflowState) ProtoReflect() protoreflect.Message {
+ mi := &file_woodpecker_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use WorkflowState.ProtoReflect.Descriptor instead.
+func (*WorkflowState) Descriptor() ([]byte, []int) {
+ return file_woodpecker_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *WorkflowState) GetStarted() int64 {
+ if x != nil {
+ return x.Started
+ }
+ return 0
+}
+
+func (x *WorkflowState) GetFinished() int64 {
+ if x != nil {
+ return x.Finished
+ }
+ return 0
+}
+
+func (x *WorkflowState) GetError() string {
if x != nil {
return x.Error
}
@@ -137,7 +200,7 @@ type LogEntry struct {
func (x *LogEntry) Reset() {
*x = LogEntry{}
if protoimpl.UnsafeEnabled {
- mi := &file_woodpecker_proto_msgTypes[1]
+ mi := &file_woodpecker_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -150,7 +213,7 @@ func (x *LogEntry) String() string {
func (*LogEntry) ProtoMessage() {}
func (x *LogEntry) ProtoReflect() protoreflect.Message {
- mi := &file_woodpecker_proto_msgTypes[1]
+ mi := &file_woodpecker_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -163,7 +226,7 @@ func (x *LogEntry) ProtoReflect() protoreflect.Message {
// Deprecated: Use LogEntry.ProtoReflect.Descriptor instead.
func (*LogEntry) Descriptor() ([]byte, []int) {
- return file_woodpecker_proto_rawDescGZIP(), []int{1}
+ return file_woodpecker_proto_rawDescGZIP(), []int{2}
}
func (x *LogEntry) GetStepUuid() string {
@@ -212,7 +275,7 @@ type Filter struct {
func (x *Filter) Reset() {
*x = Filter{}
if protoimpl.UnsafeEnabled {
- mi := &file_woodpecker_proto_msgTypes[2]
+ mi := &file_woodpecker_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -225,7 +288,7 @@ func (x *Filter) String() string {
func (*Filter) ProtoMessage() {}
func (x *Filter) ProtoReflect() protoreflect.Message {
- mi := &file_woodpecker_proto_msgTypes[2]
+ mi := &file_woodpecker_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -238,7 +301,7 @@ func (x *Filter) ProtoReflect() protoreflect.Message {
// Deprecated: Use Filter.ProtoReflect.Descriptor instead.
func (*Filter) Descriptor() ([]byte, []int) {
- return file_woodpecker_proto_rawDescGZIP(), []int{2}
+ return file_woodpecker_proto_rawDescGZIP(), []int{3}
}
func (x *Filter) GetLabels() map[string]string {
@@ -261,7 +324,7 @@ type Workflow struct {
func (x *Workflow) Reset() {
*x = Workflow{}
if protoimpl.UnsafeEnabled {
- mi := &file_woodpecker_proto_msgTypes[3]
+ mi := &file_woodpecker_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -274,7 +337,7 @@ func (x *Workflow) String() string {
func (*Workflow) ProtoMessage() {}
func (x *Workflow) ProtoReflect() protoreflect.Message {
- mi := &file_woodpecker_proto_msgTypes[3]
+ mi := &file_woodpecker_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -287,7 +350,7 @@ func (x *Workflow) ProtoReflect() protoreflect.Message {
// Deprecated: Use Workflow.ProtoReflect.Descriptor instead.
func (*Workflow) Descriptor() ([]byte, []int) {
- return file_woodpecker_proto_rawDescGZIP(), []int{3}
+ return file_woodpecker_proto_rawDescGZIP(), []int{4}
}
func (x *Workflow) GetId() string {
@@ -322,7 +385,7 @@ type NextRequest struct {
func (x *NextRequest) Reset() {
*x = NextRequest{}
if protoimpl.UnsafeEnabled {
- mi := &file_woodpecker_proto_msgTypes[4]
+ mi := &file_woodpecker_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -335,7 +398,7 @@ func (x *NextRequest) String() string {
func (*NextRequest) ProtoMessage() {}
func (x *NextRequest) ProtoReflect() protoreflect.Message {
- mi := &file_woodpecker_proto_msgTypes[4]
+ mi := &file_woodpecker_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -348,7 +411,7 @@ func (x *NextRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use NextRequest.ProtoReflect.Descriptor instead.
func (*NextRequest) Descriptor() ([]byte, []int) {
- return file_woodpecker_proto_rawDescGZIP(), []int{4}
+ return file_woodpecker_proto_rawDescGZIP(), []int{5}
}
func (x *NextRequest) GetFilter() *Filter {
@@ -363,14 +426,14 @@ type InitRequest struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
- Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
- State *State `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"`
+ Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+ State *WorkflowState `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"`
}
func (x *InitRequest) Reset() {
*x = InitRequest{}
if protoimpl.UnsafeEnabled {
- mi := &file_woodpecker_proto_msgTypes[5]
+ mi := &file_woodpecker_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -383,7 +446,7 @@ func (x *InitRequest) String() string {
func (*InitRequest) ProtoMessage() {}
func (x *InitRequest) ProtoReflect() protoreflect.Message {
- mi := &file_woodpecker_proto_msgTypes[5]
+ mi := &file_woodpecker_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -396,7 +459,7 @@ func (x *InitRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use InitRequest.ProtoReflect.Descriptor instead.
func (*InitRequest) Descriptor() ([]byte, []int) {
- return file_woodpecker_proto_rawDescGZIP(), []int{5}
+ return file_woodpecker_proto_rawDescGZIP(), []int{6}
}
func (x *InitRequest) GetId() string {
@@ -406,7 +469,7 @@ func (x *InitRequest) GetId() string {
return ""
}
-func (x *InitRequest) GetState() *State {
+func (x *InitRequest) GetState() *WorkflowState {
if x != nil {
return x.State
}
@@ -424,7 +487,7 @@ type WaitRequest struct {
func (x *WaitRequest) Reset() {
*x = WaitRequest{}
if protoimpl.UnsafeEnabled {
- mi := &file_woodpecker_proto_msgTypes[6]
+ mi := &file_woodpecker_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -437,7 +500,7 @@ func (x *WaitRequest) String() string {
func (*WaitRequest) ProtoMessage() {}
func (x *WaitRequest) ProtoReflect() protoreflect.Message {
- mi := &file_woodpecker_proto_msgTypes[6]
+ mi := &file_woodpecker_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -450,7 +513,7 @@ func (x *WaitRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use WaitRequest.ProtoReflect.Descriptor instead.
func (*WaitRequest) Descriptor() ([]byte, []int) {
- return file_woodpecker_proto_rawDescGZIP(), []int{6}
+ return file_woodpecker_proto_rawDescGZIP(), []int{7}
}
func (x *WaitRequest) GetId() string {
@@ -465,14 +528,14 @@ type DoneRequest struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
- Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
- State *State `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"`
+ Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+ State *WorkflowState `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"`
}
func (x *DoneRequest) Reset() {
*x = DoneRequest{}
if protoimpl.UnsafeEnabled {
- mi := &file_woodpecker_proto_msgTypes[7]
+ mi := &file_woodpecker_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -485,7 +548,7 @@ func (x *DoneRequest) String() string {
func (*DoneRequest) ProtoMessage() {}
func (x *DoneRequest) ProtoReflect() protoreflect.Message {
- mi := &file_woodpecker_proto_msgTypes[7]
+ mi := &file_woodpecker_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -498,7 +561,7 @@ func (x *DoneRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use DoneRequest.ProtoReflect.Descriptor instead.
func (*DoneRequest) Descriptor() ([]byte, []int) {
- return file_woodpecker_proto_rawDescGZIP(), []int{7}
+ return file_woodpecker_proto_rawDescGZIP(), []int{8}
}
func (x *DoneRequest) GetId() string {
@@ -508,7 +571,7 @@ func (x *DoneRequest) GetId() string {
return ""
}
-func (x *DoneRequest) GetState() *State {
+func (x *DoneRequest) GetState() *WorkflowState {
if x != nil {
return x.State
}
@@ -526,7 +589,7 @@ type ExtendRequest struct {
func (x *ExtendRequest) Reset() {
*x = ExtendRequest{}
if protoimpl.UnsafeEnabled {
- mi := &file_woodpecker_proto_msgTypes[8]
+ mi := &file_woodpecker_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -539,7 +602,7 @@ func (x *ExtendRequest) String() string {
func (*ExtendRequest) ProtoMessage() {}
func (x *ExtendRequest) ProtoReflect() protoreflect.Message {
- mi := &file_woodpecker_proto_msgTypes[8]
+ mi := &file_woodpecker_proto_msgTypes[9]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -552,7 +615,7 @@ func (x *ExtendRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use ExtendRequest.ProtoReflect.Descriptor instead.
func (*ExtendRequest) Descriptor() ([]byte, []int) {
- return file_woodpecker_proto_rawDescGZIP(), []int{8}
+ return file_woodpecker_proto_rawDescGZIP(), []int{9}
}
func (x *ExtendRequest) GetId() string {
@@ -567,14 +630,14 @@ type UpdateRequest struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
- Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
- State *State `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"`
+ Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+ State *StepState `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"`
}
func (x *UpdateRequest) Reset() {
*x = UpdateRequest{}
if protoimpl.UnsafeEnabled {
- mi := &file_woodpecker_proto_msgTypes[9]
+ mi := &file_woodpecker_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -587,7 +650,7 @@ func (x *UpdateRequest) String() string {
func (*UpdateRequest) ProtoMessage() {}
func (x *UpdateRequest) ProtoReflect() protoreflect.Message {
- mi := &file_woodpecker_proto_msgTypes[9]
+ mi := &file_woodpecker_proto_msgTypes[10]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -600,7 +663,7 @@ func (x *UpdateRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use UpdateRequest.ProtoReflect.Descriptor instead.
func (*UpdateRequest) Descriptor() ([]byte, []int) {
- return file_woodpecker_proto_rawDescGZIP(), []int{9}
+ return file_woodpecker_proto_rawDescGZIP(), []int{10}
}
func (x *UpdateRequest) GetId() string {
@@ -610,7 +673,7 @@ func (x *UpdateRequest) GetId() string {
return ""
}
-func (x *UpdateRequest) GetState() *State {
+func (x *UpdateRequest) GetState() *StepState {
if x != nil {
return x.State
}
@@ -622,13 +685,13 @@ type LogRequest struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
- LogEntry *LogEntry `protobuf:"bytes,1,opt,name=logEntry,proto3" json:"logEntry,omitempty"`
+ LogEntries []*LogEntry `protobuf:"bytes,1,rep,name=logEntries,proto3" json:"logEntries,omitempty"`
}
func (x *LogRequest) Reset() {
*x = LogRequest{}
if protoimpl.UnsafeEnabled {
- mi := &file_woodpecker_proto_msgTypes[10]
+ mi := &file_woodpecker_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -641,7 +704,7 @@ func (x *LogRequest) String() string {
func (*LogRequest) ProtoMessage() {}
func (x *LogRequest) ProtoReflect() protoreflect.Message {
- mi := &file_woodpecker_proto_msgTypes[10]
+ mi := &file_woodpecker_proto_msgTypes[11]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -654,12 +717,12 @@ func (x *LogRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use LogRequest.ProtoReflect.Descriptor instead.
func (*LogRequest) Descriptor() ([]byte, []int) {
- return file_woodpecker_proto_rawDescGZIP(), []int{10}
+ return file_woodpecker_proto_rawDescGZIP(), []int{11}
}
-func (x *LogRequest) GetLogEntry() *LogEntry {
+func (x *LogRequest) GetLogEntries() []*LogEntry {
if x != nil {
- return x.LogEntry
+ return x.LogEntries
}
return nil
}
@@ -673,7 +736,7 @@ type Empty struct {
func (x *Empty) Reset() {
*x = Empty{}
if protoimpl.UnsafeEnabled {
- mi := &file_woodpecker_proto_msgTypes[11]
+ mi := &file_woodpecker_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -686,7 +749,7 @@ func (x *Empty) String() string {
func (*Empty) ProtoMessage() {}
func (x *Empty) ProtoReflect() protoreflect.Message {
- mi := &file_woodpecker_proto_msgTypes[11]
+ mi := &file_woodpecker_proto_msgTypes[12]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -699,7 +762,7 @@ func (x *Empty) ProtoReflect() protoreflect.Message {
// Deprecated: Use Empty.ProtoReflect.Descriptor instead.
func (*Empty) Descriptor() ([]byte, []int) {
- return file_woodpecker_proto_rawDescGZIP(), []int{11}
+ return file_woodpecker_proto_rawDescGZIP(), []int{12}
}
type ReportHealthRequest struct {
@@ -713,7 +776,7 @@ type ReportHealthRequest struct {
func (x *ReportHealthRequest) Reset() {
*x = ReportHealthRequest{}
if protoimpl.UnsafeEnabled {
- mi := &file_woodpecker_proto_msgTypes[12]
+ mi := &file_woodpecker_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -726,7 +789,7 @@ func (x *ReportHealthRequest) String() string {
func (*ReportHealthRequest) ProtoMessage() {}
func (x *ReportHealthRequest) ProtoReflect() protoreflect.Message {
- mi := &file_woodpecker_proto_msgTypes[12]
+ mi := &file_woodpecker_proto_msgTypes[13]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -739,7 +802,7 @@ func (x *ReportHealthRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use ReportHealthRequest.ProtoReflect.Descriptor instead.
func (*ReportHealthRequest) Descriptor() ([]byte, []int) {
- return file_woodpecker_proto_rawDescGZIP(), []int{12}
+ return file_woodpecker_proto_rawDescGZIP(), []int{13}
}
func (x *ReportHealthRequest) GetStatus() string {
@@ -763,7 +826,7 @@ type RegisterAgentRequest struct {
func (x *RegisterAgentRequest) Reset() {
*x = RegisterAgentRequest{}
if protoimpl.UnsafeEnabled {
- mi := &file_woodpecker_proto_msgTypes[13]
+ mi := &file_woodpecker_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -776,7 +839,7 @@ func (x *RegisterAgentRequest) String() string {
func (*RegisterAgentRequest) ProtoMessage() {}
func (x *RegisterAgentRequest) ProtoReflect() protoreflect.Message {
- mi := &file_woodpecker_proto_msgTypes[13]
+ mi := &file_woodpecker_proto_msgTypes[14]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -789,7 +852,7 @@ func (x *RegisterAgentRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use RegisterAgentRequest.ProtoReflect.Descriptor instead.
func (*RegisterAgentRequest) Descriptor() ([]byte, []int) {
- return file_woodpecker_proto_rawDescGZIP(), []int{13}
+ return file_woodpecker_proto_rawDescGZIP(), []int{14}
}
func (x *RegisterAgentRequest) GetPlatform() string {
@@ -832,7 +895,7 @@ type VersionResponse struct {
func (x *VersionResponse) Reset() {
*x = VersionResponse{}
if protoimpl.UnsafeEnabled {
- mi := &file_woodpecker_proto_msgTypes[14]
+ mi := &file_woodpecker_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -845,7 +908,7 @@ func (x *VersionResponse) String() string {
func (*VersionResponse) ProtoMessage() {}
func (x *VersionResponse) ProtoReflect() protoreflect.Message {
- mi := &file_woodpecker_proto_msgTypes[14]
+ mi := &file_woodpecker_proto_msgTypes[15]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -858,7 +921,7 @@ func (x *VersionResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use VersionResponse.ProtoReflect.Descriptor instead.
func (*VersionResponse) Descriptor() ([]byte, []int) {
- return file_woodpecker_proto_rawDescGZIP(), []int{14}
+ return file_woodpecker_proto_rawDescGZIP(), []int{15}
}
func (x *VersionResponse) GetGrpcVersion() int32 {
@@ -886,7 +949,7 @@ type NextResponse struct {
func (x *NextResponse) Reset() {
*x = NextResponse{}
if protoimpl.UnsafeEnabled {
- mi := &file_woodpecker_proto_msgTypes[15]
+ mi := &file_woodpecker_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -899,7 +962,7 @@ func (x *NextResponse) String() string {
func (*NextResponse) ProtoMessage() {}
func (x *NextResponse) ProtoReflect() protoreflect.Message {
- mi := &file_woodpecker_proto_msgTypes[15]
+ mi := &file_woodpecker_proto_msgTypes[16]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -912,7 +975,7 @@ func (x *NextResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use NextResponse.ProtoReflect.Descriptor instead.
func (*NextResponse) Descriptor() ([]byte, []int) {
- return file_woodpecker_proto_rawDescGZIP(), []int{15}
+ return file_woodpecker_proto_rawDescGZIP(), []int{16}
}
func (x *NextResponse) GetWorkflow() *Workflow {
@@ -933,7 +996,7 @@ type RegisterAgentResponse struct {
func (x *RegisterAgentResponse) Reset() {
*x = RegisterAgentResponse{}
if protoimpl.UnsafeEnabled {
- mi := &file_woodpecker_proto_msgTypes[16]
+ mi := &file_woodpecker_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -946,7 +1009,7 @@ func (x *RegisterAgentResponse) String() string {
func (*RegisterAgentResponse) ProtoMessage() {}
func (x *RegisterAgentResponse) ProtoReflect() protoreflect.Message {
- mi := &file_woodpecker_proto_msgTypes[16]
+ mi := &file_woodpecker_proto_msgTypes[17]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -959,7 +1022,7 @@ func (x *RegisterAgentResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use RegisterAgentResponse.ProtoReflect.Descriptor instead.
func (*RegisterAgentResponse) Descriptor() ([]byte, []int) {
- return file_woodpecker_proto_rawDescGZIP(), []int{16}
+ return file_woodpecker_proto_rawDescGZIP(), []int{17}
}
func (x *RegisterAgentResponse) GetAgentId() int64 {
@@ -981,7 +1044,7 @@ type AuthRequest struct {
func (x *AuthRequest) Reset() {
*x = AuthRequest{}
if protoimpl.UnsafeEnabled {
- mi := &file_woodpecker_proto_msgTypes[17]
+ mi := &file_woodpecker_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -994,7 +1057,7 @@ func (x *AuthRequest) String() string {
func (*AuthRequest) ProtoMessage() {}
func (x *AuthRequest) ProtoReflect() protoreflect.Message {
- mi := &file_woodpecker_proto_msgTypes[17]
+ mi := &file_woodpecker_proto_msgTypes[18]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1007,7 +1070,7 @@ func (x *AuthRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use AuthRequest.ProtoReflect.Descriptor instead.
func (*AuthRequest) Descriptor() ([]byte, []int) {
- return file_woodpecker_proto_rawDescGZIP(), []int{17}
+ return file_woodpecker_proto_rawDescGZIP(), []int{18}
}
func (x *AuthRequest) GetAgentToken() string {
@@ -1037,7 +1100,7 @@ type AuthResponse struct {
func (x *AuthResponse) Reset() {
*x = AuthResponse{}
if protoimpl.UnsafeEnabled {
- mi := &file_woodpecker_proto_msgTypes[18]
+ mi := &file_woodpecker_proto_msgTypes[19]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1050,7 +1113,7 @@ func (x *AuthResponse) String() string {
func (*AuthResponse) ProtoMessage() {}
func (x *AuthResponse) ProtoReflect() protoreflect.Message {
- mi := &file_woodpecker_proto_msgTypes[18]
+ mi := &file_woodpecker_proto_msgTypes[19]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1063,7 +1126,7 @@ func (x *AuthResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use AuthResponse.ProtoReflect.Descriptor instead.
func (*AuthResponse) Descriptor() ([]byte, []int) {
- return file_woodpecker_proto_rawDescGZIP(), []int{18}
+ return file_woodpecker_proto_rawDescGZIP(), []int{19}
}
func (x *AuthResponse) GetStatus() string {
@@ -1091,141 +1154,149 @@ var File_woodpecker_proto protoreflect.FileDescriptor
var file_woodpecker_proto_rawDesc = []byte{
0x0a, 0x10, 0x77, 0x6f, 0x6f, 0x64, 0x70, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f,
- 0x74, 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa5, 0x01, 0x0a, 0x05, 0x53, 0x74,
- 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x74, 0x65, 0x70, 0x5f, 0x75, 0x75, 0x69, 0x64,
- 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x74, 0x65, 0x70, 0x55, 0x75, 0x69, 0x64,
- 0x12, 0x16, 0x0a, 0x06, 0x65, 0x78, 0x69, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08,
- 0x52, 0x06, 0x65, 0x78, 0x69, 0x74, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x78, 0x69, 0x74,
- 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x65, 0x78, 0x69,
- 0x74, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64,
- 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x12,
- 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28,
- 0x03, 0x52, 0x08, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65,
- 0x72, 0x72, 0x6f, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f,
- 0x72, 0x22, 0x77, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x1b, 0x0a,
- 0x09, 0x73, 0x74, 0x65, 0x70, 0x5f, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x08, 0x73, 0x74, 0x65, 0x70, 0x55, 0x75, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69,
- 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12,
- 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x6c, 0x69,
- 0x6e, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05,
- 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05,
- 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x76, 0x0a, 0x06, 0x46, 0x69,
- 0x6c, 0x74, 0x65, 0x72, 0x12, 0x31, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x01,
- 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x69, 0x6c,
- 0x74, 0x65, 0x72, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52,
- 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c,
- 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
- 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
- 0x38, 0x01, 0x22, 0x4e, 0x0a, 0x08, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x0e,
- 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18,
- 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52,
- 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c,
- 0x6f, 0x61, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f,
- 0x61, 0x64, 0x22, 0x34, 0x0a, 0x0b, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
- 0x74, 0x12, 0x25, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72,
- 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x41, 0x0a, 0x0b, 0x49, 0x6e, 0x69, 0x74,
- 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x22, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65,
- 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53,
- 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x1d, 0x0a, 0x0b, 0x57,
- 0x61, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
- 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x41, 0x0a, 0x0b, 0x44, 0x6f,
- 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x22, 0x0a, 0x05, 0x73, 0x74, 0x61,
- 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
- 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x1f, 0x0a,
- 0x0d, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e,
- 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x43,
- 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+ 0x74, 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa9, 0x01, 0x0a, 0x09, 0x53, 0x74,
+ 0x65, 0x70, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x74, 0x65, 0x70, 0x5f,
+ 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x74, 0x65, 0x70,
+ 0x55, 0x75, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x12, 0x1a,
+ 0x0a, 0x08, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03,
+ 0x52, 0x08, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x78,
+ 0x69, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x65, 0x78, 0x69, 0x74,
+ 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18,
+ 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x65, 0x78, 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x12,
+ 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
+ 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x5b, 0x0a, 0x0d, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
+ 0x77, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65,
+ 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64,
+ 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01,
+ 0x28, 0x03, 0x52, 0x08, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05,
+ 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72,
+ 0x6f, 0x72, 0x22, 0x77, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x1b,
+ 0x0a, 0x09, 0x73, 0x74, 0x65, 0x70, 0x5f, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x08, 0x73, 0x74, 0x65, 0x70, 0x55, 0x75, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74,
+ 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12,
+ 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x6c,
+ 0x69, 0x6e, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28,
+ 0x05, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18,
+ 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x76, 0x0a, 0x06, 0x46,
+ 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x31, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18,
+ 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x69,
+ 0x6c, 0x74, 0x65, 0x72, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
+ 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65,
+ 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,
+ 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
+ 0x02, 0x38, 0x01, 0x22, 0x4e, 0x0a, 0x08, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12,
0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12,
- 0x22, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c,
- 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74,
- 0x61, 0x74, 0x65, 0x22, 0x39, 0x0a, 0x0a, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
- 0x74, 0x12, 0x2b, 0x0a, 0x08, 0x6c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4c, 0x6f, 0x67, 0x45,
- 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x07,
- 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x2d, 0x0a, 0x13, 0x52, 0x65, 0x70, 0x6f, 0x72,
- 0x74, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16,
- 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
- 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x82, 0x01, 0x0a, 0x14, 0x52, 0x65, 0x67, 0x69, 0x73,
- 0x74, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
- 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1a, 0x0a, 0x08, 0x63,
- 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x63,
- 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x65,
- 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e,
- 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x5b, 0x0a, 0x0f, 0x56,
- 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21,
- 0x0a, 0x0c, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01,
- 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x67, 0x72, 0x70, 0x63, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
- 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73,
- 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x72, 0x76, 0x65,
- 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3b, 0x0a, 0x0c, 0x4e, 0x65, 0x78, 0x74,
- 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b,
- 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f,
- 0x74, 0x6f, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x08, 0x77, 0x6f, 0x72,
- 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x22, 0x32, 0x0a, 0x15, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65,
- 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x19,
- 0x0a, 0x08, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03,
- 0x52, 0x07, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x49, 0x0a, 0x0b, 0x41, 0x75, 0x74,
- 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x67, 0x65, 0x6e,
- 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61,
- 0x67, 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x67, 0x65,
- 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x61, 0x67, 0x65,
- 0x6e, 0x74, 0x49, 0x64, 0x22, 0x64, 0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70,
- 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01,
- 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, 0x0a, 0x08,
- 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07,
- 0x61, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73,
- 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61,
- 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x32, 0xbb, 0x04, 0x0a, 0x0a, 0x57,
- 0x6f, 0x6f, 0x64, 0x70, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x12, 0x31, 0x0a, 0x07, 0x56, 0x65, 0x72,
- 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70,
- 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69,
- 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x04,
- 0x4e, 0x65, 0x78, 0x74, 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x65, 0x78,
- 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
- 0x2e, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12,
- 0x2a, 0x0a, 0x04, 0x49, 0x6e, 0x69, 0x74, 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
- 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x2a, 0x0a, 0x04, 0x57,
- 0x61, 0x69, 0x74, 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x57, 0x61, 0x69, 0x74,
- 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
- 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x2a, 0x0a, 0x04, 0x44, 0x6f, 0x6e, 0x65, 0x12,
- 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75,
- 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74,
- 0x79, 0x22, 0x00, 0x12, 0x2e, 0x0a, 0x06, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x12, 0x14, 0x2e,
- 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75,
- 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74,
- 0x79, 0x22, 0x00, 0x12, 0x2e, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x14, 0x2e,
- 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75,
- 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74,
- 0x79, 0x22, 0x00, 0x12, 0x28, 0x0a, 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x11, 0x2e, 0x70, 0x72, 0x6f,
- 0x74, 0x6f, 0x2e, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e,
- 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x4c, 0x0a,
- 0x0d, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x1b,
- 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x41,
- 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e,
- 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x0f, 0x55,
- 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x0c,
- 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0c, 0x2e, 0x70,
- 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x3a, 0x0a, 0x0c,
- 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x1a, 0x2e, 0x70,
- 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x48, 0x65, 0x61, 0x6c, 0x74,
- 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
- 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x32, 0x43, 0x0a, 0x0e, 0x57, 0x6f, 0x6f, 0x64,
- 0x70, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x41, 0x75, 0x74, 0x68, 0x12, 0x31, 0x0a, 0x04, 0x41, 0x75,
- 0x74, 0x68, 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52,
- 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41,
- 0x75, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x37, 0x5a,
- 0x35, 0x67, 0x6f, 0x2e, 0x77, 0x6f, 0x6f, 0x64, 0x70, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x2d, 0x63,
- 0x69, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x77, 0x6f, 0x6f, 0x64, 0x70, 0x65, 0x63, 0x6b, 0x65, 0x72,
- 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x69, 0x70, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x2f, 0x72, 0x70, 0x63,
- 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03,
+ 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79,
+ 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c,
+ 0x6f, 0x61, 0x64, 0x22, 0x34, 0x0a, 0x0b, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x12, 0x25, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65,
+ 0x72, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x49, 0x0a, 0x0b, 0x49, 0x6e, 0x69,
+ 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2a, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74,
+ 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
+ 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73,
+ 0x74, 0x61, 0x74, 0x65, 0x22, 0x1d, 0x0a, 0x0b, 0x57, 0x61, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x02, 0x69, 0x64, 0x22, 0x49, 0x0a, 0x0b, 0x44, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02,
+ 0x69, 0x64, 0x12, 0x2a, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
+ 0x6f, 0x77, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x1f,
+ 0x0a, 0x0d, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+ 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22,
+ 0x47, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64,
+ 0x12, 0x26, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x65, 0x70, 0x53, 0x74, 0x61, 0x74,
+ 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x3d, 0x0a, 0x0a, 0x4c, 0x6f, 0x67, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x0a, 0x6c, 0x6f, 0x67, 0x45, 0x6e, 0x74,
+ 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x2e, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6c, 0x6f, 0x67,
+ 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79,
+ 0x22, 0x2d, 0x0a, 0x13, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
+ 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22,
+ 0x82, 0x01, 0x0a, 0x14, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e,
+ 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74,
+ 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74,
+ 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x63, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79,
+ 0x12, 0x18, 0x0a, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65,
+ 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72,
+ 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x5b, 0x0a, 0x0f, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x67, 0x72, 0x70, 0x63, 0x5f,
+ 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x67,
+ 0x72, 0x70, 0x63, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x65,
+ 0x72, 0x76, 0x65, 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
+ 0x6e, 0x22, 0x3b, 0x0a, 0x0c, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+ 0x65, 0x12, 0x2b, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x57, 0x6f, 0x72, 0x6b,
+ 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x22, 0x32,
+ 0x0a, 0x15, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x67, 0x65, 0x6e, 0x74,
+ 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x61, 0x67, 0x65, 0x6e, 0x74,
+ 0x49, 0x64, 0x22, 0x49, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x6b,
+ 0x65, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x64, 0x0a,
+ 0x0c, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a,
+ 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73,
+ 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69,
+ 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x64,
+ 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
+ 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f,
+ 0x6b, 0x65, 0x6e, 0x32, 0xbb, 0x04, 0x0a, 0x0a, 0x57, 0x6f, 0x6f, 0x64, 0x70, 0x65, 0x63, 0x6b,
+ 0x65, 0x72, 0x12, 0x31, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0c, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x04, 0x4e, 0x65, 0x78, 0x74, 0x12, 0x12, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2a, 0x0a, 0x04, 0x49, 0x6e, 0x69, 0x74,
+ 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71,
+ 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70,
+ 0x74, 0x79, 0x22, 0x00, 0x12, 0x2a, 0x0a, 0x04, 0x57, 0x61, 0x69, 0x74, 0x12, 0x12, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x57, 0x61, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x1a, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00,
+ 0x12, 0x2a, 0x0a, 0x04, 0x44, 0x6f, 0x6e, 0x65, 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x2e, 0x44, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x2e, 0x0a, 0x06,
+ 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x12, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45,
+ 0x78, 0x74, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x2e, 0x0a, 0x06,
+ 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55,
+ 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x28, 0x0a, 0x03,
+ 0x4c, 0x6f, 0x67, 0x12, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4c, 0x6f, 0x67, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45,
+ 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x0d, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74,
+ 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
+ 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71,
+ 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x67,
+ 0x69, 0x73, 0x74, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x0f, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74,
+ 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
+ 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d,
+ 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x3a, 0x0a, 0x0c, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x48,
+ 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65,
+ 0x70, 0x6f, 0x72, 0x74, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x1a, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22,
+ 0x00, 0x32, 0x43, 0x0a, 0x0e, 0x57, 0x6f, 0x6f, 0x64, 0x70, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x41,
+ 0x75, 0x74, 0x68, 0x12, 0x31, 0x0a, 0x04, 0x41, 0x75, 0x74, 0x68, 0x12, 0x12, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+ 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x37, 0x5a, 0x35, 0x67, 0x6f, 0x2e, 0x77, 0x6f, 0x6f,
+ 0x64, 0x70, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x2d, 0x63, 0x69, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x77,
+ 0x6f, 0x6f, 0x64, 0x70, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x69, 0x70,
+ 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
+ 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -1240,61 +1311,62 @@ func file_woodpecker_proto_rawDescGZIP() []byte {
return file_woodpecker_proto_rawDescData
}
-var file_woodpecker_proto_msgTypes = make([]protoimpl.MessageInfo, 20)
+var file_woodpecker_proto_msgTypes = make([]protoimpl.MessageInfo, 21)
var file_woodpecker_proto_goTypes = []interface{}{
- (*State)(nil), // 0: proto.State
- (*LogEntry)(nil), // 1: proto.LogEntry
- (*Filter)(nil), // 2: proto.Filter
- (*Workflow)(nil), // 3: proto.Workflow
- (*NextRequest)(nil), // 4: proto.NextRequest
- (*InitRequest)(nil), // 5: proto.InitRequest
- (*WaitRequest)(nil), // 6: proto.WaitRequest
- (*DoneRequest)(nil), // 7: proto.DoneRequest
- (*ExtendRequest)(nil), // 8: proto.ExtendRequest
- (*UpdateRequest)(nil), // 9: proto.UpdateRequest
- (*LogRequest)(nil), // 10: proto.LogRequest
- (*Empty)(nil), // 11: proto.Empty
- (*ReportHealthRequest)(nil), // 12: proto.ReportHealthRequest
- (*RegisterAgentRequest)(nil), // 13: proto.RegisterAgentRequest
- (*VersionResponse)(nil), // 14: proto.VersionResponse
- (*NextResponse)(nil), // 15: proto.NextResponse
- (*RegisterAgentResponse)(nil), // 16: proto.RegisterAgentResponse
- (*AuthRequest)(nil), // 17: proto.AuthRequest
- (*AuthResponse)(nil), // 18: proto.AuthResponse
- nil, // 19: proto.Filter.LabelsEntry
+ (*StepState)(nil), // 0: proto.StepState
+ (*WorkflowState)(nil), // 1: proto.WorkflowState
+ (*LogEntry)(nil), // 2: proto.LogEntry
+ (*Filter)(nil), // 3: proto.Filter
+ (*Workflow)(nil), // 4: proto.Workflow
+ (*NextRequest)(nil), // 5: proto.NextRequest
+ (*InitRequest)(nil), // 6: proto.InitRequest
+ (*WaitRequest)(nil), // 7: proto.WaitRequest
+ (*DoneRequest)(nil), // 8: proto.DoneRequest
+ (*ExtendRequest)(nil), // 9: proto.ExtendRequest
+ (*UpdateRequest)(nil), // 10: proto.UpdateRequest
+ (*LogRequest)(nil), // 11: proto.LogRequest
+ (*Empty)(nil), // 12: proto.Empty
+ (*ReportHealthRequest)(nil), // 13: proto.ReportHealthRequest
+ (*RegisterAgentRequest)(nil), // 14: proto.RegisterAgentRequest
+ (*VersionResponse)(nil), // 15: proto.VersionResponse
+ (*NextResponse)(nil), // 16: proto.NextResponse
+ (*RegisterAgentResponse)(nil), // 17: proto.RegisterAgentResponse
+ (*AuthRequest)(nil), // 18: proto.AuthRequest
+ (*AuthResponse)(nil), // 19: proto.AuthResponse
+ nil, // 20: proto.Filter.LabelsEntry
}
var file_woodpecker_proto_depIdxs = []int32{
- 19, // 0: proto.Filter.labels:type_name -> proto.Filter.LabelsEntry
- 2, // 1: proto.NextRequest.filter:type_name -> proto.Filter
- 0, // 2: proto.InitRequest.state:type_name -> proto.State
- 0, // 3: proto.DoneRequest.state:type_name -> proto.State
- 0, // 4: proto.UpdateRequest.state:type_name -> proto.State
- 1, // 5: proto.LogRequest.logEntry:type_name -> proto.LogEntry
- 3, // 6: proto.NextResponse.workflow:type_name -> proto.Workflow
- 11, // 7: proto.Woodpecker.Version:input_type -> proto.Empty
- 4, // 8: proto.Woodpecker.Next:input_type -> proto.NextRequest
- 5, // 9: proto.Woodpecker.Init:input_type -> proto.InitRequest
- 6, // 10: proto.Woodpecker.Wait:input_type -> proto.WaitRequest
- 7, // 11: proto.Woodpecker.Done:input_type -> proto.DoneRequest
- 8, // 12: proto.Woodpecker.Extend:input_type -> proto.ExtendRequest
- 9, // 13: proto.Woodpecker.Update:input_type -> proto.UpdateRequest
- 10, // 14: proto.Woodpecker.Log:input_type -> proto.LogRequest
- 13, // 15: proto.Woodpecker.RegisterAgent:input_type -> proto.RegisterAgentRequest
- 11, // 16: proto.Woodpecker.UnregisterAgent:input_type -> proto.Empty
- 12, // 17: proto.Woodpecker.ReportHealth:input_type -> proto.ReportHealthRequest
- 17, // 18: proto.WoodpeckerAuth.Auth:input_type -> proto.AuthRequest
- 14, // 19: proto.Woodpecker.Version:output_type -> proto.VersionResponse
- 15, // 20: proto.Woodpecker.Next:output_type -> proto.NextResponse
- 11, // 21: proto.Woodpecker.Init:output_type -> proto.Empty
- 11, // 22: proto.Woodpecker.Wait:output_type -> proto.Empty
- 11, // 23: proto.Woodpecker.Done:output_type -> proto.Empty
- 11, // 24: proto.Woodpecker.Extend:output_type -> proto.Empty
- 11, // 25: proto.Woodpecker.Update:output_type -> proto.Empty
- 11, // 26: proto.Woodpecker.Log:output_type -> proto.Empty
- 16, // 27: proto.Woodpecker.RegisterAgent:output_type -> proto.RegisterAgentResponse
- 11, // 28: proto.Woodpecker.UnregisterAgent:output_type -> proto.Empty
- 11, // 29: proto.Woodpecker.ReportHealth:output_type -> proto.Empty
- 18, // 30: proto.WoodpeckerAuth.Auth:output_type -> proto.AuthResponse
+ 20, // 0: proto.Filter.labels:type_name -> proto.Filter.LabelsEntry
+ 3, // 1: proto.NextRequest.filter:type_name -> proto.Filter
+ 1, // 2: proto.InitRequest.state:type_name -> proto.WorkflowState
+ 1, // 3: proto.DoneRequest.state:type_name -> proto.WorkflowState
+ 0, // 4: proto.UpdateRequest.state:type_name -> proto.StepState
+ 2, // 5: proto.LogRequest.logEntries:type_name -> proto.LogEntry
+ 4, // 6: proto.NextResponse.workflow:type_name -> proto.Workflow
+ 12, // 7: proto.Woodpecker.Version:input_type -> proto.Empty
+ 5, // 8: proto.Woodpecker.Next:input_type -> proto.NextRequest
+ 6, // 9: proto.Woodpecker.Init:input_type -> proto.InitRequest
+ 7, // 10: proto.Woodpecker.Wait:input_type -> proto.WaitRequest
+ 8, // 11: proto.Woodpecker.Done:input_type -> proto.DoneRequest
+ 9, // 12: proto.Woodpecker.Extend:input_type -> proto.ExtendRequest
+ 10, // 13: proto.Woodpecker.Update:input_type -> proto.UpdateRequest
+ 11, // 14: proto.Woodpecker.Log:input_type -> proto.LogRequest
+ 14, // 15: proto.Woodpecker.RegisterAgent:input_type -> proto.RegisterAgentRequest
+ 12, // 16: proto.Woodpecker.UnregisterAgent:input_type -> proto.Empty
+ 13, // 17: proto.Woodpecker.ReportHealth:input_type -> proto.ReportHealthRequest
+ 18, // 18: proto.WoodpeckerAuth.Auth:input_type -> proto.AuthRequest
+ 15, // 19: proto.Woodpecker.Version:output_type -> proto.VersionResponse
+ 16, // 20: proto.Woodpecker.Next:output_type -> proto.NextResponse
+ 12, // 21: proto.Woodpecker.Init:output_type -> proto.Empty
+ 12, // 22: proto.Woodpecker.Wait:output_type -> proto.Empty
+ 12, // 23: proto.Woodpecker.Done:output_type -> proto.Empty
+ 12, // 24: proto.Woodpecker.Extend:output_type -> proto.Empty
+ 12, // 25: proto.Woodpecker.Update:output_type -> proto.Empty
+ 12, // 26: proto.Woodpecker.Log:output_type -> proto.Empty
+ 17, // 27: proto.Woodpecker.RegisterAgent:output_type -> proto.RegisterAgentResponse
+ 12, // 28: proto.Woodpecker.UnregisterAgent:output_type -> proto.Empty
+ 12, // 29: proto.Woodpecker.ReportHealth:output_type -> proto.Empty
+ 19, // 30: proto.WoodpeckerAuth.Auth:output_type -> proto.AuthResponse
19, // [19:31] is the sub-list for method output_type
7, // [7:19] is the sub-list for method input_type
7, // [7:7] is the sub-list for extension type_name
@@ -1309,7 +1381,7 @@ func file_woodpecker_proto_init() {
}
if !protoimpl.UnsafeEnabled {
file_woodpecker_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*State); i {
+ switch v := v.(*StepState); i {
case 0:
return &v.state
case 1:
@@ -1321,7 +1393,7 @@ func file_woodpecker_proto_init() {
}
}
file_woodpecker_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*LogEntry); i {
+ switch v := v.(*WorkflowState); i {
case 0:
return &v.state
case 1:
@@ -1333,7 +1405,7 @@ func file_woodpecker_proto_init() {
}
}
file_woodpecker_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*Filter); i {
+ switch v := v.(*LogEntry); i {
case 0:
return &v.state
case 1:
@@ -1345,7 +1417,7 @@ func file_woodpecker_proto_init() {
}
}
file_woodpecker_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*Workflow); i {
+ switch v := v.(*Filter); i {
case 0:
return &v.state
case 1:
@@ -1357,7 +1429,7 @@ func file_woodpecker_proto_init() {
}
}
file_woodpecker_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*NextRequest); i {
+ switch v := v.(*Workflow); i {
case 0:
return &v.state
case 1:
@@ -1369,7 +1441,7 @@ func file_woodpecker_proto_init() {
}
}
file_woodpecker_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*InitRequest); i {
+ switch v := v.(*NextRequest); i {
case 0:
return &v.state
case 1:
@@ -1381,7 +1453,7 @@ func file_woodpecker_proto_init() {
}
}
file_woodpecker_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*WaitRequest); i {
+ switch v := v.(*InitRequest); i {
case 0:
return &v.state
case 1:
@@ -1393,7 +1465,7 @@ func file_woodpecker_proto_init() {
}
}
file_woodpecker_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*DoneRequest); i {
+ switch v := v.(*WaitRequest); i {
case 0:
return &v.state
case 1:
@@ -1405,7 +1477,7 @@ func file_woodpecker_proto_init() {
}
}
file_woodpecker_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*ExtendRequest); i {
+ switch v := v.(*DoneRequest); i {
case 0:
return &v.state
case 1:
@@ -1417,7 +1489,7 @@ func file_woodpecker_proto_init() {
}
}
file_woodpecker_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*UpdateRequest); i {
+ switch v := v.(*ExtendRequest); i {
case 0:
return &v.state
case 1:
@@ -1429,7 +1501,7 @@ func file_woodpecker_proto_init() {
}
}
file_woodpecker_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*LogRequest); i {
+ switch v := v.(*UpdateRequest); i {
case 0:
return &v.state
case 1:
@@ -1441,7 +1513,7 @@ func file_woodpecker_proto_init() {
}
}
file_woodpecker_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*Empty); i {
+ switch v := v.(*LogRequest); i {
case 0:
return &v.state
case 1:
@@ -1453,7 +1525,7 @@ func file_woodpecker_proto_init() {
}
}
file_woodpecker_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*ReportHealthRequest); i {
+ switch v := v.(*Empty); i {
case 0:
return &v.state
case 1:
@@ -1465,7 +1537,7 @@ func file_woodpecker_proto_init() {
}
}
file_woodpecker_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*RegisterAgentRequest); i {
+ switch v := v.(*ReportHealthRequest); i {
case 0:
return &v.state
case 1:
@@ -1477,7 +1549,7 @@ func file_woodpecker_proto_init() {
}
}
file_woodpecker_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*VersionResponse); i {
+ switch v := v.(*RegisterAgentRequest); i {
case 0:
return &v.state
case 1:
@@ -1489,7 +1561,7 @@ func file_woodpecker_proto_init() {
}
}
file_woodpecker_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*NextResponse); i {
+ switch v := v.(*VersionResponse); i {
case 0:
return &v.state
case 1:
@@ -1501,7 +1573,7 @@ func file_woodpecker_proto_init() {
}
}
file_woodpecker_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*RegisterAgentResponse); i {
+ switch v := v.(*NextResponse); i {
case 0:
return &v.state
case 1:
@@ -1513,7 +1585,7 @@ func file_woodpecker_proto_init() {
}
}
file_woodpecker_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*AuthRequest); i {
+ switch v := v.(*RegisterAgentResponse); i {
case 0:
return &v.state
case 1:
@@ -1525,6 +1597,18 @@ func file_woodpecker_proto_init() {
}
}
file_woodpecker_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*AuthRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_woodpecker_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AuthResponse); i {
case 0:
return &v.state
@@ -1543,7 +1627,7 @@ func file_woodpecker_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_woodpecker_proto_rawDesc,
NumEnums: 0,
- NumMessages: 20,
+ NumMessages: 21,
NumExtensions: 0,
NumServices: 2,
},
diff --git a/pipeline/rpc/proto/woodpecker.proto b/pipeline/rpc/proto/woodpecker.proto
index 4d752c243..ea6c987b9 100644
--- a/pipeline/rpc/proto/woodpecker.proto
+++ b/pipeline/rpc/proto/woodpecker.proto
@@ -41,10 +41,16 @@ service Woodpecker {
// Basic Types
//
-message State {
+message StepState {
string step_uuid = 1;
- bool exited = 2;
- int32 exit_code = 3;
+ int64 started = 2;
+ int64 finished = 3;
+ bool exited = 4;
+ int32 exit_code = 5;
+ string error = 6;
+}
+
+message WorkflowState {
int64 started = 4;
int64 finished = 5;
string error = 6;
@@ -78,7 +84,7 @@ message NextRequest {
message InitRequest {
string id = 1;
- State state = 2;
+ WorkflowState state = 2;
}
message WaitRequest {
@@ -87,7 +93,7 @@ message WaitRequest {
message DoneRequest {
string id = 1;
- State state = 2;
+ WorkflowState state = 2;
}
message ExtendRequest {
@@ -96,11 +102,11 @@ message ExtendRequest {
message UpdateRequest {
string id = 1;
- State state = 2;
+ StepState state = 2;
}
message LogRequest {
- LogEntry logEntry = 1;
+ repeated LogEntry logEntries = 1;
}
message Empty {
diff --git a/pipeline/rpc/proto/woodpecker_grpc.pb.go b/pipeline/rpc/proto/woodpecker_grpc.pb.go
index 837ce74e0..64437aeb1 100644
--- a/pipeline/rpc/proto/woodpecker_grpc.pb.go
+++ b/pipeline/rpc/proto/woodpecker_grpc.pb.go
@@ -15,8 +15,8 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
-// - protoc-gen-go-grpc v1.3.0
-// - protoc v4.25.1
+// - protoc-gen-go-grpc v1.4.0
+// - protoc v4.25.4
// source: woodpecker.proto
package proto
@@ -30,8 +30,8 @@ import (
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
-// Requires gRPC-Go v1.32.0 or later.
-const _ = grpc.SupportPackageIsVersion7
+// Requires gRPC-Go v1.62.0 or later.
+const _ = grpc.SupportPackageIsVersion8
const (
Woodpecker_Version_FullMethodName = "/proto.Woodpecker/Version"
@@ -50,6 +50,8 @@ const (
// WoodpeckerClient is the client API for Woodpecker service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+//
+// Woodpecker Server Service
type WoodpeckerClient interface {
Version(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*VersionResponse, error)
Next(ctx context.Context, in *NextRequest, opts ...grpc.CallOption) (*NextResponse, error)
@@ -73,8 +75,9 @@ func NewWoodpeckerClient(cc grpc.ClientConnInterface) WoodpeckerClient {
}
func (c *woodpeckerClient) Version(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*VersionResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(VersionResponse)
- err := c.cc.Invoke(ctx, Woodpecker_Version_FullMethodName, in, out, opts...)
+ err := c.cc.Invoke(ctx, Woodpecker_Version_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@@ -82,8 +85,9 @@ func (c *woodpeckerClient) Version(ctx context.Context, in *Empty, opts ...grpc.
}
func (c *woodpeckerClient) Next(ctx context.Context, in *NextRequest, opts ...grpc.CallOption) (*NextResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(NextResponse)
- err := c.cc.Invoke(ctx, Woodpecker_Next_FullMethodName, in, out, opts...)
+ err := c.cc.Invoke(ctx, Woodpecker_Next_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@@ -91,8 +95,9 @@ func (c *woodpeckerClient) Next(ctx context.Context, in *NextRequest, opts ...gr
}
func (c *woodpeckerClient) Init(ctx context.Context, in *InitRequest, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Empty)
- err := c.cc.Invoke(ctx, Woodpecker_Init_FullMethodName, in, out, opts...)
+ err := c.cc.Invoke(ctx, Woodpecker_Init_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@@ -100,8 +105,9 @@ func (c *woodpeckerClient) Init(ctx context.Context, in *InitRequest, opts ...gr
}
func (c *woodpeckerClient) Wait(ctx context.Context, in *WaitRequest, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Empty)
- err := c.cc.Invoke(ctx, Woodpecker_Wait_FullMethodName, in, out, opts...)
+ err := c.cc.Invoke(ctx, Woodpecker_Wait_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@@ -109,8 +115,9 @@ func (c *woodpeckerClient) Wait(ctx context.Context, in *WaitRequest, opts ...gr
}
func (c *woodpeckerClient) Done(ctx context.Context, in *DoneRequest, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Empty)
- err := c.cc.Invoke(ctx, Woodpecker_Done_FullMethodName, in, out, opts...)
+ err := c.cc.Invoke(ctx, Woodpecker_Done_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@@ -118,8 +125,9 @@ func (c *woodpeckerClient) Done(ctx context.Context, in *DoneRequest, opts ...gr
}
func (c *woodpeckerClient) Extend(ctx context.Context, in *ExtendRequest, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Empty)
- err := c.cc.Invoke(ctx, Woodpecker_Extend_FullMethodName, in, out, opts...)
+ err := c.cc.Invoke(ctx, Woodpecker_Extend_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@@ -127,8 +135,9 @@ func (c *woodpeckerClient) Extend(ctx context.Context, in *ExtendRequest, opts .
}
func (c *woodpeckerClient) Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Empty)
- err := c.cc.Invoke(ctx, Woodpecker_Update_FullMethodName, in, out, opts...)
+ err := c.cc.Invoke(ctx, Woodpecker_Update_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@@ -136,8 +145,9 @@ func (c *woodpeckerClient) Update(ctx context.Context, in *UpdateRequest, opts .
}
func (c *woodpeckerClient) Log(ctx context.Context, in *LogRequest, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Empty)
- err := c.cc.Invoke(ctx, Woodpecker_Log_FullMethodName, in, out, opts...)
+ err := c.cc.Invoke(ctx, Woodpecker_Log_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@@ -145,8 +155,9 @@ func (c *woodpeckerClient) Log(ctx context.Context, in *LogRequest, opts ...grpc
}
func (c *woodpeckerClient) RegisterAgent(ctx context.Context, in *RegisterAgentRequest, opts ...grpc.CallOption) (*RegisterAgentResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(RegisterAgentResponse)
- err := c.cc.Invoke(ctx, Woodpecker_RegisterAgent_FullMethodName, in, out, opts...)
+ err := c.cc.Invoke(ctx, Woodpecker_RegisterAgent_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@@ -154,8 +165,9 @@ func (c *woodpeckerClient) RegisterAgent(ctx context.Context, in *RegisterAgentR
}
func (c *woodpeckerClient) UnregisterAgent(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Empty)
- err := c.cc.Invoke(ctx, Woodpecker_UnregisterAgent_FullMethodName, in, out, opts...)
+ err := c.cc.Invoke(ctx, Woodpecker_UnregisterAgent_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@@ -163,8 +175,9 @@ func (c *woodpeckerClient) UnregisterAgent(ctx context.Context, in *Empty, opts
}
func (c *woodpeckerClient) ReportHealth(ctx context.Context, in *ReportHealthRequest, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Empty)
- err := c.cc.Invoke(ctx, Woodpecker_ReportHealth_FullMethodName, in, out, opts...)
+ err := c.cc.Invoke(ctx, Woodpecker_ReportHealth_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@@ -174,6 +187,8 @@ func (c *woodpeckerClient) ReportHealth(ctx context.Context, in *ReportHealthReq
// WoodpeckerServer is the server API for Woodpecker service.
// All implementations must embed UnimplementedWoodpeckerServer
// for forward compatibility
+//
+// Woodpecker Server Service
type WoodpeckerServer interface {
Version(context.Context, *Empty) (*VersionResponse, error)
Next(context.Context, *NextRequest) (*NextResponse, error)
@@ -513,8 +528,9 @@ func NewWoodpeckerAuthClient(cc grpc.ClientConnInterface) WoodpeckerAuthClient {
}
func (c *woodpeckerAuthClient) Auth(ctx context.Context, in *AuthRequest, opts ...grpc.CallOption) (*AuthResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(AuthResponse)
- err := c.cc.Invoke(ctx, WoodpeckerAuth_Auth_FullMethodName, in, out, opts...)
+ err := c.cc.Invoke(ctx, WoodpeckerAuth_Auth_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
diff --git a/pipeline/shutdown.go b/pipeline/shutdown.go
new file mode 100644
index 000000000..b9fd98384
--- /dev/null
+++ b/pipeline/shutdown.go
@@ -0,0 +1,48 @@
+// 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 pipeline
+
+import (
+ "context"
+ "sync"
+ "time"
+)
+
+const shutdownTimeout = time.Second * 5
+
+var (
+ shutdownCtx context.Context
+ shutdownCtxCancel context.CancelFunc
+ shutdownCtxLock sync.Mutex
+)
+
+func GetShutdownCtx() context.Context {
+ shutdownCtxLock.Lock()
+ defer shutdownCtxLock.Unlock()
+ if shutdownCtx == nil {
+ shutdownCtx, shutdownCtxCancel = context.WithTimeout(context.Background(), shutdownTimeout)
+ }
+ return shutdownCtx
+}
+
+func CancelShutdown() {
+ shutdownCtxLock.Lock()
+ defer shutdownCtxLock.Unlock()
+ if shutdownCtxCancel == nil {
+ // we create an canceled context
+ shutdownCtx, shutdownCtxCancel = context.WithCancel(context.Background()) //nolint:forbidigo
+ }
+ shutdownCtxCancel()
+}
diff --git a/pipeline/tracer.go b/pipeline/tracer.go
index 88db83586..f48a7c562 100644
--- a/pipeline/tracer.go
+++ b/pipeline/tracer.go
@@ -16,7 +16,6 @@ package pipeline
import (
"strconv"
- "time"
)
// Tracer handles process tracing.
@@ -43,17 +42,9 @@ var DefaultTracer = TraceFunc(func(state *State) error {
if state.Pipeline.Step.Environment == nil {
return nil
}
- state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "success"
- state.Pipeline.Step.Environment["CI_PIPELINE_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10)
- state.Pipeline.Step.Environment["CI_PIPELINE_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
+ state.Pipeline.Step.Environment["CI_PIPELINE_STARTED"] = strconv.FormatInt(state.Pipeline.Started, 10)
- state.Pipeline.Step.Environment["CI_STEP_STATUS"] = "success"
- state.Pipeline.Step.Environment["CI_STEP_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10)
- state.Pipeline.Step.Environment["CI_STEP_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
+ state.Pipeline.Step.Environment["CI_STEP_STARTED"] = strconv.FormatInt(state.Pipeline.Started, 10)
- if state.Pipeline.Error != nil {
- state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "failure"
- state.Pipeline.Step.Environment["CI_STEP_STATUS"] = "failure"
- }
return nil
})
diff --git a/server/api/global_registry.go b/server/api/global_registry.go
new file mode 100644
index 000000000..a9ffd9a89
--- /dev/null
+++ b/server/api/global_registry.go
@@ -0,0 +1,170 @@
+// 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 api
+
+import (
+ "net/http"
+
+ "github.com/gin-gonic/gin"
+
+ "go.woodpecker-ci.org/woodpecker/v2/server"
+ "go.woodpecker-ci.org/woodpecker/v2/server/model"
+ "go.woodpecker-ci.org/woodpecker/v2/server/router/middleware/session"
+)
+
+// GetGlobalRegistryList
+//
+// @Summary List global registries
+// @Router /registries [get]
+// @Produce json
+// @Success 200 {array} Registry
+// @Tags Registries
+// @Param Authorization header string true "Insert your personal access token" default(Bearer )
+// @Param page query int false "for response pagination, page offset number" default(1)
+// @Param perPage query int false "for response pagination, max items per page" default(50)
+func GetGlobalRegistryList(c *gin.Context) {
+ registryService := server.Config.Services.Manager.RegistryService()
+ list, err := registryService.GlobalRegistryList(session.Pagination(c))
+ if err != nil {
+ c.String(http.StatusInternalServerError, "Error getting global registry list. %s", err)
+ return
+ }
+ // copy the registry detail to remove the sensitive
+ // password and token fields.
+ for i, registry := range list {
+ list[i] = registry.Copy()
+ }
+ c.JSON(http.StatusOK, list)
+}
+
+// GetGlobalRegistry
+//
+// @Summary Get a global registry by name
+// @Router /registries/{registry} [get]
+// @Produce json
+// @Success 200 {object} Registry
+// @Tags Registries
+// @Param Authorization header string true "Insert your personal access token" default(Bearer )
+// @Param registry path string true "the registry's name"
+func GetGlobalRegistry(c *gin.Context) {
+ addr := c.Param("registry")
+ registryService := server.Config.Services.Manager.RegistryService()
+ registry, err := registryService.GlobalRegistryFind(addr)
+ if err != nil {
+ handleDBError(c, err)
+ return
+ }
+ c.JSON(http.StatusOK, registry.Copy())
+}
+
+// PostGlobalRegistry
+//
+// @Summary Create a global registry
+// @Router /registries [post]
+// @Produce json
+// @Success 200 {object} Registry
+// @Tags Registries
+// @Param Authorization header string true "Insert your personal access token" default(Bearer )
+// @Param registry body Registry true "the registry object data"
+func PostGlobalRegistry(c *gin.Context) {
+ in := new(model.Registry)
+ if err := c.Bind(in); err != nil {
+ c.String(http.StatusBadRequest, "Error parsing global registry. %s", err)
+ return
+ }
+ registry := &model.Registry{
+ Address: in.Address,
+ Username: in.Username,
+ Password: in.Password,
+ }
+ if err := registry.Validate(); err != nil {
+ c.String(http.StatusBadRequest, "Error inserting global registry. %s", err)
+ return
+ }
+
+ registryService := server.Config.Services.Manager.RegistryService()
+ if err := registryService.GlobalRegistryCreate(registry); err != nil {
+ c.String(http.StatusInternalServerError, "Error inserting global registry %q. %s", in.Address, err)
+ return
+ }
+ c.JSON(http.StatusOK, registry.Copy())
+}
+
+// PatchGlobalRegistry
+//
+// @Summary Update a global registry by name
+// @Router /registries/{registry} [patch]
+// @Produce json
+// @Success 200 {object} Registry
+// @Tags Registries
+// @Param Authorization header string true "Insert your personal access token" default(Bearer )
+// @Param registry path string true "the registry's name"
+// @Param registryData body Registry true "the registry's data"
+func PatchGlobalRegistry(c *gin.Context) {
+ addr := c.Param("registry")
+
+ in := new(model.Registry)
+ err := c.Bind(in)
+ if err != nil {
+ c.String(http.StatusBadRequest, "Error parsing registry. %s", err)
+ return
+ }
+
+ registryService := server.Config.Services.Manager.RegistryService()
+ registry, err := registryService.GlobalRegistryFind(addr)
+ if err != nil {
+ handleDBError(c, err)
+ return
+ }
+ if in.Address != "" {
+ registry.Address = in.Address
+ }
+ if in.Username != "" {
+ registry.Username = in.Username
+ }
+ if in.Password != "" {
+ registry.Password = in.Password
+ }
+
+ if err := registry.Validate(); err != nil {
+ c.String(http.StatusBadRequest, "Error updating global registry. %s", err)
+ return
+ }
+
+ if err := registryService.GlobalRegistryUpdate(registry); err != nil {
+ c.String(http.StatusInternalServerError, "Error updating global registry %q. %s", in.Address, err)
+ return
+ }
+ c.JSON(http.StatusOK, registry.Copy())
+}
+
+// DeleteGlobalRegistry
+//
+// @Summary Delete a global registry by name
+// @Router /registries/{registry} [delete]
+// @Produce plain
+// @Success 204
+// @Tags Registries
+// @Param Authorization header string true "Insert your personal access token" default(Bearer )
+// @Param registry path string true "the registry's name"
+func DeleteGlobalRegistry(c *gin.Context) {
+ addr := c.Param("registry")
+ registryService := server.Config.Services.Manager.RegistryService()
+ if err := registryService.GlobalRegistryDelete(addr); err != nil {
+ handleDBError(c, err)
+ return
+ }
+ c.Status(http.StatusNoContent)
+}
diff --git a/server/api/hook.go b/server/api/hook.go
index 40a93ef35..713fca39b 100644
--- a/server/api/hook.go
+++ b/server/api/hook.go
@@ -104,18 +104,47 @@ func BlockTilQueueHasRunningItem(c *gin.Context) {
func PostHook(c *gin.Context) {
_store := store.FromContext(c)
- _forge, err := server.Config.Services.Manager.ForgeMain() // TODO: get the forge for the specific repo somehow
+ //
+ // 1. Check if the webhook is valid and authorized
+ //
+
+ var repo *model.Repo
+
+ _, err := token.ParseRequest([]token.Type{token.HookToken}, c.Request, func(t *token.Token) (string, error) {
+ var err error
+ repo, err = getRepoFromToken(_store, t)
+ if err != nil {
+ return "", err
+ }
+
+ return repo.Hash, nil
+ })
if err != nil {
- log.Error().Err(err).Msg("Cannot get main forge")
+ msg := "failure to parse token from hook"
+ log.Error().Err(err).Msg(msg)
+ c.String(http.StatusBadRequest, msg)
+ return
+ }
+
+ if repo == nil {
+ msg := "failure to get repo from token"
+ log.Error().Msg(msg)
+ c.String(http.StatusBadRequest, msg)
+ return
+ }
+
+ _forge, err := server.Config.Services.Manager.ForgeFromRepo(repo)
+ if err != nil {
+ log.Error().Err(err).Int64("repo-id", repo.ID).Msgf("Cannot get forge with id: %d", repo.ForgeID)
c.AbortWithStatus(http.StatusInternalServerError)
return
}
//
- // 1. Parse webhook
+ // 2. Parse the webhook data
//
- tmpRepo, tmpPipeline, err := _forge.Hook(c, c.Request)
+ repoFromForge, pipelineFromForge, err := _forge.Hook(c, c.Request)
if err != nil {
if errors.Is(err, &types.ErrIgnoreEvent{}) {
msg := fmt.Sprintf("forge driver: %s", err)
@@ -130,13 +159,13 @@ func PostHook(c *gin.Context) {
return
}
- if tmpPipeline == nil {
+ if pipelineFromForge == nil {
msg := "ignoring hook: hook parsing resulted in empty pipeline"
log.Debug().Msg(msg)
c.String(http.StatusOK, msg)
return
}
- if tmpRepo == nil {
+ if repoFromForge == nil {
msg := "failure to ascertain repo from hook"
log.Debug().Msg(msg)
c.String(http.StatusBadRequest, msg)
@@ -144,21 +173,24 @@ func PostHook(c *gin.Context) {
}
//
- // 2. Get related repo from store and take repo renaming into account
+ // 3. Check the repo from the token is matching the repo returned by the forge
//
- repo, err := _store.GetRepoNameFallback(tmpRepo.ForgeRemoteID, tmpRepo.FullName)
- if err != nil {
- log.Error().Err(err).Msgf("failure to get repo %s from store", tmpRepo.FullName)
- handleDBError(c, err)
+ if repo.ForgeRemoteID != repoFromForge.ForgeRemoteID {
+ log.Warn().Msgf("ignoring hook: repo %s does not match the repo from the token", repo.FullName)
+ c.String(http.StatusBadRequest, "failure to parse token from hook")
return
}
+
+ //
+ // 4. Check if the repo is active and has an owner
+ //
+
if !repo.IsActive {
- log.Debug().Msgf("ignoring hook: repo %s is inactive", tmpRepo.FullName)
+ log.Debug().Msgf("ignoring hook: repo %s is inactive", repoFromForge.FullName)
c.Status(http.StatusNoContent)
return
}
- currentRepoFullName := repo.FullName
if repo.UserID == 0 {
log.Warn().Msgf("ignoring hook. repo %s has no owner.", repo.FullName)
@@ -174,44 +206,10 @@ func PostHook(c *gin.Context) {
forge.Refresh(c, _forge, _store, user)
//
- // 3. Check if the webhook is a valid and authorized one
+ // 4. Update the repo
//
- // get the token and verify the hook is authorized
- parsedToken, err := token.ParseRequest(c.Request, func(_ *token.Token) (string, error) {
- return repo.Hash, nil
- })
- if err != nil {
- msg := fmt.Sprintf("failure to parse token from hook for %s", repo.FullName)
- log.Error().Err(err).Msg(msg)
- c.String(http.StatusBadRequest, msg)
- return
- }
-
- // TODO: remove fallback for text full name in next major release
- verifiedKey := parsedToken.Get("repo-id") == strconv.FormatInt(repo.ID, 10) || parsedToken.Get("text") == currentRepoFullName
- if !verifiedKey {
- verifiedKey, err = _store.HasRedirectionForRepo(repo.ID, repo.FullName)
- if err != nil {
- msg := "failure to verify token from hook. Could not check for redirections of the repo"
- log.Error().Err(err).Msg(msg)
- c.String(http.StatusInternalServerError, msg)
- return
- }
- }
-
- if !verifiedKey {
- msg := fmt.Sprintf("failure to verify token from hook. Expected %s, got %s", repo.FullName, parsedToken.Get("text"))
- log.Debug().Msg(msg)
- c.String(http.StatusForbidden, msg)
- return
- }
-
- //
- // 4. Update repo
- //
-
- if currentRepoFullName != tmpRepo.FullName {
+ if repo.FullName != repoFromForge.FullName {
// create a redirection
err = _store.CreateRedirection(&model.Redirection{RepoID: repo.ID, FullName: repo.FullName})
if err != nil {
@@ -220,7 +218,7 @@ func PostHook(c *gin.Context) {
}
}
- repo.Update(tmpRepo)
+ repo.Update(repoFromForge)
err = _store.UpdateRepo(repo)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
@@ -231,7 +229,7 @@ func PostHook(c *gin.Context) {
// 5. Check if pull requests are allowed for this repo
//
- if (tmpPipeline.Event == model.EventPull || tmpPipeline.Event == model.EventPullClosed) && !repo.AllowPull {
+ if (pipelineFromForge.Event == model.EventPull || pipelineFromForge.Event == model.EventPullClosed) && !repo.AllowPull {
log.Debug().Str("repo", repo.FullName).Msg("ignoring hook: pull requests are disabled for this repo in woodpecker")
c.Status(http.StatusNoContent)
return
@@ -241,10 +239,19 @@ func PostHook(c *gin.Context) {
// 6. Finally create a pipeline
//
- pl, err := pipeline.Create(c, _store, repo, tmpPipeline)
+ pl, err := pipeline.Create(c, _store, repo, pipelineFromForge)
if err != nil {
handlePipelineErr(c, err)
} else {
c.JSON(http.StatusOK, pl)
}
}
+
+func getRepoFromToken(store store.Store, t *token.Token) (*model.Repo, error) {
+ // try to get the repo by the repo-id
+ repoID, err := strconv.ParseInt(t.Get("repo-id"), 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ return store.GetRepo(repoID)
+}
diff --git a/server/api/hook_test.go b/server/api/hook_test.go
new file mode 100644
index 000000000..681edf0c8
--- /dev/null
+++ b/server/api/hook_test.go
@@ -0,0 +1,104 @@
+package api_test
+
+import (
+ "fmt"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "testing"
+
+ "github.com/franela/goblin"
+ "github.com/gin-gonic/gin"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+
+ "go.woodpecker-ci.org/woodpecker/v2/server"
+ "go.woodpecker-ci.org/woodpecker/v2/server/api"
+ mocks_forge "go.woodpecker-ci.org/woodpecker/v2/server/forge/mocks"
+ "go.woodpecker-ci.org/woodpecker/v2/server/model"
+ mocks_config_service "go.woodpecker-ci.org/woodpecker/v2/server/services/config/mocks"
+ mocks_services "go.woodpecker-ci.org/woodpecker/v2/server/services/mocks"
+ "go.woodpecker-ci.org/woodpecker/v2/server/services/permissions"
+ mocks_registry_service "go.woodpecker-ci.org/woodpecker/v2/server/services/registry/mocks"
+ mocks_secret_service "go.woodpecker-ci.org/woodpecker/v2/server/services/secret/mocks"
+ mocks_store "go.woodpecker-ci.org/woodpecker/v2/server/store/mocks"
+ "go.woodpecker-ci.org/woodpecker/v2/shared/token"
+)
+
+func TestHook(t *testing.T) {
+ gin.SetMode(gin.TestMode)
+
+ g := goblin.Goblin(t)
+ g.Describe("Hook", func() {
+ g.It("should handle a correct webhook payload", func() {
+ _manager := mocks_services.NewManager(t)
+ _forge := mocks_forge.NewForge(t)
+ _store := mocks_store.NewStore(t)
+ _configService := mocks_config_service.NewService(t)
+ _secretService := mocks_secret_service.NewService(t)
+ _registryService := mocks_registry_service.NewService(t)
+ server.Config.Services.Manager = _manager
+ server.Config.Permissions.Open = true
+ server.Config.Permissions.Orgs = permissions.NewOrgs(nil)
+ server.Config.Permissions.Admins = permissions.NewAdmins(nil)
+ w := httptest.NewRecorder()
+ c, _ := gin.CreateTestContext(w)
+ c.Set("store", _store)
+ user := &model.User{
+ ID: 123,
+ }
+ repo := &model.Repo{
+ ID: 123,
+ ForgeRemoteID: "123",
+ Owner: "owner",
+ Name: "name",
+ IsActive: true,
+ UserID: user.ID,
+ Hash: "secret-123-this-is-a-secret",
+ }
+ pipeline := &model.Pipeline{
+ ID: 123,
+ RepoID: repo.ID,
+ Event: model.EventPush,
+ }
+
+ repoToken := token.New(token.HookToken)
+ repoToken.Set("repo-id", fmt.Sprintf("%d", repo.ID))
+ signedToken, err := repoToken.Sign("secret-123-this-is-a-secret")
+ if err != nil {
+ g.Fail(err)
+ }
+
+ header := http.Header{}
+ header.Set("Authorization", fmt.Sprintf("Bearer %s", signedToken))
+ c.Request = &http.Request{
+ Header: header,
+ URL: &url.URL{
+ Scheme: "https",
+ },
+ }
+
+ _manager.On("ForgeFromRepo", repo).Return(_forge, nil)
+ _forge.On("Hook", mock.Anything, mock.Anything).Return(repo, pipeline, nil)
+ _store.On("GetRepo", repo.ID).Return(repo, nil)
+ _store.On("GetUser", user.ID).Return(user, nil)
+ _store.On("UpdateRepo", repo).Return(nil)
+ _store.On("CreatePipeline", mock.Anything).Return(nil)
+ _manager.On("ConfigServiceFromRepo", repo).Return(_configService)
+ _configService.On("Fetch", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil)
+ _forge.On("Netrc", mock.Anything, mock.Anything).Return(&model.Netrc{}, nil)
+ _store.On("GetPipelineLastBefore", mock.Anything, mock.Anything, mock.Anything).Return(nil, nil)
+ _manager.On("SecretServiceFromRepo", repo).Return(_secretService)
+ _secretService.On("SecretListPipeline", repo, mock.Anything, mock.Anything).Return(nil, nil)
+ _manager.On("RegistryServiceFromRepo", repo).Return(_registryService)
+ _registryService.On("RegistryListPipeline", repo, mock.Anything).Return(nil, nil)
+ _manager.On("EnvironmentService").Return(nil)
+ _store.On("DeletePipeline", mock.Anything).Return(nil)
+
+ api.PostHook(c)
+
+ assert.Equal(g, http.StatusNoContent, c.Writer.Status())
+ assert.Equal(g, "true", w.Header().Get("Pipeline-Filtered"))
+ })
+ })
+}
diff --git a/server/api/login.go b/server/api/login.go
index 6c936f99b..f7db56905 100644
--- a/server/api/login.go
+++ b/server/api/login.go
@@ -37,6 +37,8 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/shared/token"
)
+const stateTokenDuration = time.Minute * 5
+
func HandleAuth(c *gin.Context) {
// TODO: check if this is really needed
c.Writer.Header().Del("Content-Type")
@@ -56,17 +58,66 @@ func HandleAuth(c *gin.Context) {
}
_store := store.FromContext(c)
- forgeID := int64(1) // TODO: replace with forge id when multiple forges are supported
- _forge, err := server.Config.Services.Manager.ForgeMain()
+
+ code := c.Request.FormValue("code")
+ state := c.Request.FormValue("state")
+ isCallback := code != "" && state != ""
+ var forgeID int64
+
+ if isCallback { // validate the state token
+ stateToken, err := token.Parse([]token.Type{token.OAuthStateToken}, state, func(_ *token.Token) (string, error) {
+ return server.Config.Server.JWTSecret, nil
+ })
+ if err != nil {
+ log.Error().Err(err).Msg("cannot verify state token")
+ c.Redirect(http.StatusSeeOther, server.Config.Server.RootPath+"/login?error=invalid_state")
+ return
+ }
+
+ _forgeID := stateToken.Get("forge-id")
+ forgeID, err = strconv.ParseInt(_forgeID, 10, 64)
+ if err != nil {
+ log.Error().Err(err).Msg("forge-id of state token invalid")
+ c.Redirect(http.StatusSeeOther, server.Config.Server.RootPath+"/login?error=invalid_state")
+ return
+ }
+ } else { // only generate a state token if not a callback
+ var err error
+
+ _forgeID := c.Request.FormValue("forge_id")
+ if _forgeID == "" {
+ forgeID = 1 // fallback to main forge
+ } else {
+ forgeID, err = strconv.ParseInt(_forgeID, 10, 64)
+ if err != nil {
+ log.Error().Err(err).Msg("forge-id of state token invalid")
+ c.Redirect(http.StatusSeeOther, server.Config.Server.RootPath+"/login?error=invalid_state")
+ return
+ }
+ }
+
+ jwtSecret := server.Config.Server.JWTSecret
+ exp := time.Now().Add(stateTokenDuration).Unix()
+ stateToken := token.New(token.OAuthStateToken)
+ stateToken.Set("forge-id", strconv.FormatInt(forgeID, 10))
+ state, err = stateToken.SignExpires(jwtSecret, exp)
+ if err != nil {
+ log.Error().Err(err).Msg("cannot create state token")
+ c.Redirect(http.StatusSeeOther, server.Config.Server.RootPath+"/login?error=internal_error")
+ return
+ }
+ }
+
+ _forge, err := server.Config.Services.Manager.ForgeByID(forgeID)
if err != nil {
- log.Error().Err(err).Msg("Cannot get main forge")
+ log.Error().Err(err).Msgf("Cannot get forge by id %d", forgeID)
c.Redirect(http.StatusSeeOther, server.Config.Server.RootPath+"/login?error=internal_error")
return
}
userFromForge, redirectURL, err := _forge.Login(c, &forge_types.OAuthRequest{
Code: c.Request.FormValue("code"),
- State: "woodpecker", // TODO: use proper state
+ State: state,
})
if err != nil {
log.Error().Err(err).Msg("cannot authenticate user")
@@ -179,6 +230,7 @@ func HandleAuth(c *gin.Context) {
user.RefreshToken = userFromForge.RefreshToken
user.Email = userFromForge.Email
user.Avatar = userFromForge.Avatar
+ user.ForgeID = forgeID
user.ForgeRemoteID = userFromForge.ForgeRemoteID
user.Login = userFromForge.Login
user.Admin = user.Admin || server.Config.Permissions.Admins.IsAdmin(userFromForge)
@@ -246,54 +298,3 @@ func GetLogout(c *gin.Context) {
httputil.DelCookie(c.Writer, c.Request, "user_last")
c.Redirect(http.StatusSeeOther, server.Config.Server.RootPath+"/")
}
-
-// TODO: remove in 3.0
-func DeprecatedGetLoginToken(c *gin.Context) {
- _store := store.FromContext(c)
-
- _forge, err := server.Config.Services.Manager.ForgeMain() // TODO: get selected forge from auth request
- if err != nil {
- log.Error().Err(err).Msg("Cannot get main forge")
- c.AbortWithStatus(http.StatusInternalServerError)
- return
- }
-
- in := &tokenPayload{}
- err = c.Bind(in)
- if err != nil {
- _ = c.AbortWithError(http.StatusBadRequest, err)
- return
- }
-
- login, err := _forge.Auth(c, in.Access, in.Refresh)
- if err != nil {
- _ = c.AbortWithError(http.StatusUnauthorized, err)
- return
- }
-
- user, err := _store.GetUserLogin(login)
- if err != nil {
- handleDBError(c, err)
- return
- }
-
- exp := time.Now().Add(server.Config.Server.SessionExpires).Unix()
- newToken := token.New(token.SessToken)
- newToken.Set("user-id", strconv.FormatInt(user.ID, 10))
- tokenStr, err := newToken.SignExpires(user.Hash, exp)
- if err != nil {
- _ = c.AbortWithError(http.StatusInternalServerError, err)
- return
- }
-
- c.JSON(http.StatusOK, &tokenPayload{
- Access: tokenStr,
- Expires: exp - time.Now().Unix(),
- })
-}
-
-type tokenPayload struct {
- Access string `json:"access_token,omitempty"`
- Refresh string `json:"refresh_token,omitempty"`
- Expires int64 `json:"expires_in,omitempty"`
-}
diff --git a/server/api/login_test.go b/server/api/login_test.go
index 5de274509..f76dd721d 100644
--- a/server/api/login_test.go
+++ b/server/api/login_test.go
@@ -1,6 +1,7 @@
package api_test
import (
+ "context"
"fmt"
"net/http"
"net/http/httptest"
@@ -16,11 +17,13 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/server"
"go.woodpecker-ci.org/woodpecker/v2/server/api"
mocks_forge "go.woodpecker-ci.org/woodpecker/v2/server/forge/mocks"
+ forge_types "go.woodpecker-ci.org/woodpecker/v2/server/forge/types"
"go.woodpecker-ci.org/woodpecker/v2/server/model"
mocks_services "go.woodpecker-ci.org/woodpecker/v2/server/services/mocks"
"go.woodpecker-ci.org/woodpecker/v2/server/services/permissions"
mocks_store "go.woodpecker-ci.org/woodpecker/v2/server/store/mocks"
"go.woodpecker-ci.org/woodpecker/v2/server/store/types"
+ "go.woodpecker-ci.org/woodpecker/v2/shared/token"
)
func TestHandleAuth(t *testing.T) {
@@ -69,12 +72,37 @@ func TestHandleAuth(t *testing.T) {
assert.Equal(g, fmt.Sprintf("/login?%s", query.Encode()), c.Writer.Header().Get("Location"))
})
- g.It("should fail if a code was provided and no state", func() {
- // TODO: implement
- })
-
g.It("should fail if the state is wrong", func() {
- // TODO: implement
+ _manager := mocks_services.NewManager(t)
+ _store := mocks_store.NewStore(t)
+ server.Config.Services.Manager = _manager
+ server.Config.Permissions.Open = true
+ server.Config.Permissions.Orgs = permissions.NewOrgs(nil)
+ server.Config.Permissions.Admins = permissions.NewAdmins(nil)
+ w := httptest.NewRecorder()
+ c, _ := gin.CreateTestContext(w)
+ c.Set("store", _store)
+
+ query := url.Values{}
+ query.Set("code", "assumed_to_be_valid_code")
+
+ wrongToken := token.New(token.OAuthStateToken)
+ wrongToken.Set("forge_id", "1")
+ signedWrongToken, _ := wrongToken.Sign("wrong_secret")
+ query.Set("state", signedWrongToken)
+
+ c.Request = &http.Request{
+ Header: make(http.Header),
+ URL: &url.URL{
+ Scheme: "https",
+ RawQuery: query.Encode(),
+ },
+ }
+
+ api.HandleAuth(c)
+
+ assert.Equal(g, http.StatusSeeOther, c.Writer.Status())
+ assert.Equal(g, "/login?error=invalid_state", c.Writer.Header().Get("Location"))
})
g.It("should redirect to forge login page", func() {
@@ -95,10 +123,17 @@ func TestHandleAuth(t *testing.T) {
},
}
- forgeRedirectURL := "https://my-awesome-forge.com/oauth/authorize?client_id=client-id"
+ _manager.On("ForgeByID", int64(1)).Return(_forge, nil)
- _manager.On("ForgeMain").Return(_forge, nil)
- _forge.On("Login", mock.Anything, mock.Anything).Return(nil, forgeRedirectURL, nil)
+ forgeRedirectURL := ""
+ _forge.On("Login", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
+ state, ok := args.Get(1).(*forge_types.OAuthRequest)
+ if ok {
+ forgeRedirectURL = fmt.Sprintf("https://my-awesome-forge.com/oauth/authorize?client_id=client-id&state=%s", state.State)
+ }
+ }).Return(nil, func(context.Context, *forge_types.OAuthRequest) string {
+ return forgeRedirectURL
+ }, nil)
api.HandleAuth(c)
@@ -124,7 +159,7 @@ func TestHandleAuth(t *testing.T) {
},
}
- _manager.On("ForgeMain").Return(_forge, nil)
+ _manager.On("ForgeByID", int64(1)).Return(_forge, nil)
_forge.On("Login", mock.Anything, mock.Anything).Return(user, "", nil)
_store.On("GetUserRemoteID", user.ForgeRemoteID, user.Login).Return(nil, types.RecordNotExist)
_store.On("CreateUser", mock.Anything).Return(nil)
@@ -158,7 +193,7 @@ func TestHandleAuth(t *testing.T) {
},
}
- _manager.On("ForgeMain").Return(_forge, nil)
+ _manager.On("ForgeByID", int64(1)).Return(_forge, nil)
_forge.On("Login", mock.Anything, mock.Anything).Return(user, "", nil)
_store.On("GetUserRemoteID", user.ForgeRemoteID, user.Login).Return(user, nil)
_store.On("OrgGet", org.ID).Return(org, nil)
@@ -190,7 +225,7 @@ func TestHandleAuth(t *testing.T) {
},
}
- _manager.On("ForgeMain").Return(_forge, nil)
+ _manager.On("ForgeByID", int64(1)).Return(_forge, nil)
_forge.On("Login", mock.Anything, mock.Anything).Return(user, "", nil)
_store.On("GetUserRemoteID", user.ForgeRemoteID, user.Login).Return(nil, types.RecordNotExist)
@@ -218,7 +253,7 @@ func TestHandleAuth(t *testing.T) {
},
}
- _manager.On("ForgeMain").Return(_forge, nil)
+ _manager.On("ForgeByID", int64(1)).Return(_forge, nil)
_forge.On("Login", mock.Anything, mock.Anything).Return(user, "", nil)
_forge.On("Teams", mock.Anything, user).Return([]*model.Team{
{
@@ -252,7 +287,7 @@ func TestHandleAuth(t *testing.T) {
}
user.OrgID = 0
- _manager.On("ForgeMain").Return(_forge, nil)
+ _manager.On("ForgeByID", int64(1)).Return(_forge, nil)
_forge.On("Login", mock.Anything, mock.Anything).Return(user, "", nil)
_store.On("GetUserRemoteID", user.ForgeRemoteID, user.Login).Return(user, nil)
_store.On("OrgFindByName", user.Login).Return(nil, types.RecordNotExist)
@@ -286,7 +321,7 @@ func TestHandleAuth(t *testing.T) {
}
user.OrgID = 0
- _manager.On("ForgeMain").Return(_forge, nil)
+ _manager.On("ForgeByID", int64(1)).Return(_forge, nil)
_forge.On("Login", mock.Anything, mock.Anything).Return(user, "", nil)
_store.On("GetUserRemoteID", user.ForgeRemoteID, user.Login).Return(user, nil)
_store.On("OrgFindByName", user.Login).Return(org, nil)
@@ -320,7 +355,7 @@ func TestHandleAuth(t *testing.T) {
}
org.Name = "not-the-user-name"
- _manager.On("ForgeMain").Return(_forge, nil)
+ _manager.On("ForgeByID", int64(1)).Return(_forge, nil)
_forge.On("Login", mock.Anything, mock.Anything).Return(user, "", nil)
_store.On("GetUserRemoteID", user.ForgeRemoteID, user.Login).Return(user, nil)
_store.On("OrgGet", user.OrgID).Return(org, nil)
diff --git a/server/api/org_registry.go b/server/api/org_registry.go
new file mode 100644
index 000000000..b52782675
--- /dev/null
+++ b/server/api/org_registry.go
@@ -0,0 +1,207 @@
+// 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 api
+
+import (
+ "net/http"
+ "strconv"
+
+ "github.com/gin-gonic/gin"
+
+ "go.woodpecker-ci.org/woodpecker/v2/server"
+ "go.woodpecker-ci.org/woodpecker/v2/server/model"
+ "go.woodpecker-ci.org/woodpecker/v2/server/router/middleware/session"
+)
+
+// GetOrgRegistry
+//
+// @Summary Get a organization registry by address
+// @Router /orgs/{org_id}/registries/{registry} [get]
+// @Produce json
+// @Success 200 {object} Registry
+// @Tags Organization registries
+// @Param Authorization header string true "Insert your personal access token" default(Bearer )
+// @Param org_id path string true "the org's id"
+// @Param registry path string true "the registry's address"
+func GetOrgRegistry(c *gin.Context) {
+ addr := c.Param("registry")
+
+ orgID, err := strconv.ParseInt(c.Param("org_id"), 10, 64)
+ if err != nil {
+ c.String(http.StatusBadRequest, "Error parsing org id. %s", err)
+ return
+ }
+
+ registryService := server.Config.Services.Manager.RegistryService()
+ registry, err := registryService.OrgRegistryFind(orgID, addr)
+ if err != nil {
+ handleDBError(c, err)
+ return
+ }
+ c.JSON(http.StatusOK, registry.Copy())
+}
+
+// GetOrgRegistryList
+//
+// @Summary List organization registries
+// @Router /orgs/{org_id}/registries [get]
+// @Produce json
+// @Success 200 {array} Registry
+// @Tags Organization registries
+// @Param Authorization header string true "Insert your personal access token" default(Bearer )
+// @Param org_id path string true "the org's id"
+// @Param page query int false "for response pagination, page offset number" default(1)
+// @Param perPage query int false "for response pagination, max items per page" default(50)
+func GetOrgRegistryList(c *gin.Context) {
+ orgID, err := strconv.ParseInt(c.Param("org_id"), 10, 64)
+ if err != nil {
+ c.String(http.StatusBadRequest, "Error parsing org id. %s", err)
+ return
+ }
+
+ registryService := server.Config.Services.Manager.RegistryService()
+ list, err := registryService.OrgRegistryList(orgID, session.Pagination(c))
+ if err != nil {
+ c.String(http.StatusInternalServerError, "Error getting registry list for %q. %s", orgID, err)
+ return
+ }
+ // copy the registry detail to remove the sensitive
+ // password and token fields.
+ for i, registry := range list {
+ list[i] = registry.Copy()
+ }
+ c.JSON(http.StatusOK, list)
+}
+
+// PostOrgRegistry
+//
+// @Summary Create an organization registry
+// @Router /orgs/{org_id}/registries [post]
+// @Produce json
+// @Success 200 {object} Registry
+// @Tags Organization registries
+// @Param Authorization header string true "Insert your personal access token" default(Bearer )
+// @Param org_id path string true "the org's id"
+// @Param registryData body Registry true "the new registry"
+func PostOrgRegistry(c *gin.Context) {
+ orgID, err := strconv.ParseInt(c.Param("org_id"), 10, 64)
+ if err != nil {
+ c.String(http.StatusBadRequest, "Error parsing org id. %s", err)
+ return
+ }
+
+ in := new(model.Registry)
+ if err := c.Bind(in); err != nil {
+ c.String(http.StatusBadRequest, "Error parsing org %q registry. %s", orgID, err)
+ return
+ }
+ registry := &model.Registry{
+ OrgID: orgID,
+ Address: in.Address,
+ Username: in.Username,
+ Password: in.Password,
+ }
+ if err := registry.Validate(); err != nil {
+ c.String(http.StatusUnprocessableEntity, "Error inserting org %q registry. %s", orgID, err)
+ return
+ }
+
+ registryService := server.Config.Services.Manager.RegistryService()
+ if err := registryService.OrgRegistryCreate(orgID, registry); err != nil {
+ c.String(http.StatusInternalServerError, "Error inserting org %q registry %q. %s", orgID, in.Address, err)
+ return
+ }
+ c.JSON(http.StatusOK, registry.Copy())
+}
+
+// PatchOrgRegistry
+//
+// @Summary Update an organization registry by name
+// @Router /orgs/{org_id}/registries/{registry} [patch]
+// @Produce json
+// @Success 200 {object} Registry
+// @Tags Organization registries
+// @Param Authorization header string true "Insert your personal access token" default(Bearer )
+// @Param org_id path string true "the org's id"
+// @Param registry path string true "the registry's name"
+// @Param registryData body Registry true "the update registry data"
+func PatchOrgRegistry(c *gin.Context) {
+ addr := c.Param("registry")
+ orgID, err := strconv.ParseInt(c.Param("org_id"), 10, 64)
+ if err != nil {
+ c.String(http.StatusBadRequest, "Error parsing org id. %s", err)
+ return
+ }
+
+ in := new(model.Registry)
+ err = c.Bind(in)
+ if err != nil {
+ c.String(http.StatusBadRequest, "Error parsing registry. %s", err)
+ return
+ }
+
+ registryService := server.Config.Services.Manager.RegistryService()
+ registry, err := registryService.OrgRegistryFind(orgID, addr)
+ if err != nil {
+ handleDBError(c, err)
+ return
+ }
+ if in.Address != "" {
+ registry.Address = in.Address
+ }
+ if in.Username != "" {
+ registry.Username = in.Username
+ }
+ if in.Password != "" {
+ registry.Password = in.Password
+ }
+
+ if err := registry.Validate(); err != nil {
+ c.String(http.StatusUnprocessableEntity, "Error updating org %q registry. %s", orgID, err)
+ return
+ }
+
+ if err := registryService.OrgRegistryUpdate(orgID, registry); err != nil {
+ c.String(http.StatusInternalServerError, "Error updating org %q registry %q. %s", orgID, in.Address, err)
+ return
+ }
+ c.JSON(http.StatusOK, registry.Copy())
+}
+
+// DeleteOrgRegistry
+//
+// @Summary Delete an organization registry by name
+// @Router /orgs/{org_id}/registries/{registry} [delete]
+// @Produce plain
+// @Success 204
+// @Tags Organization registries
+// @Param Authorization header string true "Insert your personal access token" default(Bearer )
+// @Param org_id path string true "the org's id"
+// @Param registry path string true "the registry's name"
+func DeleteOrgRegistry(c *gin.Context) {
+ addr := c.Param("registry")
+ orgID, err := strconv.ParseInt(c.Param("org_id"), 10, 64)
+ if err != nil {
+ c.String(http.StatusBadRequest, "Error parsing org id. %s", err)
+ return
+ }
+
+ registryService := server.Config.Services.Manager.RegistryService()
+ if err := registryService.OrgRegistryDelete(orgID, addr); err != nil {
+ handleDBError(c, err)
+ return
+ }
+ c.Status(http.StatusNoContent)
+}
diff --git a/server/api/pipeline.go b/server/api/pipeline.go
index 2f4509d90..f1e4b41a0 100644
--- a/server/api/pipeline.go
+++ b/server/api/pipeline.go
@@ -64,7 +64,11 @@ func CreatePipeline(c *gin.Context) {
user := session.User(c)
- lastCommit, _ := _forge.BranchHead(c, user, repo, opts.Branch)
+ lastCommit, err := _forge.BranchHead(c, user, repo, opts.Branch)
+ if err != nil {
+ _ = c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("could not fetch branch head: %w", err))
+ return
+ }
tmpPipeline := createTmpPipeline(model.EventManual, lastCommit, user, &opts)
@@ -562,7 +566,7 @@ func PostPipeline(c *gin.Context) {
return
}
- pl.Deploy = c.DefaultQuery("deploy_to", pl.Deploy)
+ pl.DeployTo = c.DefaultQuery("deploy_to", pl.DeployTo)
}
// Read query string parameters into pipelineParams, exclude reserved params
diff --git a/server/api/registry.go b/server/api/registry.go
index c26ea42b7..360db1483 100644
--- a/server/api/registry.go
+++ b/server/api/registry.go
@@ -27,7 +27,7 @@ import (
// GetRegistry
//
// @Summary Get a registry by name
-// @Router /repos/{repo_id}/registry/{registry} [get]
+// @Router /repos/{repo_id}/registries/{registry} [get]
// @Produce json
// @Success 200 {object} Registry
// @Tags Repository registries
@@ -36,10 +36,10 @@ import (
// @Param registry path string true "the registry name"
func GetRegistry(c *gin.Context) {
repo := session.Repo(c)
- name := c.Param("registry")
+ addr := c.Param("registry")
registryService := server.Config.Services.Manager.RegistryServiceFromRepo(repo)
- registry, err := registryService.RegistryFind(repo, name)
+ registry, err := registryService.RegistryFind(repo, addr)
if err != nil {
handleDBError(c, err)
return
@@ -50,7 +50,7 @@ func GetRegistry(c *gin.Context) {
// PostRegistry
//
// @Summary Create a registry
-// @Router /repos/{repo_id}/registry [post]
+// @Router /repos/{repo_id}/registries [post]
// @Produce json
// @Success 200 {object} Registry
// @Tags Repository registries
@@ -87,7 +87,7 @@ func PostRegistry(c *gin.Context) {
// PatchRegistry
//
// @Summary Update a registry by name
-// @Router /repos/{repo_id}/registry/{registry} [patch]
+// @Router /repos/{repo_id}/registries/{registry} [patch]
// @Produce json
// @Success 200 {object} Registry
// @Tags Repository registries
@@ -96,10 +96,8 @@ func PostRegistry(c *gin.Context) {
// @Param registry path string true "the registry name"
// @Param registryData body Registry true "the attributes for the registry"
func PatchRegistry(c *gin.Context) {
- var (
- repo = session.Repo(c)
- name = c.Param("registry")
- )
+ repo := session.Repo(c)
+ addr := c.Param("registry")
in := new(model.Registry)
err := c.Bind(in)
@@ -109,7 +107,7 @@ func PatchRegistry(c *gin.Context) {
}
registryService := server.Config.Services.Manager.RegistryServiceFromRepo(repo)
- registry, err := registryService.RegistryFind(repo, name)
+ registry, err := registryService.RegistryFind(repo, addr)
if err != nil {
handleDBError(c, err)
return
@@ -135,7 +133,7 @@ func PatchRegistry(c *gin.Context) {
// GetRegistryList
//
// @Summary List registries
-// @Router /repos/{repo_id}/registry [get]
+// @Router /repos/{repo_id}/registries [get]
// @Produce json
// @Success 200 {array} Registry
// @Tags Repository registries
@@ -162,7 +160,7 @@ func GetRegistryList(c *gin.Context) {
// DeleteRegistry
//
// @Summary Delete a registry by name
-// @Router /repos/{repo_id}/registry/{registry} [delete]
+// @Router /repos/{repo_id}/registries/{registry} [delete]
// @Produce plain
// @Success 204
// @Tags Repository registries
@@ -171,10 +169,10 @@ func GetRegistryList(c *gin.Context) {
// @Param registry path string true "the registry name"
func DeleteRegistry(c *gin.Context) {
repo := session.Repo(c)
- name := c.Param("registry")
+ addr := c.Param("registry")
registryService := server.Config.Services.Manager.RegistryServiceFromRepo(repo)
- err := registryService.RegistryDelete(repo, name)
+ err := registryService.RegistryDelete(repo, addr)
if err != nil {
handleDBError(c, err)
return
diff --git a/server/api/repo.go b/server/api/repo.go
index b5cefa699..b96eeaae6 100644
--- a/server/api/repo.go
+++ b/server/api/repo.go
@@ -360,7 +360,8 @@ func GetRepoBranches(c *gin.Context) {
branches, err := _forge.Branches(c, user, repo, session.Pagination(c))
if err != nil {
- _ = c.AbortWithError(http.StatusInternalServerError, err)
+ log.Error().Err(err).Msg("failed to load branches")
+ c.String(http.StatusInternalServerError, "failed to load branches: %s", err)
return
}
@@ -614,10 +615,14 @@ func repairRepo(c *gin.Context, repo *model.Repo, withPerms, skipOnErr bool) {
user, err := _store.GetUser(repo.UserID)
if err != nil {
if errors.Is(err, types.RecordNotExist) {
- if !skipOnErr {
- c.AbortWithStatus(http.StatusNotFound)
+ oldUserID := repo.UserID
+ user = session.User(c)
+ repo.UserID = user.ID
+ err = _store.UpdateRepo(repo)
+ if err != nil {
+ _ = c.AbortWithError(http.StatusInternalServerError, err)
}
- log.Error().Err(err).Msg("could not get user on repo repair")
+ log.Debug().Msgf("Could not find repo user with ID %d during repo repair, set to repair request user with ID %d", oldUserID, user.ID)
} else {
_ = c.AbortWithError(http.StatusInternalServerError, err)
}
diff --git a/server/api/stream.go b/server/api/stream.go
index 2d3c7ee86..a620dd068 100644
--- a/server/api/stream.go
+++ b/server/api/stream.go
@@ -28,12 +28,19 @@ import (
"github.com/rs/zerolog/log"
"go.woodpecker-ci.org/woodpecker/v2/server"
+ "go.woodpecker-ci.org/woodpecker/v2/server/logging"
"go.woodpecker-ci.org/woodpecker/v2/server/model"
"go.woodpecker-ci.org/woodpecker/v2/server/pubsub"
"go.woodpecker-ci.org/woodpecker/v2/server/router/middleware/session"
"go.woodpecker-ci.org/woodpecker/v2/server/store"
)
+const (
+ // How many batches of logs to keep for each client before starting to
+ // drop them if the client is not consuming them faster than they arrive.
+ maxQueuedBatchesPerClient int = 30
+)
+
// EventStreamSSE
//
// @Summary Stream events like pipeline updates
@@ -213,17 +220,32 @@ func LogStreamSSE(c *gin.Context) {
}
go func() {
- err := server.Config.Services.Logs.Tail(ctx, step.ID, func(entries ...*model.LogEntry) {
- for _, entry := range entries {
- select {
- case <-ctx.Done():
- return
- default:
- ee, _ := json.Marshal(entry)
- logChan <- ee
+ batches := make(logging.LogChan, maxQueuedBatchesPerClient)
+
+ go func() {
+ defer func() {
+ if r := recover(); r != nil {
+ log.Error().Msgf("error sending log message: %v", r)
+ }
+ }()
+
+ for entries := range batches {
+ for _, entry := range entries {
+ select {
+ case <-ctx.Done():
+ return
+ default:
+ if ee, err := json.Marshal(entry); err == nil {
+ logChan <- ee
+ } else {
+ log.Error().Err(err).Msg("unable to serialize log entry")
+ }
+ }
}
}
- })
+ }()
+
+ err := server.Config.Services.Logs.Tail(ctx, step.ID, batches)
if err != nil {
log.Error().Err(err).Msg("tail of logs failed")
}
diff --git a/server/api/z.go b/server/api/z.go
index 1c3ccb9f0..b1557733d 100644
--- a/server/api/z.go
+++ b/server/api/z.go
@@ -63,7 +63,7 @@ func Version(c *gin.Context) {
// @Description Endpoint returns the current logging level. Requires admin rights.
// @Router /log-level [get]
// @Produce json
-// @Success 200 {object} string{log-level=string}
+// @Success 200 {object} object{log-level=string}
// @Tags System
func LogLevel(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
@@ -77,10 +77,10 @@ func LogLevel(c *gin.Context) {
// @Description Endpoint sets the current logging level. Requires admin rights.
// @Router /log-level [post]
// @Produce json
-// @Success 200 {object} string{log-level=string}
+// @Success 200 {object} object{log-level=string}
// @Tags System
// @Param Authorization header string true "Insert your personal access token" default(Bearer )
-// @Param log-level body string{log-level=string} true "the new log level, one of "
+// @Param log-level body object{log-level=string} true "the new log level, one of "
func SetLogLevel(c *gin.Context) {
logLevel := struct {
LogLevel string `json:"log-level"`
diff --git a/server/config.go b/server/config.go
index 0ebcce5fc..96e9d4326 100644
--- a/server/config.go
+++ b/server/config.go
@@ -38,6 +38,7 @@ var Config = struct {
LogStore log.Service
}
Server struct {
+ JWTSecret string
Key string
Cert string
OAuthHost string
@@ -63,11 +64,12 @@ var Config = struct {
Pipeline struct {
AuthenticatePublicRepos bool
DefaultCancelPreviousPipelineEvents []model.WebhookEvent
- DefaultCloneImage string
+ DefaultClonePlugin string
+ TrustedClonePlugins []string
Limits model.ResourceLimit
Volumes []string
Networks []string
- Privileged []string
+ PrivilegedPlugins []string
DefaultTimeout int64
MaxTimeout int64
Proxy struct {
diff --git a/server/cron/cron.go b/server/cron/cron.go
index a1dcddd29..9fa35aa8c 100644
--- a/server/cron/cron.go
+++ b/server/cron/cron.go
@@ -19,7 +19,7 @@ import (
"fmt"
"time"
- "github.com/robfig/cron"
+ "github.com/gdgvda/cron"
"github.com/rs/zerolog/log"
"go.woodpecker-ci.org/woodpecker/v2/server"
@@ -31,14 +31,14 @@ import (
const (
// Specifies the interval woodpecker checks for new crons to exec.
- checkTime = 10 * time.Second
+ checkTime = time.Minute
// Specifies the batch size of crons to retrieve per check from database.
checkItems = 10
)
-// Start starts the cron scheduler loop.
-func Start(ctx context.Context, store store.Store) error {
+// Run starts the cron scheduler loop.
+func Run(ctx context.Context, store store.Store) error {
for {
select {
case <-ctx.Done():
@@ -71,7 +71,7 @@ func CalcNewNext(schedule string, now time.Time) (time.Time, error) {
// TODO: allow the users / the admin to set a specific timezone
- c, err := cron.Parse(schedule)
+ c, err := cron.ParseStandard(schedule)
if err != nil {
return time.Time{}, fmt.Errorf("cron parse schedule: %w", err)
}
diff --git a/server/forge/bitbucket/bitbucket.go b/server/forge/bitbucket/bitbucket.go
index 43f507b2c..675809689 100644
--- a/server/forge/bitbucket/bitbucket.go
+++ b/server/forge/bitbucket/bitbucket.go
@@ -313,7 +313,7 @@ func (c *config) Activate(ctx context.Context, u *model.User, r *model.Repo, lin
return c.newClient(ctx, u).CreateHook(r.Owner, r.Name, &internal.Hook{
Active: true,
Desc: rawURL.Host,
- Events: []string{"repo:push", "pullrequest:created"},
+ Events: []string{"repo:push", "pullrequest:created", "pullrequest:updated", "pullrequest:fulfilled", "pullrequest:rejected"},
URL: link,
})
}
diff --git a/server/forge/bitbucket/convert.go b/server/forge/bitbucket/convert.go
index 0fa28d988..59eb39fd5 100644
--- a/server/forge/bitbucket/convert.go
+++ b/server/forge/bitbucket/convert.go
@@ -168,22 +168,30 @@ func convertPullHook(from *internal.PullRequestHook) *model.Pipeline {
event = model.EventPullClosed
}
- return &model.Pipeline{
+ pipeline := &model.Pipeline{
Event: event,
- Commit: from.PullRequest.Dest.Commit.Hash,
- Ref: fmt.Sprintf("refs/heads/%s", from.PullRequest.Dest.Branch.Name),
+ Commit: from.PullRequest.Source.Commit.Hash,
+ Ref: fmt.Sprintf("refs/pull-requests/%d/from", from.PullRequest.ID),
Refspec: fmt.Sprintf("%s:%s",
from.PullRequest.Source.Branch.Name,
from.PullRequest.Dest.Branch.Name,
),
ForgeURL: from.PullRequest.Links.HTML.Href,
- Branch: from.PullRequest.Dest.Branch.Name,
- Message: from.PullRequest.Desc,
+ Branch: from.PullRequest.Source.Branch.Name,
+ Message: from.PullRequest.Title,
Avatar: from.Actor.Links.Avatar.Href,
Author: from.Actor.Login,
Sender: from.Actor.Login,
Timestamp: from.PullRequest.Updated.UTC().Unix(),
}
+
+ if from.PullRequest.State == stateClosed {
+ pipeline.Commit = from.PullRequest.MergeCommit.Hash
+ pipeline.Ref = fmt.Sprintf("refs/heads/%s", from.PullRequest.Dest.Branch.Name)
+ pipeline.Branch = from.PullRequest.Dest.Branch.Name
+ }
+
+ return pipeline
}
// convertPushHook is a helper function used to convert a Bitbucket push
diff --git a/server/forge/bitbucket/convert_test.go b/server/forge/bitbucket/convert_test.go
index c4bc75fb7..0765615a8 100644
--- a/server/forge/bitbucket/convert_test.go
+++ b/server/forge/bitbucket/convert_test.go
@@ -129,20 +129,22 @@ func Test_helper(t *testing.T) {
hook.PullRequest.Dest.Repo.Links.HTML.Href = "https://bitbucket.org/foo/bar"
hook.PullRequest.Source.Branch.Name = "change"
hook.PullRequest.Source.Repo.FullName = "baz/bar"
+ hook.PullRequest.Source.Commit.Hash = "c8411d7"
hook.PullRequest.Links.HTML.Href = "https://bitbucket.org/foo/bar/pulls/5"
- hook.PullRequest.Desc = "updated README"
+ hook.PullRequest.Title = "updated README"
hook.PullRequest.Updated = time.Now()
+ hook.PullRequest.ID = 1
pipeline := convertPullHook(hook)
g.Assert(pipeline.Event).Equal(model.EventPull)
g.Assert(pipeline.Author).Equal(hook.Actor.Login)
g.Assert(pipeline.Avatar).Equal(hook.Actor.Links.Avatar.Href)
- g.Assert(pipeline.Commit).Equal(hook.PullRequest.Dest.Commit.Hash)
- g.Assert(pipeline.Branch).Equal(hook.PullRequest.Dest.Branch.Name)
+ g.Assert(pipeline.Commit).Equal(hook.PullRequest.Source.Commit.Hash)
+ g.Assert(pipeline.Branch).Equal(hook.PullRequest.Source.Branch.Name)
g.Assert(pipeline.ForgeURL).Equal(hook.PullRequest.Links.HTML.Href)
- g.Assert(pipeline.Ref).Equal("refs/heads/main")
+ g.Assert(pipeline.Ref).Equal("refs/pull-requests/1/from")
g.Assert(pipeline.Refspec).Equal("change:main")
- g.Assert(pipeline.Message).Equal(hook.PullRequest.Desc)
+ g.Assert(pipeline.Message).Equal(hook.PullRequest.Title)
g.Assert(pipeline.Timestamp).Equal(hook.PullRequest.Updated.Unix())
})
diff --git a/server/forge/bitbucket/internal/types.go b/server/forge/bitbucket/internal/types.go
index a5dc4acb4..bbb03ab1c 100644
--- a/server/forge/bitbucket/internal/types.go
+++ b/server/forge/bitbucket/internal/types.go
@@ -164,6 +164,10 @@ type PullRequestHook struct {
Created time.Time `json:"created_on"`
Updated time.Time `json:"updated_on"`
+ MergeCommit struct {
+ Hash string `json:"hash"`
+ } `json:"merge_commit"`
+
Source struct {
Repo Repo `json:"repository"`
Commit struct {
diff --git a/server/forge/bitbucket/parse_test.go b/server/forge/bitbucket/parse_test.go
index aa9b81117..a5562fc39 100644
--- a/server/forge/bitbucket/parse_test.go
+++ b/server/forge/bitbucket/parse_test.go
@@ -63,7 +63,7 @@ func Test_parser(t *testing.T) {
g.Assert(err).IsNil()
g.Assert(r.FullName).Equal("user_name/repo_name")
g.Assert(b.Event).Equal(model.EventPull)
- g.Assert(b.Commit).Equal("ce5965ddd289")
+ g.Assert(b.Commit).Equal("d3022fc0ca3d")
})
g.It("should return pull-request details for a pull-request merged payload", func() {
@@ -76,7 +76,7 @@ func Test_parser(t *testing.T) {
g.Assert(err).IsNil()
g.Assert(r.FullName).Equal("anbraten/test-2")
g.Assert(b.Event).Equal(model.EventPullClosed)
- g.Assert(b.Commit).Equal("6c5f0bc9b2aa")
+ g.Assert(b.Commit).Equal("006704dbeab2")
})
g.It("should return pull-request details for a pull-request closed payload", func() {
@@ -89,7 +89,7 @@ func Test_parser(t *testing.T) {
g.Assert(err).IsNil()
g.Assert(r.FullName).Equal("anbraten/test-2")
g.Assert(b.Event).Equal(model.EventPullClosed)
- g.Assert(b.Commit).Equal("006704dbeab2")
+ g.Assert(b.Commit).Equal("f90e18fc9d45")
})
})
diff --git a/server/forge/bitbucketdatacenter/bitbucketdatacenter.go b/server/forge/bitbucketdatacenter/bitbucketdatacenter.go
index 5b27f2632..42212895b 100644
--- a/server/forge/bitbucketdatacenter/bitbucketdatacenter.go
+++ b/server/forge/bitbucketdatacenter/bitbucketdatacenter.go
@@ -211,7 +211,7 @@ func (c *client) Repos(ctx context.Context, u *model.User) ([]*model.Repo, error
}
opts := &bb.RepositorySearchOptions{Permission: bb.PermissionRepoWrite, ListOptions: bb.ListOptions{Limit: listLimit}}
- var all []*model.Repo
+ all := make([]*model.Repo, 0)
for {
repos, resp, err := bc.Projects.SearchRepositories(ctx, opts)
if err != nil {
@@ -277,7 +277,7 @@ func (c *client) Dir(ctx context.Context, u *model.User, r *model.Repo, p *model
}
opts := &bb.FilesListOptions{At: p.Commit}
- var all []*forge_types.FileMeta
+ all := make([]*forge_types.FileMeta, 0)
for {
list, resp, err := bc.Projects.ListFiles(ctx, r.Owner, r.Name, path, opts)
if err != nil {
@@ -341,7 +341,7 @@ func (c *client) Branches(ctx context.Context, u *model.User, r *model.Repo, p *
}
opts := &bb.BranchSearchOptions{ListOptions: convertListOptions(p)}
- var all []string
+ all := make([]string, 0)
for {
branches, resp, err := bc.Projects.SearchBranches(ctx, r.Owner, r.Name, opts)
if err != nil {
@@ -389,7 +389,7 @@ func (c *client) PullRequests(ctx context.Context, u *model.User, r *model.Repo,
}
opts := &bb.PullRequestSearchOptions{ListOptions: convertListOptions(p)}
- var all []*model.PullRequest
+ all := make([]*model.PullRequest, 0)
for {
prs, resp, err := bc.Projects.SearchPullRequests(ctx, r.Owner, r.Name, opts)
if err != nil {
diff --git a/server/forge/forge.go b/server/forge/forge.go
index bb5db187d..4169e60d0 100644
--- a/server/forge/forge.go
+++ b/server/forge/forge.go
@@ -15,7 +15,7 @@
package forge
-//go:generate mockery --name Forge --output mocks --case underscore
+//go:generate mockery --name Forge --output mocks --case underscore --note "+build test"
import (
"context"
diff --git a/server/forge/gitea/gitea.go b/server/forge/gitea/gitea.go
index 50b5ae56d..c3929fc87 100644
--- a/server/forge/gitea/gitea.go
+++ b/server/forge/gitea/gitea.go
@@ -472,12 +472,17 @@ func (c *Gitea) PullRequests(ctx context.Context, u *model.User, r *model.Repo,
return nil, err
}
- pullRequests, _, err := client.ListRepoPullRequests(r.Owner, r.Name, gitea.ListPullRequestsOptions{
+ pullRequests, resp, err := client.ListRepoPullRequests(r.Owner, r.Name, gitea.ListPullRequestsOptions{
ListOptions: gitea.ListOptions{Page: p.Page, PageSize: p.PerPage},
State: gitea.StateOpen,
})
if err != nil {
- return nil, err
+ // Repositories without commits return empty list with status code 404
+ if pullRequests != nil && resp != nil && resp.StatusCode == http.StatusNotFound {
+ err = nil
+ } else {
+ return nil, err
+ }
}
result := make([]*model.PullRequest, len(pullRequests))
diff --git a/server/forge/github/convert.go b/server/forge/github/convert.go
index fbeaf7f3f..5184cf4b9 100644
--- a/server/forge/github/convert.go
+++ b/server/forge/github/convert.go
@@ -18,7 +18,7 @@ package github
import (
"fmt"
- "github.com/google/go-github/v62/github"
+ "github.com/google/go-github/v64/github"
"go.woodpecker-ci.org/woodpecker/v2/server/model"
)
diff --git a/server/forge/github/convert_test.go b/server/forge/github/convert_test.go
index 33abce887..dd366467c 100644
--- a/server/forge/github/convert_test.go
+++ b/server/forge/github/convert_test.go
@@ -19,7 +19,7 @@ import (
"testing"
"github.com/franela/goblin"
- "github.com/google/go-github/v62/github"
+ "github.com/google/go-github/v64/github"
"go.woodpecker-ci.org/woodpecker/v2/server/model"
)
diff --git a/server/forge/github/fixtures/hooks.go b/server/forge/github/fixtures/hooks.go
index bae47d9e1..895c537ba 100644
--- a/server/forge/github/fixtures/hooks.go
+++ b/server/forge/github/fixtures/hooks.go
@@ -49,7 +49,7 @@ const HookPush = `{
"site_admin": false
},
"html_url": "https://github.com/woodpecker-ci/woodpecker",
- "description": "Woodpecker is a simple yet powerful CI/CD engine with great extensibility.",
+ "description": "Woodpecker is a simple, yet powerful CI/CD engine with great extensibility.",
"fork": false,
"url": "https://github.com/woodpecker-ci/woodpecker",
"forks_url": "https://api.github.com/repos/woodpecker-ci/woodpecker/forks",
@@ -152,7 +152,7 @@ const HookPush = `{
"members_url": "https://api.github.com/orgs/woodpecker-ci/members{/member}",
"public_members_url": "https://api.github.com/orgs/woodpecker-ci/public_members{/member}",
"avatar_url": "https://avatars.githubusercontent.com/u/84780935?v=4",
- "description": "Woodpecker is a simple yet powerful CI/CD engine with great extensibility."
+ "description": "Woodpecker is a simple, yet powerful CI/CD engine with great extensibility."
},
"sender": {
"login": "6543",
diff --git a/server/forge/github/github.go b/server/forge/github/github.go
index cd54bbe94..2b95605e0 100644
--- a/server/forge/github/github.go
+++ b/server/forge/github/github.go
@@ -27,7 +27,7 @@ import (
"strings"
"time"
- "github.com/google/go-github/v62/github"
+ "github.com/google/go-github/v64/github"
"github.com/rs/zerolog/log"
"golang.org/x/oauth2"
diff --git a/server/forge/github/parse.go b/server/forge/github/parse.go
index 5c1ed8dbe..f47e91751 100644
--- a/server/forge/github/parse.go
+++ b/server/forge/github/parse.go
@@ -22,7 +22,7 @@ import (
"net/http"
"strings"
- "github.com/google/go-github/v62/github"
+ "github.com/google/go-github/v64/github"
"go.woodpecker-ci.org/woodpecker/v2/server/forge/types"
"go.woodpecker-ci.org/woodpecker/v2/server/model"
@@ -126,10 +126,10 @@ func parseDeployHook(hook *github.DeploymentEvent) (*model.Repo, *model.Pipeline
Message: hook.GetDeployment().GetDescription(),
Ref: hook.GetDeployment().GetRef(),
Branch: hook.GetDeployment().GetRef(),
- Deploy: hook.GetDeployment().GetEnvironment(),
Avatar: hook.GetSender().GetAvatarURL(),
Author: hook.GetSender().GetLogin(),
Sender: hook.GetSender().GetLogin(),
+ DeployTo: hook.GetDeployment().GetEnvironment(),
DeployTask: hook.GetDeployment().GetTask(),
}
// if the ref is a sha or short sha we need to manually construct the ref.
diff --git a/server/forge/github/parse_test.go b/server/forge/github/parse_test.go
index 39ca63f5c..225bfd3c9 100644
--- a/server/forge/github/parse_test.go
+++ b/server/forge/github/parse_test.go
@@ -119,7 +119,7 @@ func Test_parser(t *testing.T) {
g.Assert(b).IsNotNil()
g.Assert(p).IsNil()
g.Assert(b.Event).Equal(model.EventDeploy)
- g.Assert(b.Deploy).Equal("production")
+ g.Assert(b.DeployTo).Equal("production")
g.Assert(b.DeployTask).Equal("deploy")
})
})
diff --git a/server/forge/gitlab/convert.go b/server/forge/gitlab/convert.go
index 793e81248..ad6dbea58 100644
--- a/server/forge/gitlab/convert.go
+++ b/server/forge/gitlab/convert.go
@@ -124,6 +124,7 @@ func convertMergeRequestHook(hook *gitlab.MergeEvent, req *http.Request) (int, *
pipeline.Ref = fmt.Sprintf(mergeRefs, obj.IID)
pipeline.Branch = obj.SourceBranch
+ pipeline.Refspec = fmt.Sprintf("%s:%s", obj.SourceBranch, obj.TargetBranch)
author := lastCommit.Author
diff --git a/server/forge/mocks/forge.go b/server/forge/mocks/forge.go
index a926ca16a..3deb6b960 100644
--- a/server/forge/mocks/forge.go
+++ b/server/forge/mocks/forge.go
@@ -1,5 +1,8 @@
// Code generated by mockery. DO NOT EDIT.
+//go:build test
+// +build test
+
package mocks
import (
diff --git a/server/grpc/rpc.go b/server/grpc/rpc.go
index 94cda672c..52edf1f99 100644
--- a/server/grpc/rpc.go
+++ b/server/grpc/rpc.go
@@ -39,6 +39,9 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/server/store"
)
+// updateAgentLastWorkDelay the delay before the LastWork info should be updated.
+const updateAgentLastWorkDelay = time.Minute
+
type RPC struct {
queue queue.Queue
pubsub *pubsub.Publisher
@@ -48,7 +51,7 @@ type RPC struct {
pipelineCount *prometheus.CounterVec
}
-// Next implements the rpc.Next function.
+// Next blocks until it provides the next workflow to execute.
func (s *RPC) Next(c context.Context, agentFilter rpc.Filter) (*rpc.Workflow, error) {
if hostname, err := s.getHostnameFromContext(c); err == nil {
log.Debug().Msgf("agent connected: %s: polling", hostname)
@@ -80,25 +83,35 @@ func (s *RPC) Next(c context.Context, agentFilter rpc.Filter) (*rpc.Workflow, er
}
// task should not run, so mark it as done
- if err := s.Done(c, task.ID, rpc.State{}); err != nil {
- log.Error().Err(err).Msgf("mark task '%s' done failed", task.ID)
+ if err := s.Done(c, task.ID, rpc.WorkflowState{}); err != nil {
+ log.Error().Err(err).Msgf("marking workflow task '%s' as done failed", task.ID)
}
}
}
-// Wait implements the rpc.Wait function.
-func (s *RPC) Wait(c context.Context, id string) error {
- return s.queue.Wait(c, id)
+// Wait blocks until the workflow with the given ID is done.
+func (s *RPC) Wait(c context.Context, workflowID string) error {
+ return s.queue.Wait(c, workflowID)
}
-// Extend implements the rpc.Extend function.
-func (s *RPC) Extend(c context.Context, id string) error {
- return s.queue.Extend(c, id)
+// Extend extends the lease for the workflow with the given ID.
+func (s *RPC) Extend(c context.Context, workflowID string) error {
+ agent, err := s.getAgentFromContext(c)
+ if err != nil {
+ return err
+ }
+
+ err = s.updateAgentLastWork(agent)
+ if err != nil {
+ return err
+ }
+
+ return s.queue.Extend(c, workflowID)
}
-// Update implements the rpc.Update function.
-func (s *RPC) Update(_ context.Context, id string, state rpc.State) error {
- workflowID, err := strconv.ParseInt(id, 10, 64)
+// Update updates the state of a step.
+func (s *RPC) Update(_ context.Context, strWorkflowID string, state rpc.StepState) error {
+ workflowID, err := strconv.ParseInt(strWorkflowID, 10, 64)
if err != nil {
return err
}
@@ -127,7 +140,7 @@ func (s *RPC) Update(_ context.Context, id string, state rpc.State) error {
Int64("stepPipelineID", step.PipelineID).
Int64("currentPipelineID", currentPipeline.ID).
Msg(msg)
- return fmt.Errorf(msg)
+ return errors.New(msg)
}
repo, err := s.store.GetRepo(currentPipeline.RepoID)
@@ -163,15 +176,15 @@ func (s *RPC) Update(_ context.Context, id string, state rpc.State) error {
}
// Init implements the rpc.Init function.
-func (s *RPC) Init(c context.Context, id string, state rpc.State) error {
- stepID, err := strconv.ParseInt(id, 10, 64)
+func (s *RPC) Init(c context.Context, strWorkflowID string, state rpc.WorkflowState) error {
+ workflowID, err := strconv.ParseInt(strWorkflowID, 10, 64)
if err != nil {
return err
}
- workflow, err := s.store.WorkflowLoad(stepID)
+ workflow, err := s.store.WorkflowLoad(workflowID)
if err != nil {
- log.Error().Err(err).Msgf("cannot find step with id %d", stepID)
+ log.Error().Err(err).Msgf("cannot find workflow with id %d", workflowID)
return err
}
@@ -195,7 +208,7 @@ func (s *RPC) Init(c context.Context, id string, state rpc.State) error {
if currentPipeline.Status == model.StatusPending {
if currentPipeline, err = pipeline.UpdateToStatusRunning(s.store, *currentPipeline, state.Started); err != nil {
- log.Error().Err(err).Msgf("init: cannot update build_id %d state", currentPipeline.ID)
+ log.Error().Err(err).Msgf("init: cannot update pipeline %d state", currentPipeline.ID)
}
}
@@ -220,24 +233,25 @@ func (s *RPC) Init(c context.Context, id string, state rpc.State) error {
s.pubsub.Publish(message)
}()
- workflow, err = pipeline.UpdateWorkflowToStatusStarted(s.store, *workflow, state)
+ workflow, err = pipeline.UpdateWorkflowStatusToRunning(s.store, *workflow, state)
if err != nil {
return err
}
s.updateForgeStatus(c, repo, currentPipeline, workflow)
- return nil
+
+ return s.updateAgentLastWork(agent)
}
-// Done implements the rpc.Done function.
-func (s *RPC) Done(c context.Context, id string, state rpc.State) error {
- workflowID, err := strconv.ParseInt(id, 10, 64)
+// Done marks the workflow with the given ID as done.
+func (s *RPC) Done(c context.Context, strWorkflowID string, state rpc.WorkflowState) error {
+ workflowID, err := strconv.ParseInt(strWorkflowID, 10, 64)
if err != nil {
return err
}
workflow, err := s.store.WorkflowLoad(workflowID)
if err != nil {
- log.Error().Err(err).Msgf("cannot find step with id %d", workflowID)
+ log.Error().Err(err).Msgf("cannot find workflow with id %d", workflowID)
return err
}
@@ -261,19 +275,19 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error {
logger := log.With().
Str("repo_id", fmt.Sprint(repo.ID)).
Str("pipeline_id", fmt.Sprint(currentPipeline.ID)).
- Str("workflow_id", id).Logger()
+ Str("workflow_id", strWorkflowID).Logger()
logger.Trace().Msgf("gRPC Done with state: %#v", state)
if workflow, err = pipeline.UpdateWorkflowStatusToDone(s.store, *workflow, state); err != nil {
- logger.Error().Err(err).Msgf("pipeline.UpdateStepStatusToDone: cannot update workflow state: %s", err)
+ logger.Error().Err(err).Msgf("pipeline.UpdateWorkflowStatusToDone: cannot update workflow state: %s", err)
}
var queueErr error
if workflow.Failing() {
- queueErr = s.queue.Error(c, id, fmt.Errorf("step finished with exit code %d, %s", state.ExitCode, state.Error))
+ queueErr = s.queue.Error(c, strWorkflowID, fmt.Errorf("workflow finished with error %s", state.Error))
} else {
- queueErr = s.queue.Done(c, id, workflow.State)
+ queueErr = s.queue.Done(c, strWorkflowID, workflow.State)
}
if queueErr != nil {
logger.Error().Err(queueErr).Msg("queue.Done: cannot ack workflow")
@@ -286,8 +300,8 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error {
s.completeChildrenIfParentCompleted(workflow)
if !model.IsThereRunningStage(currentPipeline.Workflows) {
- if currentPipeline, err = pipeline.UpdateStatusToDone(s.store, *currentPipeline, model.PipelineStatus(currentPipeline.Workflows), workflow.Stopped); err != nil {
- logger.Error().Err(err).Msgf("pipeline.UpdateStatusToDone: cannot update workflow final state")
+ if currentPipeline, err = pipeline.UpdateStatusToDone(s.store, *currentPipeline, model.PipelineStatus(currentPipeline.Workflows), workflow.Finished); err != nil {
+ logger.Error().Err(err).Msgf("pipeline.UpdateStatusToDone: cannot update workflows final state")
}
}
@@ -311,34 +325,62 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error {
s.pipelineTime.WithLabelValues(repo.FullName, currentPipeline.Branch, string(currentPipeline.Status), "total").Set(float64(currentPipeline.Finished - currentPipeline.Started))
}
if currentPipeline.IsMultiPipeline() {
- s.pipelineTime.WithLabelValues(repo.FullName, currentPipeline.Branch, string(workflow.State), workflow.Name).Set(float64(workflow.Stopped - workflow.Started))
+ s.pipelineTime.WithLabelValues(repo.FullName, currentPipeline.Branch, string(workflow.State), workflow.Name).Set(float64(workflow.Finished - workflow.Started))
}
- return nil
+ agent, err := s.getAgentFromContext(c)
+ if err != nil {
+ return err
+ }
+ return s.updateAgentLastWork(agent)
}
-// Log implements the rpc.Log function.
-func (s *RPC) Log(c context.Context, _logEntry *rpc.LogEntry) error {
- // convert rpc log_entry to model.log_entry
- step, err := s.store.StepByUUID(_logEntry.StepUUID)
+// Log writes a log entry to the database and publishes it to the pubsub.
+// An explicit stepUUID makes it obvious that all entries must come from the same step.
+func (s *RPC) Log(c context.Context, stepUUID string, rpcLogEntries []*rpc.LogEntry) error {
+ step, err := s.store.StepByUUID(stepUUID)
if err != nil {
- return fmt.Errorf("could not find step with uuid %s in store: %w", _logEntry.StepUUID, err)
+ return fmt.Errorf("could not find step with uuid %s in store: %w", stepUUID, err)
}
- logEntry := &model.LogEntry{
- StepID: step.ID,
- Time: _logEntry.Time,
- Line: _logEntry.Line,
- Data: _logEntry.Data,
- Type: model.LogEntryType(_logEntry.Type),
+
+ agent, err := s.getAgentFromContext(c)
+ if err != nil {
+ return err
}
+
+ err = s.updateAgentLastWork(agent)
+ if err != nil {
+ return err
+ }
+
+ var logEntries []*model.LogEntry
+
+ for _, rpcLogEntry := range rpcLogEntries {
+ if rpcLogEntry.StepUUID != stepUUID {
+ return fmt.Errorf("expected step UUID %s, got %s", stepUUID, rpcLogEntry.StepUUID)
+ }
+ logEntries = append(logEntries, &model.LogEntry{
+ StepID: step.ID,
+ Time: rpcLogEntry.Time,
+ Line: rpcLogEntry.Line,
+ Data: rpcLogEntry.Data,
+ Type: model.LogEntryType(rpcLogEntry.Type),
+ })
+ }
+
// make sure writes to pubsub are non blocking (https://github.com/woodpecker-ci/woodpecker/blob/c919f32e0b6432a95e1a6d3d0ad662f591adf73f/server/logging/log.go#L9)
go func() {
// write line to listening web clients
- if err := s.logger.Write(c, logEntry.StepID, logEntry); err != nil {
+ if err := s.logger.Write(c, step.ID, logEntries); err != nil {
log.Error().Err(err).Msgf("rpc server could not write to logger")
}
}()
- return server.Config.Services.LogStore.LogAppend(logEntry)
+
+ if err = server.Config.Services.LogStore.LogAppend(step, logEntries); err != nil {
+ log.Error().Err(err).Msg("could not store log entries")
+ }
+
+ return nil
}
func (s *RPC) RegisterAgent(ctx context.Context, platform, backend, version string, capacity int32) (int64, error) {
@@ -366,13 +408,14 @@ func (s *RPC) RegisterAgent(ctx context.Context, platform, backend, version stri
return agent.ID, nil
}
+// UnregisterAgent removes the agent from the database.
func (s *RPC) UnregisterAgent(ctx context.Context) error {
agent, err := s.getAgentFromContext(ctx)
if !agent.IsSystemAgent() {
// registered with individual agent token -> do not unregister
return nil
}
- log.Debug().Msgf("unregistering agent with ID %d", agent.ID)
+ log.Debug().Msgf("un-registering agent with ID %d", agent.ID)
if err != nil {
return err
}
@@ -401,7 +444,7 @@ func (s *RPC) ReportHealth(ctx context.Context, status string) error {
func (s *RPC) completeChildrenIfParentCompleted(completedWorkflow *model.Workflow) {
for _, c := range completedWorkflow.Children {
if c.Running() {
- if _, err := pipeline.UpdateStepToStatusSkipped(s.store, *c, completedWorkflow.Stopped); err != nil {
+ if _, err := pipeline.UpdateStepToStatusSkipped(s.store, *c, completedWorkflow.Finished); err != nil {
log.Error().Err(err).Msgf("done: cannot update step_id %d child state", c.ID)
}
}
@@ -480,3 +523,17 @@ func (s *RPC) getHostnameFromContext(ctx context.Context) (string, error) {
}
return "", errors.New("no hostname in metadata")
}
+
+func (s *RPC) updateAgentLastWork(agent *model.Agent) error {
+ // only update agent.LastWork if not recently updated
+ if time.Unix(agent.LastWork, 0).Add(updateAgentLastWorkDelay).After(time.Now()) {
+ return nil
+ }
+
+ agent.LastWork = time.Now().Unix()
+ if err := s.store.AgentUpdate(agent); err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/server/grpc/rpc_test.go b/server/grpc/rpc_test.go
index 1fd850b8a..01c57676b 100644
--- a/server/grpc/rpc_test.go
+++ b/server/grpc/rpc_test.go
@@ -17,9 +17,11 @@ package grpc
import (
"context"
"testing"
+ "time"
"github.com/franela/goblin"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
"google.golang.org/grpc/metadata"
"go.woodpecker-ci.org/woodpecker/v2/server/model"
@@ -107,3 +109,51 @@ func TestRegisterAgent(t *testing.T) {
})
})
}
+
+func TestUpdateAgentLastWork(t *testing.T) {
+ t.Run("When last work was never updated it should update last work timestamp", func(t *testing.T) {
+ agent := model.Agent{
+ LastWork: 0,
+ }
+ store := mocks_store.NewStore(t)
+ rpc := RPC{
+ store: store,
+ }
+ store.On("AgentUpdate", mock.Anything).Once().Return(nil)
+
+ err := rpc.updateAgentLastWork(&agent)
+ assert.NoError(t, err)
+
+ assert.NotZero(t, agent.LastWork)
+ })
+
+ t.Run("When last work was updated over a minute ago it should update last work timestamp", func(t *testing.T) {
+ lastWork := time.Now().Add(-time.Hour).Unix()
+ agent := model.Agent{
+ LastWork: lastWork,
+ }
+ store := mocks_store.NewStore(t)
+ rpc := RPC{
+ store: store,
+ }
+ store.On("AgentUpdate", mock.Anything).Once().Return(nil)
+
+ err := rpc.updateAgentLastWork(&agent)
+ assert.NoError(t, err)
+
+ assert.NotEqual(t, lastWork, agent.LastWork)
+ })
+
+ t.Run("When last work was updated in the last minute it should not update last work timestamp again", func(t *testing.T) {
+ lastWork := time.Now().Add(-time.Second * 30).Unix()
+ agent := model.Agent{
+ LastWork: lastWork,
+ }
+ rpc := RPC{}
+
+ err := rpc.updateAgentLastWork(&agent)
+ assert.NoError(t, err)
+
+ assert.Equal(t, lastWork, agent.LastWork)
+ })
+}
diff --git a/server/grpc/server.go b/server/grpc/server.go
index 67c942223..633a7ee99 100644
--- a/server/grpc/server.go
+++ b/server/grpc/server.go
@@ -20,6 +20,7 @@ import (
"github.com/prometheus/client_golang/prometheus"
prometheus_auto "github.com/prometheus/client_golang/prometheus/promauto"
+ "github.com/rs/zerolog/log"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc/proto"
@@ -85,13 +86,10 @@ func (s *WoodpeckerServer) Next(c context.Context, req *proto.NextRequest) (*pro
}
func (s *WoodpeckerServer) Init(c context.Context, req *proto.InitRequest) (*proto.Empty, error) {
- state := rpc.State{
- Error: req.GetState().GetError(),
- ExitCode: int(req.GetState().GetExitCode()),
- Finished: req.GetState().GetFinished(),
+ state := rpc.WorkflowState{
Started: req.GetState().GetStarted(),
- StepUUID: req.GetState().GetStepUuid(),
- Exited: req.GetState().GetExited(),
+ Finished: req.GetState().GetFinished(),
+ Error: req.GetState().GetError(),
}
res := new(proto.Empty)
err := s.peer.Init(c, req.GetId(), state)
@@ -99,13 +97,13 @@ func (s *WoodpeckerServer) Init(c context.Context, req *proto.InitRequest) (*pro
}
func (s *WoodpeckerServer) Update(c context.Context, req *proto.UpdateRequest) (*proto.Empty, error) {
- state := rpc.State{
+ state := rpc.StepState{
+ StepUUID: req.GetState().GetStepUuid(),
+ Started: req.GetState().GetStarted(),
+ Finished: req.GetState().GetFinished(),
+ Exited: req.GetState().GetExited(),
Error: req.GetState().GetError(),
ExitCode: int(req.GetState().GetExitCode()),
- Finished: req.GetState().GetFinished(),
- Started: req.GetState().GetStarted(),
- StepUUID: req.GetState().GetStepUuid(),
- Exited: req.GetState().GetExited(),
}
res := new(proto.Empty)
err := s.peer.Update(c, req.GetId(), state)
@@ -113,13 +111,10 @@ func (s *WoodpeckerServer) Update(c context.Context, req *proto.UpdateRequest) (
}
func (s *WoodpeckerServer) Done(c context.Context, req *proto.DoneRequest) (*proto.Empty, error) {
- state := rpc.State{
- Error: req.GetState().GetError(),
- ExitCode: int(req.GetState().GetExitCode()),
- Finished: req.GetState().GetFinished(),
+ state := rpc.WorkflowState{
Started: req.GetState().GetStarted(),
- StepUUID: req.GetState().GetStepUuid(),
- Exited: req.GetState().GetExited(),
+ Finished: req.GetState().GetFinished(),
+ Error: req.GetState().GetError(),
}
res := new(proto.Empty)
err := s.peer.Done(c, req.GetId(), state)
@@ -139,15 +134,39 @@ func (s *WoodpeckerServer) Extend(c context.Context, req *proto.ExtendRequest) (
}
func (s *WoodpeckerServer) Log(c context.Context, req *proto.LogRequest) (*proto.Empty, error) {
- logEntry := &rpc.LogEntry{
- Data: req.GetLogEntry().GetData(),
- Line: int(req.GetLogEntry().GetLine()),
- Time: req.GetLogEntry().GetTime(),
- StepUUID: req.GetLogEntry().GetStepUuid(),
- Type: int(req.GetLogEntry().GetType()),
+ var (
+ entries []*rpc.LogEntry
+ stepUUID string
+ )
+
+ write := func() error {
+ if len(entries) > 0 {
+ if err := s.peer.Log(c, stepUUID, entries); err != nil {
+ log.Error().Err(err).Msg("could not write log entries")
+ return err
+ }
+ }
+ return nil
}
+
+ for _, reqEntry := range req.GetLogEntries() {
+ entry := &rpc.LogEntry{
+ Data: reqEntry.GetData(),
+ Line: int(reqEntry.GetLine()),
+ Time: reqEntry.GetTime(),
+ StepUUID: reqEntry.GetStepUuid(),
+ Type: int(reqEntry.GetType()),
+ }
+ if entry.StepUUID != stepUUID {
+ _ = write()
+ stepUUID = entry.StepUUID
+ entries = entries[:0]
+ }
+ entries = append(entries, entry)
+ }
+
res := new(proto.Empty)
- err := s.peer.Log(c, logEntry)
+ err := write()
return res, err
}
diff --git a/server/logging/log.go b/server/logging/log.go
index 1db5475e5..0e713644f 100644
--- a/server/logging/log.go
+++ b/server/logging/log.go
@@ -18,6 +18,8 @@ import (
"context"
"sync"
+ logger "github.com/rs/zerolog/log"
+
"go.woodpecker-ci.org/woodpecker/v2/server/model"
)
@@ -38,7 +40,7 @@ import (
// sub.start()... event loop
type subscriber struct {
- handler Handler
+ receiver LogChan
}
type stream struct {
@@ -77,7 +79,7 @@ func (l *log) Open(_ context.Context, stepID int64) error {
return nil
}
-func (l *log) Write(ctx context.Context, stepID int64, logEntry *model.LogEntry) error {
+func (l *log) Write(ctx context.Context, stepID int64, entries []*model.LogEntry) error {
l.Lock()
s, ok := l.streams[stepID]
l.Unlock()
@@ -92,15 +94,20 @@ func (l *log) Write(ctx context.Context, stepID int64, logEntry *model.LogEntry)
}
s.Lock()
- s.list = append(s.list, logEntry)
+ s.list = append(s.list, entries...)
for sub := range s.subs {
- go sub.handler(logEntry)
+ select {
+ case sub.receiver <- entries:
+ default:
+ logger.Info().Msgf("subscriber channel is full -- dropping logs for step %d", stepID)
+ }
}
s.Unlock()
+
return nil
}
-func (l *log) Tail(c context.Context, stepID int64, handler Handler) error {
+func (l *log) Tail(c context.Context, stepID int64, receiver LogChan) error {
l.Lock()
s, ok := l.streams[stepID]
l.Unlock()
@@ -109,11 +116,11 @@ func (l *log) Tail(c context.Context, stepID int64, handler Handler) error {
}
sub := &subscriber{
- handler: handler,
+ receiver: receiver,
}
s.Lock()
if len(s.list) != 0 {
- sub.handler(s.list...)
+ sub.receiver <- s.list
}
s.subs[sub] = struct{}{}
s.Unlock()
diff --git a/server/logging/log_test.go b/server/logging/log_test.go
index 90565a48f..f84a5b8f3 100644
--- a/server/logging/log_test.go
+++ b/server/logging/log_test.go
@@ -39,28 +39,37 @@ func TestLogging(t *testing.T) {
context.Background(),
)
+ receiver := make(LogChan, 10)
+ defer close(receiver)
+
+ go func() {
+ for range receiver {
+ wg.Done()
+ }
+ }()
+
logger := New()
assert.NoError(t, logger.Open(ctx, testStepID))
go func() {
- assert.NoError(t, logger.Tail(ctx, testStepID, func(_ ...*model.LogEntry) { wg.Done() }))
+ assert.NoError(t, logger.Tail(ctx, testStepID, receiver))
}()
go func() {
- assert.NoError(t, logger.Tail(ctx, testStepID, func(_ ...*model.LogEntry) { wg.Done() }))
+ assert.NoError(t, logger.Tail(ctx, testStepID, receiver))
}()
<-time.After(500 * time.Millisecond)
wg.Add(4)
go func() {
- assert.NoError(t, logger.Write(ctx, testStepID, testEntry))
- assert.NoError(t, logger.Write(ctx, testStepID, testEntry))
+ assert.NoError(t, logger.Write(ctx, testStepID, []*model.LogEntry{testEntry}))
+ assert.NoError(t, logger.Write(ctx, testStepID, []*model.LogEntry{testEntry}))
}()
wg.Wait()
wg.Add(1)
go func() {
- assert.NoError(t, logger.Tail(ctx, testStepID, func(_ ...*model.LogEntry) { wg.Done() }))
+ assert.NoError(t, logger.Tail(ctx, testStepID, receiver))
}()
<-time.After(500 * time.Millisecond)
diff --git a/server/logging/logging.go b/server/logging/logging.go
index 400273def..e8eb80117 100644
--- a/server/logging/logging.go
+++ b/server/logging/logging.go
@@ -24,8 +24,8 @@ import (
// ErrNotFound is returned when the log does not exist.
var ErrNotFound = errors.New("stream: not found")
-// Handler defines a callback function for handling log entries.
-type Handler func(...*model.LogEntry)
+// LogChan defines a channel type for receiving ordered batches of log entries.
+type LogChan chan []*model.LogEntry
// Log defines a log multiplexer.
type Log interface {
@@ -33,10 +33,10 @@ type Log interface {
Open(c context.Context, stepID int64) error
// Write writes the entry to the log.
- Write(c context.Context, stepID int64, entry *model.LogEntry) error
+ Write(c context.Context, stepID int64, entries []*model.LogEntry) error
// Tail tails the log.
- Tail(c context.Context, stepID int64, handler Handler) error
+ Tail(c context.Context, stepID int64, handler LogChan) error
// Close closes the log.
Close(c context.Context, stepID int64) error
diff --git a/server/model/agent.go b/server/model/agent.go
index aebb9d742..31655cbb8 100644
--- a/server/model/agent.go
+++ b/server/model/agent.go
@@ -22,6 +22,7 @@ type Agent struct {
OwnerID int64 `json:"owner_id" xorm:"'owner_id'"`
Token string `json:"token" xorm:"token"`
LastContact int64 `json:"last_contact" xorm:"last_contact"`
+ LastWork int64 `json:"last_work" xorm:"last_work"` // last time the agent did something, this value is used to determine if the agent is still doing work used by the autoscaler
Platform string `json:"platform" xorm:"VARCHAR(100) 'platform'"`
Backend string `json:"backend" xorm:"VARCHAR(100) 'backend'"`
Capacity int32 `json:"capacity" xorm:"capacity"`
diff --git a/server/model/config.go b/server/model/config.go
index ee8cd479e..7103a5999 100644
--- a/server/model/config.go
+++ b/server/model/config.go
@@ -17,15 +17,23 @@ package model
// Config represents a pipeline configuration.
type Config struct {
- ID int64 `json:"-" xorm:"pk autoincr 'config_id'"`
- RepoID int64 `json:"-" xorm:"UNIQUE(s) 'config_repo_id'"`
- Hash string `json:"hash" xorm:"UNIQUE(s) 'config_hash'"`
- Name string `json:"name" xorm:"UNIQUE(s) 'config_name'"`
- Data []byte `json:"data" xorm:"LONGBLOB 'config_data'"`
+ ID int64 `json:"-" xorm:"pk autoincr 'id'"`
+ RepoID int64 `json:"-" xorm:"UNIQUE(s) 'repo_id'"`
+ Hash string `json:"hash" xorm:"UNIQUE(s) 'hash'"`
+ Name string `json:"name" xorm:"UNIQUE(s) 'name'"`
+ Data []byte `json:"data" xorm:"LONGBLOB 'data'"`
} // @name Config
+func (Config) TableName() string {
+ return "configs"
+}
+
// PipelineConfig is the n:n relation between Pipeline and Config.
type PipelineConfig struct {
ConfigID int64 `json:"-" xorm:"UNIQUE(s) NOT NULL 'config_id'"`
PipelineID int64 `json:"-" xorm:"UNIQUE(s) NOT NULL 'pipeline_id'"`
}
+
+func (PipelineConfig) TableName() string {
+ return "pipeline_configs"
+}
diff --git a/server/model/cron.go b/server/model/cron.go
index 6fa213724..cdce73ef3 100644
--- a/server/model/cron.go
+++ b/server/model/cron.go
@@ -17,18 +17,18 @@ package model
import (
"fmt"
- "github.com/robfig/cron"
+ "github.com/gdgvda/cron"
)
type Cron struct {
- ID int64 `json:"id" xorm:"pk autoincr"`
- Name string `json:"name" xorm:"UNIQUE(s) INDEX"`
- RepoID int64 `json:"repo_id" xorm:"repo_id UNIQUE(s) INDEX"`
- CreatorID int64 `json:"creator_id" xorm:"creator_id INDEX"`
- NextExec int64 `json:"next_exec"`
- Schedule string `json:"schedule" xorm:"NOT NULL"` // @weekly, 3min, ...
- Created int64 `json:"created_at" xorm:"created NOT NULL DEFAULT 0"`
- Branch string `json:"branch"`
+ ID int64 `json:"id" xorm:"pk autoincr 'id'"`
+ Name string `json:"name" xorm:"name UNIQUE(s) INDEX"`
+ RepoID int64 `json:"repo_id" xorm:"repo_id UNIQUE(s) INDEX"`
+ CreatorID int64 `json:"creator_id" xorm:"creator_id INDEX"`
+ NextExec int64 `json:"next_exec" xorm:"next_exec"`
+ Schedule string `json:"schedule" xorm:"schedule NOT NULL"` // @weekly, 3min, ...
+ Created int64 `json:"created" xorm:"created NOT NULL DEFAULT 0"`
+ Branch string `json:"branch" xorm:"branch"`
} // @name Cron
// TableName returns the database table name for xorm.
@@ -46,7 +46,7 @@ func (c *Cron) Validate() error {
return fmt.Errorf("schedule is required")
}
- _, err := cron.Parse(c.Schedule)
+ _, err := cron.ParseStandard(c.Schedule)
if err != nil {
return fmt.Errorf("can't parse schedule: %w", err)
}
diff --git a/server/model/feed.go b/server/model/feed.go
index 0ff5296a0..04357fc4e 100644
--- a/server/model/feed.go
+++ b/server/model/feed.go
@@ -17,21 +17,21 @@ package model
// Feed represents an item in the user's feed or timeline.
type Feed struct {
- RepoID int64 `json:"repo_id" xorm:"feed_repo_id"`
- ID int64 `json:"id,omitempty" xorm:"feed_pipeline_id"`
- Number int64 `json:"number,omitempty" xorm:"feed_pipeline_number"`
- Event string `json:"event,omitempty" xorm:"feed_pipeline_event"`
- Status string `json:"status,omitempty" xorm:"feed_pipeline_status"`
- Created int64 `json:"created_at,omitempty" xorm:"feed_pipeline_created"`
- Started int64 `json:"started_at,omitempty" xorm:"feed_pipeline_started"`
- Finished int64 `json:"finished_at,omitempty" xorm:"feed_pipeline_finished"`
- Commit string `json:"commit,omitempty" xorm:"feed_pipeline_commit"`
- Branch string `json:"branch,omitempty" xorm:"feed_pipeline_branch"`
- Ref string `json:"ref,omitempty" xorm:"feed_pipeline_ref"`
- Refspec string `json:"refspec,omitempty" xorm:"feed_pipeline_refspec"`
- Title string `json:"title,omitempty" xorm:"feed_pipeline_title"`
- Message string `json:"message,omitempty" xorm:"feed_pipeline_message"`
- Author string `json:"author,omitempty" xorm:"feed_pipeline_author"`
- Avatar string `json:"author_avatar,omitempty" xorm:"feed_pipeline_avatar"`
- Email string `json:"author_email,omitempty" xorm:"feed_pipeline_email"`
+ RepoID int64 `json:"repo_id" xorm:"repo_id"`
+ ID int64 `json:"id,omitempty" xorm:"pipeline_id"`
+ Number int64 `json:"number,omitempty" xorm:"pipeline_number"`
+ Event string `json:"event,omitempty" xorm:"pipeline_event"`
+ Status string `json:"status,omitempty" xorm:"pipeline_status"`
+ Created int64 `json:"created,omitempty" xorm:"pipeline_created"`
+ Started int64 `json:"started,omitempty" xorm:"pipeline_started"`
+ Finished int64 `json:"finished,omitempty" xorm:"pipeline_finished"`
+ Commit string `json:"commit,omitempty" xorm:"pipeline_commit"`
+ Branch string `json:"branch,omitempty" xorm:"pipeline_branch"`
+ Ref string `json:"ref,omitempty" xorm:"pipeline_ref"`
+ Refspec string `json:"refspec,omitempty" xorm:"pipeline_refspec"`
+ Title string `json:"title,omitempty" xorm:"pipeline_title"`
+ Message string `json:"message,omitempty" xorm:"pipeline_message"`
+ Author string `json:"author,omitempty" xorm:"pipeline_author"`
+ Avatar string `json:"author_avatar,omitempty" xorm:"pipeline_avatar"`
+ Email string `json:"author_email,omitempty" xorm:"pipeline_email"`
} // @name Feed
diff --git a/server/model/forge.go b/server/model/forge.go
index 39a1af292..87854dd3e 100644
--- a/server/model/forge.go
+++ b/server/model/forge.go
@@ -37,6 +37,11 @@ type Forge struct {
AdditionalOptions map[string]any `json:"additional_options,omitempty" xorm:"json"`
} // @name Forge
+// TableName returns the database table name for xorm.
+func (Forge) TableName() string {
+ return "forges"
+}
+
// PublicCopy returns a copy of the forge without sensitive information and technical details.
func (f *Forge) PublicCopy() *Forge {
forge := &Forge{
diff --git a/server/model/log.go b/server/model/log.go
index 1e06c8075..9ac618063 100644
--- a/server/model/log.go
+++ b/server/model/log.go
@@ -28,11 +28,11 @@ const (
type LogEntry struct {
ID int64 `json:"id" xorm:"pk autoincr 'id'"`
StepID int64 `json:"step_id" xorm:"INDEX 'step_id'"`
- Time int64 `json:"time"`
- Line int `json:"line"`
+ Time int64 `json:"time" xorm:"'time'"`
+ Line int `json:"line" xorm:"'line'"`
Data []byte `json:"data" xorm:"LONGBLOB"`
Created int64 `json:"-" xorm:"created"`
- Type LogEntryType `json:"type"`
+ Type LogEntryType `json:"type" xorm:"'type'"`
} // @name LogEntry
// TODO: store info what specific command the line belongs to (must be optional and impl. by backend)
diff --git a/server/model/perm.go b/server/model/perm.go
index d0e7c4339..f25c23812 100644
--- a/server/model/perm.go
+++ b/server/model/perm.go
@@ -17,13 +17,13 @@ package model
// Perm defines a repository permission for an individual user.
type Perm struct {
- UserID int64 `json:"-" xorm:"UNIQUE(s) INDEX NOT NULL 'perm_user_id'"`
- RepoID int64 `json:"-" xorm:"UNIQUE(s) INDEX NOT NULL 'perm_repo_id'"`
+ UserID int64 `json:"-" xorm:"UNIQUE(s) INDEX NOT NULL 'user_id'"`
+ RepoID int64 `json:"-" xorm:"UNIQUE(s) INDEX NOT NULL 'repo_id'"`
Repo *Repo `json:"-" xorm:"-"`
- Pull bool `json:"pull" xorm:"perm_pull"`
- Push bool `json:"push" xorm:"perm_push"`
- Admin bool `json:"admin" xorm:"perm_admin"`
- Synced int64 `json:"synced" xorm:"perm_synced"`
+ Pull bool `json:"pull" xorm:"pull"`
+ Push bool `json:"push" xorm:"push"`
+ Admin bool `json:"admin" xorm:"admin"`
+ Synced int64 `json:"synced" xorm:"synced"`
Created int64 `json:"created" xorm:"created"`
Updated int64 `json:"updated" xorm:"updated"`
} // @name Perm
diff --git a/server/model/pipeline.go b/server/model/pipeline.go
index f2a4557ee..a073ad15f 100644
--- a/server/model/pipeline.go
+++ b/server/model/pipeline.go
@@ -20,50 +20,50 @@ import (
)
type Pipeline struct {
- ID int64 `json:"id" xorm:"pk autoincr 'pipeline_id'"`
- RepoID int64 `json:"-" xorm:"UNIQUE(s) INDEX 'pipeline_repo_id'"`
- Number int64 `json:"number" xorm:"UNIQUE(s) 'pipeline_number'"`
- Author string `json:"author" xorm:"INDEX 'pipeline_author'"`
- Parent int64 `json:"parent" xorm:"pipeline_parent"`
- Event WebhookEvent `json:"event" xorm:"pipeline_event"`
- Status StatusValue `json:"status" xorm:"INDEX 'pipeline_status'"`
- Errors []*types.PipelineError `json:"errors" xorm:"json 'pipeline_errors'"`
- Created int64 `json:"created_at" xorm:"pipeline_created"`
- Updated int64 `json:"updated_at" xorm:"updated NOT NULL DEFAULT 0 'updated'"`
- Started int64 `json:"started_at" xorm:"pipeline_started"`
- Finished int64 `json:"finished_at" xorm:"pipeline_finished"`
- Deploy string `json:"deploy_to" xorm:"pipeline_deploy"`
- DeployTask string `json:"deploy_task" xorm:"pipeline_deploy_task"`
- Commit string `json:"commit" xorm:"pipeline_commit"`
- Branch string `json:"branch" xorm:"pipeline_branch"`
- Ref string `json:"ref" xorm:"pipeline_ref"`
- Refspec string `json:"refspec" xorm:"pipeline_refspec"`
- Title string `json:"title" xorm:"pipeline_title"`
- Message string `json:"message" xorm:"TEXT 'pipeline_message'"`
- Timestamp int64 `json:"timestamp" xorm:"pipeline_timestamp"`
- Sender string `json:"sender" xorm:"pipeline_sender"` // uses reported user for webhooks and name of cron for cron pipelines
- Avatar string `json:"author_avatar" xorm:"pipeline_avatar"`
- Email string `json:"author_email" xorm:"pipeline_email"`
- ForgeURL string `json:"forge_url" xorm:"pipeline_forge_url"`
- Reviewer string `json:"reviewed_by" xorm:"pipeline_reviewer"`
- Reviewed int64 `json:"reviewed_at" xorm:"pipeline_reviewed"`
+ ID int64 `json:"id" xorm:"pk autoincr 'id'"`
+ RepoID int64 `json:"-" xorm:"UNIQUE(s) INDEX 'repo_id'"`
+ Number int64 `json:"number" xorm:"UNIQUE(s) 'number'"`
+ Author string `json:"author" xorm:"INDEX 'author'"`
+ Parent int64 `json:"parent" xorm:"parent"`
+ Event WebhookEvent `json:"event" xorm:"event"`
+ Status StatusValue `json:"status" xorm:"INDEX 'status'"`
+ Errors []*types.PipelineError `json:"errors" xorm:"json 'errors'"`
+ Created int64 `json:"created" xorm:"'created' NOT NULL DEFAULT 0 created"`
+ Updated int64 `json:"updated" xorm:"'updated' NOT NULL DEFAULT 0 updated"`
+ Started int64 `json:"started" xorm:"started"`
+ Finished int64 `json:"finished" xorm:"finished"`
+ DeployTo string `json:"deploy_to" xorm:"deploy"`
+ DeployTask string `json:"deploy_task" xorm:"deploy_task"`
+ Commit string `json:"commit" xorm:"commit"`
+ Branch string `json:"branch" xorm:"branch"`
+ Ref string `json:"ref" xorm:"ref"`
+ Refspec string `json:"refspec" xorm:"refspec"`
+ Title string `json:"title" xorm:"title"`
+ Message string `json:"message" xorm:"TEXT 'message'"`
+ Timestamp int64 `json:"timestamp" xorm:"'timestamp'"`
+ Sender string `json:"sender" xorm:"sender"` // uses reported user for webhooks and name of cron for cron pipelines
+ Avatar string `json:"author_avatar" xorm:"avatar"`
+ Email string `json:"author_email" xorm:"email"`
+ ForgeURL string `json:"forge_url" xorm:"forge_url"`
+ Reviewer string `json:"reviewed_by" xorm:"reviewer"`
+ Reviewed int64 `json:"reviewed" xorm:"reviewed"`
Workflows []*Workflow `json:"workflows,omitempty" xorm:"-"`
ChangedFiles []string `json:"changed_files,omitempty" xorm:"LONGTEXT 'changed_files'"`
AdditionalVariables map[string]string `json:"variables,omitempty" xorm:"json 'additional_variables'"`
PullRequestLabels []string `json:"pr_labels,omitempty" xorm:"json 'pr_labels'"`
- IsPrerelease bool `json:"is_prerelease,omitempty" xorm:"is_prerelease"`
+ IsPrerelease bool `json:"is_prerelease,omitempty" xorm:"is_prerelease"`
} // @name Pipeline
-type PipelineFilter struct {
- Before int64
- After int64
-}
-
// TableName return database table name for xorm.
func (Pipeline) TableName() string {
return "pipelines"
}
+type PipelineFilter struct {
+ Before int64
+ After int64
+}
+
// IsMultiPipeline checks if step list contain more than one parent step.
func (p Pipeline) IsMultiPipeline() bool {
return len(p.Workflows) > 1
diff --git a/server/model/redirection.go b/server/model/redirection.go
index fa780fe17..5cdb8779e 100644
--- a/server/model/redirection.go
+++ b/server/model/redirection.go
@@ -15,7 +15,7 @@
package model
type Redirection struct {
- ID int64 `xorm:"pk autoincr 'redirection_id'"`
+ ID int64 `xorm:"pk autoincr 'id'"`
RepoID int64 `xorm:"'repo_id'"`
FullName string `xorm:"UNIQUE INDEX 'repo_full_name'"`
}
diff --git a/server/model/registry.go b/server/model/registry.go
index e5772b824..20af16fed 100644
--- a/server/model/registry.go
+++ b/server/model/registry.go
@@ -28,13 +28,34 @@ var (
// Registry represents a docker registry with credentials.
type Registry struct {
- ID int64 `json:"id" xorm:"pk autoincr 'registry_id'"`
- RepoID int64 `json:"-" xorm:"UNIQUE(s) INDEX 'registry_repo_id'"`
- Address string `json:"address" xorm:"UNIQUE(s) INDEX 'registry_addr'"`
- Username string `json:"username" xorm:"varchar(2000) 'registry_username'"`
- Password string `json:"password" xorm:"TEXT 'registry_password'"`
+ ID int64 `json:"id" xorm:"pk autoincr 'id'"`
+ OrgID int64 `json:"org_id" xorm:"NOT NULL DEFAULT 0 UNIQUE(s) INDEX 'org_id'"`
+ RepoID int64 `json:"repo_id" xorm:"NOT NULL DEFAULT 0 UNIQUE(s) INDEX 'repo_id'"`
+ Address string `json:"address" xorm:"NOT NULL UNIQUE(s) INDEX 'address'"`
+ Username string `json:"username" xorm:"varchar(2000) 'username'"`
+ Password string `json:"password" xorm:"TEXT 'password'"`
+ ReadOnly bool `json:"readonly" xorm:"-"`
} // @name Registry
+func (r Registry) TableName() string {
+ return "registries"
+}
+
+// Global registry.
+func (r Registry) IsGlobal() bool {
+ return r.RepoID == 0 && r.OrgID == 0
+}
+
+// Organization registry.
+func (r Registry) IsOrganization() bool {
+ return r.RepoID == 0 && r.OrgID != 0
+}
+
+// Repository registry.
+func (r Registry) IsRepository() bool {
+ return r.RepoID != 0 && r.OrgID == 0
+}
+
// Validate validates the registry information.
func (r *Registry) Validate() error {
switch {
@@ -54,8 +75,10 @@ func (r *Registry) Validate() error {
func (r *Registry) Copy() *Registry {
return &Registry{
ID: r.ID,
+ OrgID: r.OrgID,
RepoID: r.RepoID,
Address: r.Address,
Username: r.Username,
+ ReadOnly: r.ReadOnly,
}
}
diff --git a/server/model/repo.go b/server/model/repo.go
index b1e8b19e8..36080f93e 100644
--- a/server/model/repo.go
+++ b/server/model/repo.go
@@ -22,32 +22,32 @@ import (
// Repo represents a repository.
type Repo struct {
- ID int64 `json:"id,omitempty" xorm:"pk autoincr 'repo_id'"`
- UserID int64 `json:"-" xorm:"repo_user_id"`
+ ID int64 `json:"id,omitempty" xorm:"pk autoincr 'id'"`
+ UserID int64 `json:"-" xorm:"INDEX 'user_id'"`
ForgeID int64 `json:"forge_id,omitempty" xorm:"forge_id"`
// ForgeRemoteID is the unique identifier for the repository on the forge.
ForgeRemoteID ForgeRemoteID `json:"forge_remote_id" xorm:"forge_remote_id"`
- OrgID int64 `json:"org_id" xorm:"repo_org_id"`
- Owner string `json:"owner" xorm:"UNIQUE(name) 'repo_owner'"`
- Name string `json:"name" xorm:"UNIQUE(name) 'repo_name'"`
- FullName string `json:"full_name" xorm:"UNIQUE 'repo_full_name'"`
- Avatar string `json:"avatar_url,omitempty" xorm:"varchar(500) 'repo_avatar'"`
- ForgeURL string `json:"forge_url,omitempty" xorm:"varchar(1000) 'repo_forge_url'"`
- Clone string `json:"clone_url,omitempty" xorm:"varchar(1000) 'repo_clone'"`
- CloneSSH string `json:"clone_url_ssh" xorm:"varchar(1000) 'repo_clone_ssh'"`
- Branch string `json:"default_branch,omitempty" xorm:"varchar(500) 'repo_branch'"`
- SCMKind SCMKind `json:"scm,omitempty" xorm:"varchar(50) 'repo_scm'"`
- PREnabled bool `json:"pr_enabled" xorm:"DEFAULT TRUE 'repo_pr_enabled'"`
- Timeout int64 `json:"timeout,omitempty" xorm:"repo_timeout"`
- Visibility RepoVisibility `json:"visibility" xorm:"varchar(10) 'repo_visibility'"`
- IsSCMPrivate bool `json:"private" xorm:"repo_private"`
- IsTrusted bool `json:"trusted" xorm:"repo_trusted"`
- IsGated bool `json:"gated" xorm:"repo_gated"`
- IsActive bool `json:"active" xorm:"repo_active"`
- AllowPull bool `json:"allow_pr" xorm:"repo_allow_pr"`
- AllowDeploy bool `json:"allow_deploy" xorm:"repo_allow_deploy"`
- Config string `json:"config_file" xorm:"varchar(500) 'repo_config_path'"`
- Hash string `json:"-" xorm:"varchar(500) 'repo_hash'"`
+ OrgID int64 `json:"org_id" xorm:"INDEX 'org_id'"`
+ Owner string `json:"owner" xorm:"UNIQUE(name) 'owner'"`
+ Name string `json:"name" xorm:"UNIQUE(name) 'name'"`
+ FullName string `json:"full_name" xorm:"UNIQUE 'full_name'"`
+ Avatar string `json:"avatar_url,omitempty" xorm:"varchar(500) 'avatar'"`
+ ForgeURL string `json:"forge_url,omitempty" xorm:"varchar(1000) 'forge_url'"`
+ Clone string `json:"clone_url,omitempty" xorm:"varchar(1000) 'clone'"`
+ CloneSSH string `json:"clone_url_ssh" xorm:"varchar(1000) 'clone_ssh'"`
+ Branch string `json:"default_branch,omitempty" xorm:"varchar(500) 'branch'"`
+ SCMKind SCMKind `json:"scm,omitempty" xorm:"varchar(50) 'scm'"`
+ PREnabled bool `json:"pr_enabled" xorm:"DEFAULT TRUE 'pr_enabled'"`
+ Timeout int64 `json:"timeout,omitempty" xorm:"timeout"`
+ Visibility RepoVisibility `json:"visibility" xorm:"varchar(10) 'visibility'"`
+ IsSCMPrivate bool `json:"private" xorm:"private"`
+ IsTrusted bool `json:"trusted" xorm:"trusted"`
+ IsGated bool `json:"gated" xorm:"gated"`
+ IsActive bool `json:"active" xorm:"active"`
+ AllowPull bool `json:"allow_pr" xorm:"allow_pr"`
+ AllowDeploy bool `json:"allow_deploy" xorm:"allow_deploy"`
+ Config string `json:"config_file" xorm:"varchar(500) 'config_path'"`
+ Hash string `json:"-" xorm:"varchar(500) 'hash'"`
Perm *Perm `json:"-" xorm:"-"`
CancelPreviousPipelineEvents []WebhookEvent `json:"cancel_previous_pipeline_events" xorm:"json 'cancel_previous_pipeline_events'"`
NetrcOnlyTrusted bool `json:"netrc_only_trusted" xorm:"NOT NULL DEFAULT true 'netrc_only_trusted'"`
diff --git a/server/model/secret.go b/server/model/secret.go
index 327da66b0..d9806145b 100644
--- a/server/model/secret.go
+++ b/server/model/secret.go
@@ -45,13 +45,13 @@ type SecretStore interface {
// Secret represents a secret variable, such as a password or token.
type Secret struct {
- ID int64 `json:"id" xorm:"pk autoincr 'secret_id'"`
- OrgID int64 `json:"org_id" xorm:"NOT NULL DEFAULT 0 UNIQUE(s) INDEX 'secret_org_id'"`
- RepoID int64 `json:"repo_id" xorm:"NOT NULL DEFAULT 0 UNIQUE(s) INDEX 'secret_repo_id'"`
- Name string `json:"name" xorm:"NOT NULL UNIQUE(s) INDEX 'secret_name'"`
- Value string `json:"value,omitempty" xorm:"TEXT 'secret_value'"`
- Images []string `json:"images" xorm:"json 'secret_images'"`
- Events []WebhookEvent `json:"events" xorm:"json 'secret_events'"`
+ ID int64 `json:"id" xorm:"pk autoincr 'id'"`
+ OrgID int64 `json:"org_id" xorm:"NOT NULL DEFAULT 0 UNIQUE(s) INDEX 'org_id'"`
+ RepoID int64 `json:"repo_id" xorm:"NOT NULL DEFAULT 0 UNIQUE(s) INDEX 'repo_id'"`
+ Name string `json:"name" xorm:"NOT NULL UNIQUE(s) INDEX 'name'"`
+ Value string `json:"value,omitempty" xorm:"TEXT 'value'"`
+ Images []string `json:"images" xorm:"json 'images'"`
+ Events []WebhookEvent `json:"events" xorm:"json 'events'"`
} // @name Secret
// TableName return database table name for xorm.
diff --git a/server/model/server_config.go b/server/model/server_config.go
index 2c18bbdfd..ac85b0c86 100644
--- a/server/model/server_config.go
+++ b/server/model/server_config.go
@@ -16,6 +16,11 @@ package model
// ServerConfig represents a key-value pair for storing server configurations.
type ServerConfig struct {
- Key string `json:"key" xorm:"pk"`
- Value string `json:"value" xorm:""`
+ Key string `json:"key" xorm:"pk 'key'"`
+ Value string `json:"value" xorm:"value"`
+}
+
+// TableName return database table name for xorm.
+func (ServerConfig) TableName() string {
+ return "server_configs"
}
diff --git a/server/model/step.go b/server/model/step.go
index 7ceb81300..dba0d3bac 100644
--- a/server/model/step.go
+++ b/server/model/step.go
@@ -26,19 +26,19 @@ const (
// Step represents a process in the pipeline.
type Step struct {
- ID int64 `json:"id" xorm:"pk autoincr 'step_id'"`
- UUID string `json:"uuid" xorm:"INDEX 'step_uuid'"`
- PipelineID int64 `json:"pipeline_id" xorm:"UNIQUE(s) INDEX 'step_pipeline_id'"`
- PID int `json:"pid" xorm:"UNIQUE(s) 'step_pid'"`
- PPID int `json:"ppid" xorm:"step_ppid"`
- Name string `json:"name" xorm:"step_name"`
- State StatusValue `json:"state" xorm:"step_state"`
- Error string `json:"error,omitempty" xorm:"TEXT 'step_error'"`
- Failure string `json:"-" xorm:"step_failure"`
- ExitCode int `json:"exit_code" xorm:"step_exit_code"`
- Started int64 `json:"start_time,omitempty" xorm:"step_started"`
- Stopped int64 `json:"end_time,omitempty" xorm:"step_stopped"`
- Type StepType `json:"type,omitempty" xorm:"step_type"`
+ ID int64 `json:"id" xorm:"pk autoincr 'id'"`
+ UUID string `json:"uuid" xorm:"INDEX 'uuid'"`
+ PipelineID int64 `json:"pipeline_id" xorm:"UNIQUE(s) INDEX 'pipeline_id'"`
+ PID int `json:"pid" xorm:"UNIQUE(s) 'pid'"`
+ PPID int `json:"ppid" xorm:"ppid"`
+ Name string `json:"name" xorm:"name"`
+ State StatusValue `json:"state" xorm:"state"`
+ Error string `json:"error,omitempty" xorm:"TEXT 'error'"`
+ Failure string `json:"-" xorm:"failure"`
+ ExitCode int `json:"exit_code" xorm:"exit_code"`
+ Started int64 `json:"started,omitempty" xorm:"started"`
+ Finished int64 `json:"finished,omitempty" xorm:"finished"`
+ Type StepType `json:"type,omitempty" xorm:"type"`
} // @name Step
// TableName return database table name for xorm.
diff --git a/server/model/task.go b/server/model/task.go
index c9b5a7801..3f73bebed 100644
--- a/server/model/task.go
+++ b/server/model/task.go
@@ -21,12 +21,12 @@ import (
// Task defines scheduled pipeline Task.
type Task struct {
- ID string `json:"id" xorm:"PK UNIQUE 'task_id'"`
- Data []byte `json:"data" xorm:"LONGBLOB 'task_data'"`
- Labels map[string]string `json:"labels" xorm:"json 'task_labels'"`
- Dependencies []string `json:"dependencies" xorm:"json 'task_dependencies'"`
- RunOn []string `json:"run_on" xorm:"json 'task_run_on'"`
- DepStatus map[string]StatusValue `json:"dep_status" xorm:"json 'task_dep_status'"`
+ ID string `json:"id" xorm:"PK UNIQUE 'id'"`
+ Data []byte `json:"-" xorm:"LONGBLOB 'data'"`
+ Labels map[string]string `json:"labels" xorm:"json 'labels'"`
+ Dependencies []string `json:"dependencies" xorm:"json 'dependencies'"`
+ RunOn []string `json:"run_on" xorm:"json 'run_on'"`
+ DepStatus map[string]StatusValue `json:"dep_status" xorm:"json 'dependencies_status'"`
AgentID int64 `json:"agent_id" xorm:"'agent_id'"`
} // @name Task
diff --git a/server/model/user.go b/server/model/user.go
index ff41e9e22..f389be4df 100644
--- a/server/model/user.go
+++ b/server/model/user.go
@@ -32,7 +32,7 @@ type User struct {
// the id for this user.
//
// required: true
- ID int64 `json:"id" xorm:"pk autoincr 'user_id'"`
+ ID int64 `json:"id" xorm:"pk autoincr 'id'"`
ForgeID int64 `json:"forge_id,omitempty" xorm:"forge_id"`
@@ -41,36 +41,36 @@ type User struct {
// Login is the username for this user.
//
// required: true
- Login string `json:"login" xorm:"UNIQUE 'user_login'"`
+ Login string `json:"login" xorm:"UNIQUE 'login'"`
// AccessToken is the oauth2 access token.
- AccessToken string `json:"-" xorm:"TEXT 'user_token'"`
+ AccessToken string `json:"-" xorm:"TEXT 'token'"`
// RefreshToken is the oauth2 refresh token.
- RefreshToken string `json:"-" xorm:"TEXT 'user_secret'"`
+ RefreshToken string `json:"-" xorm:"TEXT 'secret'"`
// Expiry is the AccessToken expiration timestamp (unix seconds).
- Expiry int64 `json:"-" xorm:"user_expiry"`
+ Expiry int64 `json:"-" xorm:"expiry"`
// Email is the email address for this user.
//
// required: true
- Email string `json:"email" xorm:" varchar(500) 'user_email'"`
+ Email string `json:"email" xorm:" varchar(500) 'email'"`
// the avatar url for this user.
- Avatar string `json:"avatar_url" xorm:" varchar(500) 'user_avatar'"`
+ Avatar string `json:"avatar_url" xorm:" varchar(500) 'avatar'"`
// Admin indicates the user is a system administrator.
//
// NOTE: If the username is part of the WOODPECKER_ADMIN
// environment variable, this value will be set to true on login.
- Admin bool `json:"admin,omitempty" xorm:"user_admin"`
+ Admin bool `json:"admin,omitempty" xorm:"admin"`
// Hash is a unique token used to sign tokens.
- Hash string `json:"-" xorm:"UNIQUE varchar(500) 'user_hash'"`
+ Hash string `json:"-" xorm:"UNIQUE varchar(500) 'hash'"`
// OrgID is the of the user as model.Org.
- OrgID int64 `json:"org_id" xorm:"user_org_id"`
+ OrgID int64 `json:"org_id" xorm:"org_id"`
} // @name User
// TableName return database table name for xorm.
diff --git a/server/model/workflow.go b/server/model/workflow.go
index e75b4385a..e6029ab69 100644
--- a/server/model/workflow.go
+++ b/server/model/workflow.go
@@ -17,18 +17,18 @@ package model
// Workflow represents a workflow in the pipeline.
type Workflow struct {
- ID int64 `json:"id" xorm:"pk autoincr 'workflow_id'"`
- PipelineID int64 `json:"pipeline_id" xorm:"UNIQUE(s) INDEX 'workflow_pipeline_id'"`
- PID int `json:"pid" xorm:"UNIQUE(s) 'workflow_pid'"`
- Name string `json:"name" xorm:"workflow_name"`
- State StatusValue `json:"state" xorm:"workflow_state"`
- Error string `json:"error,omitempty" xorm:"TEXT 'workflow_error'"`
- Started int64 `json:"start_time,omitempty" xorm:"workflow_started"`
- Stopped int64 `json:"end_time,omitempty" xorm:"workflow_stopped"`
- AgentID int64 `json:"agent_id,omitempty" xorm:"workflow_agent_id"`
- Platform string `json:"platform,omitempty" xorm:"workflow_platform"`
- Environ map[string]string `json:"environ,omitempty" xorm:"json 'workflow_environ'"`
- AxisID int `json:"-" xorm:"workflow_axis_id"`
+ ID int64 `json:"id" xorm:"pk autoincr 'id'"`
+ PipelineID int64 `json:"pipeline_id" xorm:"UNIQUE(s) INDEX 'pipeline_id'"`
+ PID int `json:"pid" xorm:"UNIQUE(s) 'pid'"`
+ Name string `json:"name" xorm:"name"`
+ State StatusValue `json:"state" xorm:"state"`
+ Error string `json:"error,omitempty" xorm:"TEXT 'error'"`
+ Started int64 `json:"started,omitempty" xorm:"started"`
+ Finished int64 `json:"finished,omitempty" xorm:"finished"`
+ AgentID int64 `json:"agent_id,omitempty" xorm:"agent_id"`
+ Platform string `json:"platform,omitempty" xorm:"platform"`
+ Environ map[string]string `json:"environ,omitempty" xorm:"json 'environ'"`
+ AxisID int `json:"-" xorm:"axis_id"`
Children []*Step `json:"children,omitempty" xorm:"-"`
}
diff --git a/server/pipeline/approve.go b/server/pipeline/approve.go
index 374693a2c..d91840c7d 100644
--- a/server/pipeline/approve.go
+++ b/server/pipeline/approve.go
@@ -16,6 +16,7 @@ package pipeline
import (
"context"
+ "errors"
"fmt"
"github.com/rs/zerolog/log"
@@ -37,7 +38,7 @@ func Approve(ctx context.Context, store store.Store, currentPipeline *model.Pipe
if err != nil {
msg := fmt.Sprintf("failure to load forge for repo '%s'", repo.FullName)
log.Error().Err(err).Str("repo", repo.FullName).Msg(msg)
- return nil, fmt.Errorf(msg)
+ return nil, errors.New(msg)
}
// fetch the pipeline file from the database
@@ -84,7 +85,7 @@ func Approve(ctx context.Context, store store.Store, currentPipeline *model.Pipe
if err != nil {
msg := fmt.Sprintf("failure to createPipelineItems for %s", repo.FullName)
log.Error().Err(err).Msg(msg)
- return nil, fmt.Errorf(msg)
+ return nil, errors.New(msg)
}
// we have no way to link old workflows and steps in database to new engine generated steps,
@@ -100,7 +101,7 @@ func Approve(ctx context.Context, store store.Store, currentPipeline *model.Pipe
if err != nil {
msg := fmt.Sprintf("failure to start pipeline for %s: %v", repo.FullName, err)
log.Error().Err(err).Msg(msg)
- return nil, fmt.Errorf(msg)
+ return nil, errors.New(msg)
}
return currentPipeline, nil
diff --git a/server/pipeline/create.go b/server/pipeline/create.go
index 127c3aa44..0539e8d3c 100644
--- a/server/pipeline/create.go
+++ b/server/pipeline/create.go
@@ -38,7 +38,7 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, pipeline
if err != nil {
msg := fmt.Sprintf("failure to find repo owner via id '%d'", repo.UserID)
log.Error().Err(err).Str("repo", repo.FullName).Msg(msg)
- return nil, fmt.Errorf(msg)
+ return nil, errors.New(msg)
}
if pipeline.Event == model.EventPush || pipeline.Event == model.EventPull || pipeline.Event == model.EventPullClosed {
@@ -57,7 +57,7 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, pipeline
if err != nil {
msg := fmt.Sprintf("failure to load forge for repo '%s'", repo.FullName)
log.Error().Err(err).Str("repo", repo.FullName).Msg(msg)
- return nil, fmt.Errorf(msg)
+ return nil, errors.New(msg)
}
// If the forge has a refresh token, the current access token
@@ -88,13 +88,13 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, pipeline
return nil, ErrFiltered
} else if configFetchErr != nil {
log.Debug().Str("repo", repo.FullName).Err(configFetchErr).Msgf("error while fetching config '%s' in '%s' with user: '%s'", repo.Config, pipeline.Ref, repoUser.Login)
- return nil, updatePipelineWithErr(ctx, _forge, _store, pipeline, repo, repoUser, fmt.Errorf("pipeline definition not found in %s", repo.FullName))
+ return nil, updatePipelineWithErr(ctx, _forge, _store, pipeline, repo, repoUser, fmt.Errorf("could not load config from forge: %w", err))
}
pipelineItems, parseErr := parsePipeline(_forge, _store, pipeline, repoUser, repo, forgeYamlConfigs, nil)
if pipeline_errors.HasBlockingErrors(parseErr) {
log.Debug().Str("repo", repo.FullName).Err(parseErr).Msg("failed to parse yaml")
- return nil, updatePipelineWithErr(ctx, _forge, _store, pipeline, repo, repoUser, parseErr)
+ return pipeline, updatePipelineWithErr(ctx, _forge, _store, pipeline, repo, repoUser, parseErr)
} else if parseErr != nil {
pipeline.Errors = pipeline_errors.GetPipelineErrors(parseErr)
}
@@ -117,7 +117,7 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, pipeline
if err != nil {
msg := fmt.Sprintf("failed to find or persist pipeline config for %s", repo.FullName)
log.Error().Err(err).Msg(msg)
- return nil, fmt.Errorf(msg)
+ return nil, errors.New(msg)
}
configs = append(configs, config)
}
@@ -125,7 +125,7 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, pipeline
if err := linkPipelineConfigs(_store, configs, pipeline.ID); err != nil {
msg := fmt.Sprintf("failed to find or persist pipeline config for %s", repo.FullName)
log.Error().Err(err).Msg(msg)
- return nil, fmt.Errorf(msg)
+ return nil, errors.New(msg)
}
if err := prepareStart(ctx, _forge, _store, pipeline, repoUser, repo); err != nil {
@@ -145,7 +145,7 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, pipeline
if err != nil {
msg := fmt.Sprintf("failed to start pipeline for %s", repo.FullName)
log.Error().Err(err).Msg(msg)
- return nil, fmt.Errorf(msg)
+ return nil, errors.New(msg)
}
return pipeline, nil
diff --git a/server/pipeline/decline.go b/server/pipeline/decline.go
index 1f9611c5c..a4f7e48a3 100644
--- a/server/pipeline/decline.go
+++ b/server/pipeline/decline.go
@@ -16,6 +16,7 @@ package pipeline
import (
"context"
+ "errors"
"fmt"
"github.com/rs/zerolog/log"
@@ -31,7 +32,7 @@ func Decline(ctx context.Context, store store.Store, pipeline *model.Pipeline, u
if err != nil {
msg := fmt.Sprintf("failure to load forge for repo '%s'", repo.FullName)
log.Error().Err(err).Str("repo", repo.FullName).Msg(msg)
- return nil, fmt.Errorf(msg)
+ return nil, errors.New(msg)
}
if pipeline.Status != model.StatusBlocked {
diff --git a/server/pipeline/items.go b/server/pipeline/items.go
index 92f59af7e..b6b2dc917 100644
--- a/server/pipeline/items.go
+++ b/server/pipeline/items.go
@@ -44,13 +44,13 @@ func parsePipeline(forge forge.Forge, store store.Store, currentPipeline *model.
}
secretService := server.Config.Services.Manager.SecretServiceFromRepo(repo)
- secs, err := secretService.SecretListPipeline(repo, currentPipeline, &model.ListOptions{All: true})
+ secs, err := secretService.SecretListPipeline(repo, currentPipeline)
if err != nil {
log.Error().Err(err).Msgf("error getting secrets for %s#%d", repo.FullName, currentPipeline.Number)
}
registryService := server.Config.Services.Manager.RegistryServiceFromRepo(repo)
- regs, err := registryService.RegistryList(repo, &model.ListOptions{All: true})
+ regs, err := registryService.RegistryListPipeline(repo, currentPipeline)
if err != nil {
log.Error().Err(err).Msgf("error getting registry credentials for %s#%d", repo.FullName, currentPipeline.Number)
}
diff --git a/server/pipeline/restart.go b/server/pipeline/restart.go
index e8b841bf1..3c997a290 100644
--- a/server/pipeline/restart.go
+++ b/server/pipeline/restart.go
@@ -33,13 +33,11 @@ func Restart(ctx context.Context, store store.Store, lastPipeline *model.Pipelin
if err != nil {
msg := fmt.Sprintf("failure to load forge for repo '%s'", repo.FullName)
log.Error().Err(err).Str("repo", repo.FullName).Msg(msg)
- return nil, fmt.Errorf(msg)
+ return nil, errors.New(msg)
}
- switch lastPipeline.Status {
- case model.StatusDeclined,
- model.StatusBlocked:
- return nil, &ErrBadRequest{Msg: fmt.Sprintf("cannot restart a pipeline with status %s", lastPipeline.Status)}
+ if lastPipeline.Status == model.StatusBlocked {
+ return nil, &ErrBadRequest{Msg: "cannot restart a pipeline with status blocked"}
}
// fetch the old pipeline config from the database
@@ -70,7 +68,7 @@ func Restart(ctx context.Context, store store.Store, lastPipeline *model.Pipelin
if err != nil {
msg := fmt.Sprintf("failure to save pipeline for %s", repo.FullName)
log.Error().Err(err).Msg(msg)
- return nil, fmt.Errorf(msg)
+ return nil, errors.New(msg)
}
if len(configs) == 0 {
@@ -85,27 +83,27 @@ func Restart(ctx context.Context, store store.Store, lastPipeline *model.Pipelin
if err := linkPipelineConfigs(store, configs, newPipeline.ID); err != nil {
msg := fmt.Sprintf("failure to persist pipeline config for %s.", repo.FullName)
log.Error().Err(err).Msg(msg)
- return nil, fmt.Errorf(msg)
+ return nil, errors.New(msg)
}
newPipeline, pipelineItems, err := createPipelineItems(ctx, forge, store, newPipeline, user, repo, pipelineFiles, envs)
if err != nil {
msg := fmt.Sprintf("failure to createPipelineItems for %s", repo.FullName)
log.Error().Err(err).Msg(msg)
- return nil, fmt.Errorf(msg)
+ return nil, errors.New(msg)
}
if err := prepareStart(ctx, forge, store, newPipeline, user, repo); err != nil {
msg := fmt.Sprintf("failure to prepare pipeline for %s", repo.FullName)
log.Error().Err(err).Msg(msg)
- return nil, fmt.Errorf(msg)
+ return nil, errors.New(msg)
}
newPipeline, err = start(ctx, forge, store, newPipeline, user, repo, pipelineItems)
if err != nil {
msg := fmt.Sprintf("failure to start pipeline for %s", repo.FullName)
log.Error().Err(err).Msg(msg)
- return nil, fmt.Errorf(msg)
+ return nil, errors.New(msg)
}
return newPipeline, nil
diff --git a/server/pipeline/step_status.go b/server/pipeline/step_status.go
index 4fb869fcc..8ee5b83ba 100644
--- a/server/pipeline/step_status.go
+++ b/server/pipeline/step_status.go
@@ -24,9 +24,9 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/server/store"
)
-func UpdateStepStatus(store store.Store, step *model.Step, state rpc.State) error {
+func UpdateStepStatus(store store.Store, step *model.Step, state rpc.StepState) error {
if state.Exited {
- step.Stopped = state.Finished
+ step.Finished = state.Finished
step.ExitCode = state.ExitCode
step.Error = state.Error
step.State = model.StatusSuccess
@@ -36,30 +36,30 @@ func UpdateStepStatus(store store.Store, step *model.Step, state rpc.State) erro
if state.ExitCode == pipeline.ExitCodeKilled {
step.State = model.StatusKilled
}
- } else if step.Stopped == 0 {
+ } else if step.Finished == 0 {
step.Started = state.Started
step.State = model.StatusRunning
}
return store.StepUpdate(step)
}
-func UpdateStepToStatusStarted(store store.Store, step model.Step, state rpc.State) (*model.Step, error) {
+func UpdateStepToStatusStarted(store store.Store, step model.Step, state rpc.StepState) (*model.Step, error) {
step.Started = state.Started
step.State = model.StatusRunning
return &step, store.StepUpdate(&step)
}
-func UpdateStepToStatusSkipped(store store.Store, step model.Step, stopped int64) (*model.Step, error) {
+func UpdateStepToStatusSkipped(store store.Store, step model.Step, finished int64) (*model.Step, error) {
step.State = model.StatusSkipped
if step.Started != 0 {
step.State = model.StatusSuccess // for daemons that are killed
- step.Stopped = stopped
+ step.Finished = finished
}
return &step, store.StepUpdate(&step)
}
-func UpdateStepStatusToDone(store store.Store, step model.Step, state rpc.State) (*model.Step, error) {
- step.Stopped = state.Finished
+func UpdateStepStatusToDone(store store.Store, step model.Step, state rpc.StepState) (*model.Step, error) {
+ step.Finished = state.Finished
step.Error = state.Error
step.ExitCode = state.ExitCode
if state.Started == 0 {
@@ -75,9 +75,9 @@ func UpdateStepStatusToDone(store store.Store, step model.Step, state rpc.State)
func UpdateStepToStatusKilled(store store.Store, step model.Step) (*model.Step, error) {
step.State = model.StatusKilled
- step.Stopped = time.Now().Unix()
+ step.Finished = time.Now().Unix()
if step.Started == 0 {
- step.Started = step.Stopped
+ step.Started = step.Finished
}
step.ExitCode = pipeline.ExitCodeKilled
return &step, store.StepUpdate(&step)
diff --git a/server/pipeline/step_status_test.go b/server/pipeline/step_status_test.go
index 9ac124d99..c2e9564cf 100644
--- a/server/pipeline/step_status_test.go
+++ b/server/pipeline/step_status_test.go
@@ -41,7 +41,7 @@ func TestUpdateStepStatusNotExited(t *testing.T) {
step := &model.Step{}
// advertised step status
- state := rpc.State{
+ state := rpc.StepState{
Started: int64(42),
Exited: false,
// Dummy data
@@ -54,7 +54,7 @@ func TestUpdateStepStatusNotExited(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, model.StatusRunning, step.State)
assert.EqualValues(t, 42, step.Started)
- assert.EqualValues(t, 0, step.Stopped)
+ assert.EqualValues(t, 0, step.Finished)
assert.EqualValues(t, 0, step.ExitCode)
assert.EqualValues(t, "", step.Error)
}
@@ -63,10 +63,10 @@ func TestUpdateStepStatusNotExitedButStopped(t *testing.T) {
t.Parallel()
// step in db before update
- step := &model.Step{Started: 42, Stopped: 64, State: model.StatusKilled}
+ step := &model.Step{Started: 42, Finished: 64, State: model.StatusKilled}
// advertised step status
- state := rpc.State{
+ state := rpc.StepState{
Exited: false,
// Dummy data
Finished: int64(1),
@@ -78,7 +78,7 @@ func TestUpdateStepStatusNotExitedButStopped(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, model.StatusKilled, step.State)
assert.EqualValues(t, 42, step.Started)
- assert.EqualValues(t, 64, step.Stopped)
+ assert.EqualValues(t, 64, step.Finished)
assert.EqualValues(t, 0, step.ExitCode)
assert.EqualValues(t, "", step.Error)
}
@@ -90,7 +90,7 @@ func TestUpdateStepStatusExited(t *testing.T) {
step := &model.Step{Started: 42}
// advertised step status
- state := rpc.State{
+ state := rpc.StepState{
Started: int64(42),
Exited: true,
Finished: int64(34),
@@ -102,7 +102,7 @@ func TestUpdateStepStatusExited(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, model.StatusKilled, step.State)
assert.EqualValues(t, 42, step.Started)
- assert.EqualValues(t, 34, step.Stopped)
+ assert.EqualValues(t, 34, step.Finished)
assert.EqualValues(t, pipeline.ExitCodeKilled, step.ExitCode)
assert.EqualValues(t, "an error", step.Error)
}
@@ -114,7 +114,7 @@ func TestUpdateStepStatusExitedButNot137(t *testing.T) {
step := &model.Step{Started: 42}
// advertised step status
- state := rpc.State{
+ state := rpc.StepState{
Started: int64(42),
Exited: true,
Finished: int64(34),
@@ -125,7 +125,7 @@ func TestUpdateStepStatusExitedButNot137(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, model.StatusFailure, step.State)
assert.EqualValues(t, 42, step.Started)
- assert.EqualValues(t, 34, step.Stopped)
+ assert.EqualValues(t, 34, step.Finished)
assert.EqualValues(t, 0, step.ExitCode)
assert.EqualValues(t, "an error", step.Error)
}
@@ -134,7 +134,7 @@ func TestUpdateStepStatusExitedWithCode(t *testing.T) {
t.Parallel()
// advertised step status
- state := rpc.State{
+ state := rpc.StepState{
Started: int64(42),
Exited: true,
Finished: int64(34),
@@ -149,10 +149,10 @@ func TestUpdateStepStatusExitedWithCode(t *testing.T) {
assert.Equal(t, 1, step.ExitCode)
}
-func TestUpdateStepPToStatusStarted(t *testing.T) {
+func TestUpdateStepToStatusStarted(t *testing.T) {
t.Parallel()
- state := rpc.State{Started: int64(42)}
+ state := rpc.StepState{Started: int64(42)}
step, _ := UpdateStepToStatusStarted(mockStoreStep(t), model.Step{}, state)
assert.Equal(t, model.StatusRunning, step.State)
@@ -165,7 +165,7 @@ func TestUpdateStepToStatusSkipped(t *testing.T) {
step, _ := UpdateStepToStatusSkipped(mockStoreStep(t), model.Step{}, int64(1))
assert.Equal(t, model.StatusSkipped, step.State)
- assert.EqualValues(t, 0, step.Stopped)
+ assert.EqualValues(t, 0, step.Finished)
}
func TestUpdateStepToStatusSkippedButStarted(t *testing.T) {
@@ -178,20 +178,20 @@ func TestUpdateStepToStatusSkippedButStarted(t *testing.T) {
step, _ = UpdateStepToStatusSkipped(mockStoreStep(t), *step, int64(1))
assert.Equal(t, model.StatusSuccess, step.State)
- assert.EqualValues(t, 1, step.Stopped)
+ assert.EqualValues(t, 1, step.Finished)
}
func TestUpdateStepStatusToDoneSkipped(t *testing.T) {
t.Parallel()
- state := rpc.State{
+ state := rpc.StepState{
Finished: int64(34),
}
step, _ := UpdateStepStatusToDone(mockStoreStep(t), model.Step{}, state)
assert.Equal(t, model.StatusSkipped, step.State)
- assert.EqualValues(t, 34, step.Stopped)
+ assert.EqualValues(t, 34, step.Finished)
assert.Empty(t, step.Error)
assert.Equal(t, 0, step.ExitCode)
}
@@ -199,7 +199,7 @@ func TestUpdateStepStatusToDoneSkipped(t *testing.T) {
func TestUpdateStepStatusToDoneSuccess(t *testing.T) {
t.Parallel()
- state := rpc.State{
+ state := rpc.StepState{
Started: int64(42),
Finished: int64(34),
}
@@ -207,7 +207,7 @@ func TestUpdateStepStatusToDoneSuccess(t *testing.T) {
step, _ := UpdateStepStatusToDone(mockStoreStep(t), model.Step{}, state)
assert.Equal(t, model.StatusSuccess, step.State)
- assert.EqualValues(t, 34, step.Stopped)
+ assert.EqualValues(t, 34, step.Finished)
assert.Empty(t, step.Error)
assert.Equal(t, 0, step.ExitCode)
}
@@ -215,7 +215,7 @@ func TestUpdateStepStatusToDoneSuccess(t *testing.T) {
func TestUpdateStepStatusToDoneFailureWithError(t *testing.T) {
t.Parallel()
- state := rpc.State{Error: "an error"}
+ state := rpc.StepState{Error: "an error"}
step, _ := UpdateStepStatusToDone(mockStoreStep(t), model.Step{}, state)
@@ -225,7 +225,7 @@ func TestUpdateStepStatusToDoneFailureWithError(t *testing.T) {
func TestUpdateStepStatusToDoneFailureWithExitCode(t *testing.T) {
t.Parallel()
- state := rpc.State{ExitCode: 43}
+ state := rpc.StepState{ExitCode: 43}
step, _ := UpdateStepStatusToDone(mockStoreStep(t), model.Step{}, state)
@@ -240,8 +240,8 @@ func TestUpdateStepToStatusKilledStarted(t *testing.T) {
step, _ := UpdateStepToStatusKilled(mockStoreStep(t), model.Step{})
assert.Equal(t, model.StatusKilled, step.State)
- assert.LessOrEqual(t, now, step.Stopped)
- assert.Equal(t, step.Stopped, step.Started)
+ assert.LessOrEqual(t, now, step.Finished)
+ assert.Equal(t, step.Finished, step.Started)
assert.Equal(t, 137, step.ExitCode)
}
diff --git a/server/pipeline/stepbuilder/metadata.go b/server/pipeline/stepbuilder/metadata.go
index 2e2a3c106..3ea13f9e4 100644
--- a/server/pipeline/stepbuilder/metadata.go
+++ b/server/pipeline/stepbuilder/metadata.go
@@ -48,6 +48,7 @@ func MetadataFromStruct(forge metadata.ServerForge, repo *model.Repo, pipeline,
Owner: repo.Owner,
RemoteID: fmt.Sprint(repo.ForgeRemoteID),
ForgeURL: repo.ForgeURL,
+ SCM: string(repo.SCMKind),
CloneURL: repo.Clone,
CloneSSHURL: repo.CloneSSH,
Private: repo.IsSCMPrivate,
@@ -107,15 +108,16 @@ func metadataPipelineFromModelPipeline(pipeline *model.Pipeline, includeParent b
}
return metadata.Pipeline{
- Number: pipeline.Number,
- Parent: parent,
- Created: pipeline.Created,
- Started: pipeline.Started,
- Finished: pipeline.Finished,
- Status: string(pipeline.Status),
- Event: string(pipeline.Event),
- ForgeURL: pipeline.ForgeURL,
- Target: pipeline.Deploy,
+ Number: pipeline.Number,
+ Parent: parent,
+ Created: pipeline.Created,
+ Started: pipeline.Started,
+ Finished: pipeline.Finished,
+ Status: string(pipeline.Status),
+ Event: string(pipeline.Event),
+ ForgeURL: pipeline.ForgeURL,
+ DeployTo: pipeline.DeployTo,
+ DeployTask: pipeline.DeployTask,
Commit: metadata.Commit{
Sha: pipeline.Commit,
Ref: pipeline.Ref,
diff --git a/server/pipeline/stepbuilder/metadata_test.go b/server/pipeline/stepbuilder/metadata_test.go
index a0d451425..368eae47e 100644
--- a/server/pipeline/stepbuilder/metadata_test.go
+++ b/server/pipeline/stepbuilder/metadata_test.go
@@ -46,22 +46,22 @@ func TestMetadataFromStruct(t *testing.T) {
"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_COMMIT_URL": "", "CI_FORGE_TYPE": "", "CI_FORGE_URL": "",
- "CI_PIPELINE_CREATED": "0", "CI_PIPELINE_DEPLOY_TARGET": "", "CI_PIPELINE_DEPLOY_TASK": "", "CI_PIPELINE_EVENT": "", "CI_PIPELINE_FINISHED": "0", "CI_PIPELINE_FILES": "[]", "CI_PIPELINE_NUMBER": "0",
- "CI_PIPELINE_PARENT": "0", "CI_PIPELINE_STARTED": "0", "CI_PIPELINE_STATUS": "", "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_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": "git", "CI_REPO_TRUSTED": "false", "CI_REPO_URL": "", "CI_STEP_FINISHED": "",
- "CI_STEP_NAME": "", "CI_STEP_NUMBER": "0", "CI_STEP_STARTED": "", "CI_STEP_STATUS": "", "CI_STEP_URL": "/repos/0/pipeline/0", "CI_SYSTEM_HOST": "", "CI_SYSTEM_NAME": "woodpecker",
+ "CI_REPO_NAME": "", "CI_REPO_OWNER": "", "CI_REPO_PRIVATE": "false", "CI_REPO_SCM": "", "CI_REPO_TRUSTED": "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",
},
},
{
name: "Test with forge",
forge: forge,
- repo: &model.Repo{FullName: "testUser/testRepo", ForgeURL: "https://gitea.com/testUser/testRepo", Clone: "https://gitea.com/testUser/testRepo.git", CloneSSH: "git@gitea.com:testUser/testRepo.git", Branch: "main", IsSCMPrivate: true},
+ repo: &model.Repo{FullName: "testUser/testRepo", ForgeURL: "https://gitea.com/testUser/testRepo", Clone: "https://gitea.com/testUser/testRepo.git", CloneSSH: "git@gitea.com:testUser/testRepo.git", Branch: "main", IsSCMPrivate: true, SCMKind: "git"},
pipeline: &model.Pipeline{Number: 3, ChangedFiles: []string{"test.go", "markdown file.md"}},
last: &model.Pipeline{Number: 2},
workflow: &model.Workflow{Name: "hello"},
@@ -69,7 +69,7 @@ func TestMetadataFromStruct(t *testing.T) {
expectedMetadata: metadata.Metadata{
Forge: metadata.Forge{Type: "gitea", URL: "https://gitea.com"},
Sys: metadata.System{Name: "woodpecker", Host: "example.com", URL: "https://example.com"},
- Repo: metadata.Repo{Owner: "testUser", Name: "testRepo", ForgeURL: "https://gitea.com/testUser/testRepo", CloneURL: "https://gitea.com/testUser/testRepo.git", CloneSSHURL: "git@gitea.com:testUser/testRepo.git", Branch: "main", Private: true},
+ Repo: metadata.Repo{Owner: "testUser", Name: "testRepo", ForgeURL: "https://gitea.com/testUser/testRepo", CloneURL: "https://gitea.com/testUser/testRepo.git", CloneSSHURL: "git@gitea.com:testUser/testRepo.git", Branch: "main", Private: true, SCM: "git"},
Curr: metadata.Pipeline{
Number: 3,
Commit: metadata.Commit{ChangedFiles: []string{"test.go", "markdown file.md"}},
@@ -81,16 +81,16 @@ func TestMetadataFromStruct(t *testing.T) {
"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_COMMIT_URL": "", "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_FINISHED": "0", "CI_PIPELINE_FILES": `["test.go","markdown file.md"]`,
- "CI_PIPELINE_NUMBER": "3", "CI_PIPELINE_PARENT": "0", "CI_PIPELINE_STARTED": "0", "CI_PIPELINE_STATUS": "", "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_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_URL": "https://gitea.com/testUser/testRepo", "CI_STEP_FINISHED": "",
- "CI_STEP_NAME": "", "CI_STEP_NUMBER": "0", "CI_STEP_STARTED": "", "CI_STEP_STATUS": "", "CI_STEP_URL": "https://example.com/repos/0/pipeline/3", "CI_SYSTEM_HOST": "example.com",
+ "CI_REPO_SCM": "git", "CI_REPO_TRUSTED": "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",
},
},
diff --git a/server/pipeline/stepbuilder/stepBuilder.go b/server/pipeline/stepbuilder/stepBuilder.go
index 586fad595..aeb91a25a 100644
--- a/server/pipeline/stepbuilder/stepBuilder.go
+++ b/server/pipeline/stepbuilder/stepBuilder.go
@@ -142,6 +142,8 @@ func (b *StepBuilder) genItemForWorkflow(workflow *model.Workflow, axis matrix.A
// lint pipeline
errorsAndWarnings = multierr.Append(errorsAndWarnings, linter.New(
linter.WithTrusted(b.Repo.IsTrusted),
+ linter.PrivilegedPlugins(server.Config.Pipeline.PrivilegedPlugins),
+ linter.WithTrustedClonePlugins(server.Config.Pipeline.TrustedClonePlugins),
).Lint([]*linter.WorkflowConfig{{
Workflow: parsed,
File: workflow.Name,
@@ -267,7 +269,7 @@ func (b *StepBuilder) toInternalRepresentation(parsed *yaml_types.Workflow, envi
compiler.WithEnviron(environ),
compiler.WithEnviron(b.Envs),
// TODO: server deps should be moved into StepBuilder fields and set on StepBuilder creation
- compiler.WithEscalated(server.Config.Pipeline.Privileged...),
+ compiler.WithEscalated(server.Config.Pipeline.PrivilegedPlugins...),
compiler.WithResourceLimit(server.Config.Pipeline.Limits.MemSwapLimit, server.Config.Pipeline.Limits.MemLimit, server.Config.Pipeline.Limits.ShmSize, server.Config.Pipeline.Limits.CPUQuota, server.Config.Pipeline.Limits.CPUShares, server.Config.Pipeline.Limits.CPUSet),
compiler.WithVolumes(server.Config.Pipeline.Volumes...),
compiler.WithNetworks(server.Config.Pipeline.Networks...),
@@ -280,7 +282,8 @@ func (b *StepBuilder) toInternalRepresentation(parsed *yaml_types.Workflow, envi
),
b.Repo.IsSCMPrivate || server.Config.Pipeline.AuthenticatePublicRepos,
),
- compiler.WithDefaultCloneImage(server.Config.Pipeline.DefaultCloneImage),
+ compiler.WithDefaultClonePlugin(server.Config.Pipeline.DefaultClonePlugin),
+ compiler.WithTrustedClonePlugins(server.Config.Pipeline.TrustedClonePlugins),
compiler.WithRegistry(registries...),
compiler.WithSecret(secrets...),
compiler.WithPrefix(
@@ -291,7 +294,7 @@ func (b *StepBuilder) toInternalRepresentation(parsed *yaml_types.Workflow, envi
),
),
compiler.WithProxy(b.ProxyOpts),
- compiler.WithWorkspaceFromURL("/woodpecker", b.Repo.ForgeURL),
+ compiler.WithWorkspaceFromURL(compiler.DefaultWorkspaceBase, b.Repo.ForgeURL),
compiler.WithMetadata(metadata),
compiler.WithTrusted(b.Repo.IsTrusted),
compiler.WithNetrcOnlyTrusted(b.Repo.NetrcOnlyTrusted),
diff --git a/server/pipeline/stepbuilder/stepBuilder_test.go b/server/pipeline/stepbuilder/stepBuilder_test.go
index 98cb79129..ae86ba35f 100644
--- a/server/pipeline/stepbuilder/stepBuilder_test.go
+++ b/server/pipeline/stepbuilder/stepBuilder_test.go
@@ -348,10 +348,10 @@ func TestBranchFilter(t *testing.T) {
{Data: []byte(`
when:
event: push
+ branch: main
steps:
xxx:
image: scratch
-branches: main
`)},
{Data: []byte(`
when:
diff --git a/server/pipeline/workflowStatus.go b/server/pipeline/workflow_status.go
similarity index 86%
rename from server/pipeline/workflowStatus.go
rename to server/pipeline/workflow_status.go
index f29105ebd..a99ef8ddd 100644
--- a/server/pipeline/workflowStatus.go
+++ b/server/pipeline/workflow_status.go
@@ -20,7 +20,7 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/server/store"
)
-func UpdateWorkflowToStatusStarted(store store.Store, workflow model.Workflow, state rpc.State) (*model.Workflow, error) {
+func UpdateWorkflowStatusToRunning(store store.Store, workflow model.Workflow, state rpc.WorkflowState) (*model.Workflow, error) {
workflow.Started = state.Started
workflow.State = model.StatusRunning
return &workflow, store.WorkflowUpdate(&workflow)
@@ -31,8 +31,8 @@ func UpdateWorkflowToStatusSkipped(store store.Store, workflow model.Workflow) (
return &workflow, store.WorkflowUpdate(&workflow)
}
-func UpdateWorkflowStatusToDone(store store.Store, workflow model.Workflow, state rpc.State) (*model.Workflow, error) {
- workflow.Stopped = state.Finished
+func UpdateWorkflowStatusToDone(store store.Store, workflow model.Workflow, state rpc.WorkflowState) (*model.Workflow, error) {
+ workflow.Finished = state.Finished
workflow.Error = state.Error
if state.Started == 0 {
workflow.State = model.StatusSkipped
diff --git a/server/queue/fifo.go b/server/queue/fifo.go
index d6fe664c9..5e5a17edd 100644
--- a/server/queue/fifo.go
+++ b/server/queue/fifo.go
@@ -24,6 +24,7 @@ import (
"github.com/rs/zerolog/log"
"go.woodpecker-ci.org/woodpecker/v2/server/model"
+ "go.woodpecker-ci.org/woodpecker/v2/shared/constant"
)
type entry struct {
@@ -43,6 +44,7 @@ type worker struct {
type fifo struct {
sync.Mutex
+ ctx context.Context
workers map[*worker]struct{}
running map[string]*entry
pending *list.List
@@ -51,18 +53,23 @@ type fifo struct {
paused bool
}
+// processTimeInterval is the time till the queue rearranges things,
+// as the agent pull in 10 milliseconds we should also give them work asap.
+const processTimeInterval = 100 * time.Millisecond
+
// New returns a new fifo queue.
-//
-//nolint:mnd
-func New(_ context.Context) Queue {
- return &fifo{
+func New(ctx context.Context) Queue {
+ q := &fifo{
+ ctx: ctx,
workers: map[*worker]struct{}{},
running: map[string]*entry{},
pending: list.New(),
waitingOnDeps: list.New(),
- extension: time.Minute * 10,
+ extension: constant.TaskTimeout,
paused: false,
}
+ go q.process()
+ return q
}
// Push pushes a task to the tail of this queue.
@@ -70,7 +77,6 @@ func (q *fifo) Push(_ context.Context, task *model.Task) error {
q.Lock()
q.pending.PushBack(task)
q.Unlock()
- go q.process()
return nil
}
@@ -81,7 +87,6 @@ func (q *fifo) PushAtOnce(_ context.Context, tasks []*model.Task) error {
q.pending.PushBack(task)
}
q.Unlock()
- go q.process()
return nil
}
@@ -98,7 +103,6 @@ func (q *fifo) Poll(c context.Context, agentID int64, f FilterFn) (*model.Task,
}
q.workers[w] = struct{}{}
q.Unlock()
- go q.process()
for {
select {
@@ -237,7 +241,6 @@ func (q *fifo) Resume() {
q.Lock()
q.paused = false
q.Unlock()
- go q.process()
}
// KickAgentWorkers kicks all workers for a given agent.
@@ -254,28 +257,36 @@ func (q *fifo) KickAgentWorkers(agentID int64) {
}
// helper function that loops through the queue and attempts to
-// match the item to a single subscriber.
+// match the item to a single subscriber until context got cancel.
func (q *fifo) process() {
- q.Lock()
- defer q.Unlock()
-
- if q.paused {
- return
- }
-
- q.resubmitExpiredPipelines()
- q.filterWaiting()
- for pending, worker := q.assignToWorker(); pending != nil && worker != nil; pending, worker = q.assignToWorker() {
- task, _ := pending.Value.(*model.Task)
- task.AgentID = worker.agentID
- delete(q.workers, worker)
- q.pending.Remove(pending)
- q.running[task.ID] = &entry{
- item: task,
- done: make(chan bool),
- deadline: time.Now().Add(q.extension),
+ for {
+ select {
+ case <-time.After(processTimeInterval):
+ case <-q.ctx.Done():
+ return
}
- worker.channel <- task
+
+ q.Lock()
+ if q.paused {
+ q.Unlock()
+ continue
+ }
+
+ q.resubmitExpiredPipelines()
+ q.filterWaiting()
+ for pending, worker := q.assignToWorker(); pending != nil && worker != nil; pending, worker = q.assignToWorker() {
+ task, _ := pending.Value.(*model.Task)
+ task.AgentID = worker.agentID
+ delete(q.workers, worker)
+ q.pending.Remove(pending)
+ q.running[task.ID] = &entry{
+ item: task,
+ done: make(chan bool),
+ deadline: time.Now().Add(q.extension),
+ }
+ worker.channel <- task
+ }
+ q.Unlock()
}
}
diff --git a/server/queue/fifo_test.go b/server/queue/fifo_test.go
index d1d3a2ebc..0de92e3f2 100644
--- a/server/queue/fifo_test.go
+++ b/server/queue/fifo_test.go
@@ -52,17 +52,23 @@ func TestFifo(t *testing.T) {
func TestFifoExpire(t *testing.T) {
want := &model.Task{ID: "1"}
+ ctx, cancel := context.WithCancelCause(context.Background())
- q, _ := New(context.Background()).(*fifo)
+ q, _ := New(ctx).(*fifo)
q.extension = 0
- assert.NoError(t, q.Push(noContext, want))
- info := q.Info(noContext)
+ assert.NoError(t, q.Push(ctx, want))
+ info := q.Info(ctx)
assert.Len(t, info.Pending, 1, "expect task in pending queue")
- got, err := q.Poll(noContext, 1, func(*model.Task) bool { return true })
+ got, err := q.Poll(ctx, 1, func(*model.Task) bool { return true })
assert.NoError(t, err)
assert.Equal(t, want, got)
+ // cancel the context to let the process func end
+ go func() {
+ time.Sleep(time.Millisecond)
+ cancel(nil)
+ }()
q.process()
assert.Len(t, info.Pending, 1, "expect task re-added to pending queue")
}
diff --git a/server/queue/persistent.go b/server/queue/persistent.go
index 96d9fff9f..e87f7c7b2 100644
--- a/server/queue/persistent.go
+++ b/server/queue/persistent.go
@@ -27,9 +27,9 @@ import (
// WithTaskStore returns a queue that is backed by the TaskStore. This
// ensures the task Queue can be restored when the system starts.
-func WithTaskStore(q Queue, s store.Store) Queue {
+func WithTaskStore(ctx context.Context, q Queue, s store.Store) Queue {
tasks, _ := s.TaskList()
- if err := q.PushAtOnce(context.Background(), tasks); err != nil {
+ if err := q.PushAtOnce(ctx, tasks); err != nil {
log.Error().Err(err).Msg("PushAtOnce failed")
}
return &persistentQueue{q, s}
diff --git a/server/router/api.go b/server/router/api.go
index b433c7c61..a7c9f8f5e 100644
--- a/server/router/api.go
+++ b/server/router/api.go
@@ -15,8 +15,6 @@
package router
import (
- "net/http"
-
"github.com/gin-gonic/gin"
"github.com/rs/zerolog"
@@ -61,11 +59,18 @@ func apiRoutes(e *gin.RouterGroup) {
org.Use(session.MustOrgMember(true))
org.DELETE("", session.MustAdmin(), api.DeleteOrg)
org.GET("", api.GetOrg)
+
org.GET("/secrets", api.GetOrgSecretList)
org.POST("/secrets", api.PostOrgSecret)
org.GET("/secrets/:secret", api.GetOrgSecret)
org.PATCH("/secrets/:secret", api.PatchOrgSecret)
org.DELETE("/secrets/:secret", api.DeleteOrgSecret)
+
+ org.GET("/registries", api.GetOrgRegistryList)
+ org.POST("/registries", api.PostOrgRegistry)
+ org.GET("/registries/:registry", api.GetOrgRegistry)
+ org.PATCH("/registries/:registry", api.PatchOrgRegistry)
+ org.DELETE("/registries/:registry", api.DeleteOrgRegistry)
}
}
}
@@ -118,11 +123,11 @@ func apiRoutes(e *gin.RouterGroup) {
repo.DELETE("/secrets/:secret", session.MustPush, api.DeleteSecret)
// requires push permissions
- repo.GET("/registry", session.MustPush, api.GetRegistryList)
- repo.POST("/registry", session.MustPush, api.PostRegistry)
- repo.GET("/registry/:registry", session.MustPush, api.GetRegistry)
- repo.PATCH("/registry/:registry", session.MustPush, api.PatchRegistry)
- repo.DELETE("/registry/:registry", session.MustPush, api.DeleteRegistry)
+ repo.GET("/registries", session.MustPush, api.GetRegistryList)
+ repo.POST("/registries", session.MustPush, api.PostRegistry)
+ repo.GET("/registries/:registry", session.MustPush, api.GetRegistry)
+ repo.PATCH("/registries/:registry", session.MustPush, api.PatchRegistry)
+ repo.DELETE("/registries/:registry", session.MustPush, api.DeleteRegistry)
// requires push permissions
repo.GET("/cron", session.MustPush, api.GetCronList)
@@ -184,6 +189,21 @@ func apiRoutes(e *gin.RouterGroup) {
secrets.DELETE("/:secret", api.DeleteGlobalSecret)
}
+ // global registries can be read without actual values by any user
+ readGlobalRegistries := apiBase.Group("/registries")
+ {
+ readGlobalRegistries.Use(session.MustUser())
+ readGlobalRegistries.GET("", api.GetGlobalRegistryList)
+ readGlobalRegistries.GET("/:registry", api.GetGlobalRegistry)
+ }
+ registries := apiBase.Group("/registries")
+ {
+ registries.Use(session.MustAdmin())
+ registries.POST("", api.PostGlobalRegistry)
+ registries.PATCH("/:registry", api.PatchGlobalRegistry)
+ registries.DELETE("/:registry", api.DeleteGlobalRegistry)
+ }
+
logLevel := apiBase.Group("/log-level")
{
logLevel.Use(session.MustAdmin())
@@ -243,12 +263,4 @@ func apiRoutes(e *gin.RouterGroup) {
}
}
}
-
- // TODO: remove with 3.x
- e.Any("/hook", func(c *gin.Context) {
- c.String(http.StatusGone, "use /api/hook")
- })
- e.Any("/stream/events", func(c *gin.Context) {
- c.String(http.StatusGone, "use /api/stream/events")
- })
}
diff --git a/server/router/middleware/session/agent.go b/server/router/middleware/session/agent.go
index cacaf0d44..0cbfa2a33 100644
--- a/server/router/middleware/session/agent.go
+++ b/server/router/middleware/session/agent.go
@@ -31,17 +31,14 @@ func AuthorizeAgent(c *gin.Context) {
return
}
- parsed, err := token.ParseRequest(c.Request, func(_ *token.Token) (string, error) {
+ _, err := token.ParseRequest([]token.Type{token.AgentToken}, c.Request, func(_ *token.Token) (string, error) {
return secret, nil
})
- switch {
- case err != nil:
+ if err != nil {
c.String(http.StatusInternalServerError, "invalid or empty token. %s", err)
c.Abort()
- case parsed.Kind != token.AgentToken:
- c.String(http.StatusForbidden, "invalid token. please use an agent token")
- c.Abort()
- default:
- c.Next()
+ return
}
+
+ c.Next()
}
diff --git a/server/router/middleware/session/user.go b/server/router/middleware/session/user.go
index b413cf528..2f098b5cb 100644
--- a/server/router/middleware/session/user.go
+++ b/server/router/middleware/session/user.go
@@ -43,7 +43,7 @@ func SetUser() gin.HandlerFunc {
return func(c *gin.Context) {
var user *model.User
- t, err := token.ParseRequest(c.Request, func(t *token.Token) (string, error) {
+ t, err := token.ParseRequest([]token.Type{token.UserToken, token.SessToken}, c.Request, func(t *token.Token) (string, error) {
var err error
userID, err := strconv.ParseInt(t.Get("user-id"), 10, 64)
if err != nil {
@@ -58,7 +58,7 @@ func SetUser() gin.HandlerFunc {
// if this is a session token (ie not the API token)
// this means the user is accessing with a web browser,
// so we should implement CSRF protection measures.
- if t.Kind == token.SessToken {
+ if t.Type == token.SessToken {
err = token.CheckCsrf(c.Request, func(_ *token.Token) (string, error) {
return user.Hash, nil
})
diff --git a/server/router/router.go b/server/router/router.go
index 89e1046f9..c873062d3 100644
--- a/server/router/router.go
+++ b/server/router/router.go
@@ -62,7 +62,6 @@ func Load(noRouteHandler http.HandlerFunc, middleware ...gin.HandlerFunc) http.H
{
auth.GET("", api.HandleAuth)
auth.POST("", api.HandleAuth)
- auth.POST("/token", api.DeprecatedGetLoginToken)
}
base.GET("/metrics", metrics.PromHandler())
diff --git a/server/services/config/combined_test.go b/server/services/config/combined_test.go
index 7e3d71084..2d0910c6a 100644
--- a/server/services/config/combined_test.go
+++ b/server/services/config/combined_test.go
@@ -27,9 +27,9 @@ import (
"testing"
"time"
- "github.com/go-ap/httpsig"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
+ "github.com/yaronf/httpsign"
"go.woodpecker-ci.org/woodpecker/v2/server/forge/mocks"
forge_types "go.woodpecker-ci.org/woodpecker/v2/server/forge/types"
@@ -120,25 +120,19 @@ func TestFetchFromConfigService(t *testing.T) {
fixtureHandler := func(w http.ResponseWriter, r *http.Request) {
// check signature
- pubKeyID := "woodpecker-ci-plugins"
+ pubKeyID := "woodpecker-ci-extensions"
- keystore := httpsig.NewMemoryKeyStore()
- keystore.SetKey(pubKeyID, pubEd25519Key)
+ verifier, err := httpsign.NewEd25519Verifier(pubEd25519Key,
+ httpsign.NewVerifyConfig(),
+ httpsign.Headers("@request-target", "content-digest")) // The Content-Digest header will be auto-generated
+ assert.NoError(t, err)
- verifier := httpsig.NewVerifier(keystore)
- verifier.SetRequiredHeaders([]string{"(request-target)", "date"})
-
- keyID, err := verifier.Verify(r)
+ err = httpsign.VerifyRequest(pubKeyID, *verifier, r)
if err != nil {
http.Error(w, "Invalid signature", http.StatusBadRequest)
return
}
- if keyID != pubKeyID {
- http.Error(w, "Used wrong key", http.StatusBadRequest)
- return
- }
-
type config struct {
Name string `json:"name"`
Data string `json:"data"`
@@ -163,12 +157,12 @@ func TestFetchFromConfigService(t *testing.T) {
}
if req.Repo.Name == "Fetch empty" {
- w.WriteHeader(404)
+ w.WriteHeader(http.StatusNotFound)
return
}
if req.Repo.Name == "Use old config" {
- w.WriteHeader(204)
+ w.WriteHeader(http.StatusNoContent)
return
}
@@ -192,7 +186,7 @@ func TestFetchFromConfigService(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(fixtureHandler))
defer ts.Close()
- httpFetcher := config.NewHTTP(ts.URL, privEd25519Key)
+ httpFetcher := config.NewHTTP(ts.URL+"/", privEd25519Key)
for _, tt := range testTable {
t.Run(tt.name, func(t *testing.T) {
diff --git a/server/services/config/http.go b/server/services/config/http.go
index de3a0844a..33dcfc756 100644
--- a/server/services/config/http.go
+++ b/server/services/config/http.go
@@ -16,7 +16,7 @@ package config
import (
"context"
- "crypto"
+ "crypto/ed25519"
"fmt"
net_http "net/http"
@@ -28,7 +28,7 @@ import (
type http struct {
endpoint string
- privateKey crypto.PrivateKey
+ privateKey ed25519.PrivateKey
}
// configData same as forge.FileMeta but with json tags and string data.
@@ -38,26 +38,20 @@ type configData struct {
}
type requestStructure struct {
- Repo *model.Repo `json:"repo"`
- Pipeline *model.Pipeline `json:"pipeline"`
- Netrc *model.Netrc `json:"netrc"`
- Configuration []*configData `json:"configs"` // TODO: deprecate in favor of netrc and remove in next major release
+ Repo *model.Repo `json:"repo"`
+ Pipeline *model.Pipeline `json:"pipeline"`
+ Netrc *model.Netrc `json:"netrc"`
}
type responseStructure struct {
Configs []*configData `json:"configs"`
}
-func NewHTTP(endpoint string, privateKey crypto.PrivateKey) Service {
+func NewHTTP(endpoint string, privateKey ed25519.PrivateKey) Service {
return &http{endpoint, privateKey}
}
func (h *http) Fetch(ctx context.Context, forge forge.Forge, user *model.User, repo *model.Repo, pipeline *model.Pipeline, oldConfigData []*types.FileMeta, _ bool) ([]*types.FileMeta, error) {
- currentConfigs := make([]*configData, len(oldConfigData))
- for i, pipe := range oldConfigData {
- currentConfigs[i] = &configData{Name: pipe.Name, Data: string(pipe.Data)}
- }
-
netrc, err := forge.Netrc(user, repo)
if err != nil {
return nil, fmt.Errorf("could not get Netrc data from forge: %w", err)
@@ -65,10 +59,9 @@ func (h *http) Fetch(ctx context.Context, forge forge.Forge, user *model.User, r
response := new(responseStructure)
body := requestStructure{
- Repo: repo,
- Pipeline: pipeline,
- Configuration: currentConfigs,
- Netrc: netrc,
+ Repo: repo,
+ Pipeline: pipeline,
+ Netrc: netrc,
}
status, err := utils.Send(ctx, net_http.MethodPost, h.endpoint, h.privateKey, body, response)
diff --git a/server/services/config/mocks/service.go b/server/services/config/mocks/service.go
new file mode 100644
index 000000000..3f08d71c7
--- /dev/null
+++ b/server/services/config/mocks/service.go
@@ -0,0 +1,63 @@
+// Code generated by mockery. DO NOT EDIT.
+
+package mocks
+
+import (
+ context "context"
+
+ mock "github.com/stretchr/testify/mock"
+ forge "go.woodpecker-ci.org/woodpecker/v2/server/forge"
+
+ model "go.woodpecker-ci.org/woodpecker/v2/server/model"
+
+ types "go.woodpecker-ci.org/woodpecker/v2/server/forge/types"
+)
+
+// Service is an autogenerated mock type for the Service type
+type Service struct {
+ mock.Mock
+}
+
+// Fetch provides a mock function with given fields: ctx, _a1, user, repo, pipeline, oldConfigData, restart
+func (_m *Service) Fetch(ctx context.Context, _a1 forge.Forge, user *model.User, repo *model.Repo, pipeline *model.Pipeline, oldConfigData []*types.FileMeta, restart bool) ([]*types.FileMeta, error) {
+ ret := _m.Called(ctx, _a1, user, repo, pipeline, oldConfigData, restart)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Fetch")
+ }
+
+ var r0 []*types.FileMeta
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, forge.Forge, *model.User, *model.Repo, *model.Pipeline, []*types.FileMeta, bool) ([]*types.FileMeta, error)); ok {
+ return rf(ctx, _a1, user, repo, pipeline, oldConfigData, restart)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, forge.Forge, *model.User, *model.Repo, *model.Pipeline, []*types.FileMeta, bool) []*types.FileMeta); ok {
+ r0 = rf(ctx, _a1, user, repo, pipeline, oldConfigData, restart)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]*types.FileMeta)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, forge.Forge, *model.User, *model.Repo, *model.Pipeline, []*types.FileMeta, bool) error); ok {
+ r1 = rf(ctx, _a1, user, repo, pipeline, oldConfigData, restart)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// NewService creates a new instance of Service. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewService(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *Service {
+ mock := &Service{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/server/services/config/service.go b/server/services/config/service.go
index 12ba46f21..9f857a796 100644
--- a/server/services/config/service.go
+++ b/server/services/config/service.go
@@ -22,6 +22,8 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/server/model"
)
+//go:generate mockery --name Service --output mocks --case underscore
+
type Service interface {
Fetch(ctx context.Context, forge forge.Forge, user *model.User, repo *model.Repo, pipeline *model.Pipeline, oldConfigData []*types.FileMeta, restart bool) (configData []*types.FileMeta, err error)
}
diff --git a/server/services/encryption/aes_builder.go b/server/services/encryption/aes_builder.go
index 1da6df8a0..bd6800e5d 100644
--- a/server/services/encryption/aes_builder.go
+++ b/server/services/encryption/aes_builder.go
@@ -18,7 +18,7 @@ import (
"errors"
"fmt"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/server/services/encryption/types"
"go.woodpecker-ci.org/woodpecker/v2/server/store"
@@ -30,8 +30,8 @@ type aesConfiguration struct {
clients []types.EncryptionClient
}
-func newAES(ctx *cli.Context, s store.Store) types.EncryptionServiceBuilder {
- key := ctx.String(rawKeyConfigFlag)
+func newAES(c *cli.Command, s store.Store) types.EncryptionServiceBuilder {
+ key := c.String(rawKeyConfigFlag)
return &aesConfiguration{key, s, nil}
}
diff --git a/server/services/encryption/encryption.go b/server/services/encryption/encryption.go
index 4548aa8a3..4312a5ae5 100644
--- a/server/services/encryption/encryption.go
+++ b/server/services/encryption/encryption.go
@@ -17,7 +17,7 @@ package encryption
import (
"fmt"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/server/services/encryption/types"
"go.woodpecker-ci.org/woodpecker/v2/server/store"
@@ -25,12 +25,12 @@ import (
type builder struct {
store store.Store
- ctx *cli.Context
+ c *cli.Command
clients []types.EncryptionClient
}
-func Encryption(ctx *cli.Context, s store.Store) types.EncryptionBuilder {
- return &builder{store: s, ctx: ctx}
+func Encryption(c *cli.Command, s store.Store) types.EncryptionBuilder {
+ return &builder{store: s, c: c}
}
func (b builder) WithClient(client types.EncryptionClient) types.EncryptionBuilder {
@@ -44,7 +44,7 @@ func (b builder) Build() error {
return err
}
- disableFlag := b.ctx.Bool(disableEncryptionConfigFlag)
+ disableFlag := b.c.Bool(disableEncryptionConfigFlag)
keyType, err := b.detectKeyType()
if err != nil {
diff --git a/server/services/encryption/encryption_builder.go b/server/services/encryption/encryption_builder.go
index 700fbdb77..b59606360 100644
--- a/server/services/encryption/encryption_builder.go
+++ b/server/services/encryption/encryption_builder.go
@@ -48,8 +48,8 @@ func (b builder) isEnabled() (bool, error) {
}
func (b builder) detectKeyType() (string, error) {
- rawKeyPresent := b.ctx.IsSet(rawKeyConfigFlag)
- tinkKeysetPresent := b.ctx.IsSet(tinkKeysetFilepathConfigFlag)
+ rawKeyPresent := b.c.IsSet(rawKeyConfigFlag)
+ tinkKeysetPresent := b.c.IsSet(tinkKeysetFilepathConfigFlag)
switch {
case rawKeyPresent && tinkKeysetPresent:
return "", errors.New(errMessageCantUseBothServices)
@@ -64,9 +64,9 @@ func (b builder) detectKeyType() (string, error) {
func (b builder) serviceBuilder(keyType string) (types.EncryptionServiceBuilder, error) {
switch {
case keyType == keyTypeTink:
- return newTink(b.ctx, b.store), nil
+ return newTink(b.c, b.store), nil
case keyType == keyTypeRaw:
- return newAES(b.ctx, b.store), nil
+ return newAES(b.c, b.store), nil
case keyType == keyTypeNone:
return &noEncryptionBuilder{}, nil
}
diff --git a/server/services/encryption/tink_builder.go b/server/services/encryption/tink_builder.go
index 9dd1ddd79..ccb10cb53 100644
--- a/server/services/encryption/tink_builder.go
+++ b/server/services/encryption/tink_builder.go
@@ -18,7 +18,7 @@ import (
"errors"
"fmt"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/server/services/encryption/types"
"go.woodpecker-ci.org/woodpecker/v2/server/store"
@@ -30,8 +30,8 @@ type tinkConfiguration struct {
clients []types.EncryptionClient
}
-func newTink(ctx *cli.Context, s store.Store) types.EncryptionServiceBuilder {
- filepath := ctx.String(tinkKeysetFilepathConfigFlag)
+func newTink(c *cli.Command, s store.Store) types.EncryptionServiceBuilder {
+ filepath := c.String(tinkKeysetFilepathConfigFlag)
return &tinkConfiguration{filepath, s, nil}
}
diff --git a/server/services/environment/mocks/service.go b/server/services/environment/mocks/service.go
new file mode 100644
index 000000000..b7cb0776d
--- /dev/null
+++ b/server/services/environment/mocks/service.go
@@ -0,0 +1,57 @@
+// Code generated by mockery. DO NOT EDIT.
+
+package mocks
+
+import (
+ mock "github.com/stretchr/testify/mock"
+ model "go.woodpecker-ci.org/woodpecker/v2/server/model"
+)
+
+// Service is an autogenerated mock type for the Service type
+type Service struct {
+ mock.Mock
+}
+
+// EnvironList provides a mock function with given fields: _a0
+func (_m *Service) EnvironList(_a0 *model.Repo) ([]*model.Environ, error) {
+ ret := _m.Called(_a0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for EnvironList")
+ }
+
+ var r0 []*model.Environ
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*model.Repo) ([]*model.Environ, error)); ok {
+ return rf(_a0)
+ }
+ if rf, ok := ret.Get(0).(func(*model.Repo) []*model.Environ); ok {
+ r0 = rf(_a0)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]*model.Environ)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*model.Repo) error); ok {
+ r1 = rf(_a0)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// NewService creates a new instance of Service. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewService(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *Service {
+ mock := &Service{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/server/services/environment/service.go b/server/services/environment/service.go
index f8ad14821..0b63471fd 100644
--- a/server/services/environment/service.go
+++ b/server/services/environment/service.go
@@ -16,6 +16,8 @@ package environment
import "go.woodpecker-ci.org/woodpecker/v2/server/model"
+//go:generate mockery --name Service --output mocks --case underscore
+
// Service defines a service for managing environment variables.
type Service interface {
EnvironList(*model.Repo) ([]*model.Environ, error)
diff --git a/server/services/log/file/file.go b/server/services/log/file/file.go
index 276c31798..f19931beb 100644
--- a/server/services/log/file/file.go
+++ b/server/services/log/file/file.go
@@ -8,10 +8,18 @@ import (
"path/filepath"
"strings"
+ logger "github.com/rs/zerolog/log"
+
+ "go.woodpecker-ci.org/woodpecker/v2/pipeline"
"go.woodpecker-ci.org/woodpecker/v2/server/model"
"go.woodpecker-ci.org/woodpecker/v2/server/services/log"
)
+const (
+ // Add base64 overhead and space for other JSON fields (just to be safe).
+ maxLineLength int = (pipeline.MaxLogLineLength/3)*4 + (64 * 1024) //nolint:mnd
+)
+
type logStore struct {
base string
}
@@ -43,7 +51,10 @@ func (l logStore) LogFind(step *model.Step) ([]*model.LogEntry, error) {
return nil, err
}
+ buf := make([]byte, 0, bufio.MaxScanTokenSize)
s := bufio.NewScanner(file)
+ s.Buffer(buf, maxLineLength)
+
var entries []*model.LogEntry
for s.Scan() {
j := s.Text()
@@ -61,19 +72,30 @@ func (l logStore) LogFind(step *model.Step) ([]*model.LogEntry, error) {
return entries, nil
}
-func (l logStore) LogAppend(logEntry *model.LogEntry) error {
- file, err := os.OpenFile(l.filePath(logEntry.StepID), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o600)
+func (l logStore) LogAppend(step *model.Step, logEntries []*model.LogEntry) error {
+ path := l.filePath(step.ID)
+
+ file, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o600)
if err != nil {
+ logger.Error().Err(err).Msgf("could not open log file %s", path)
return err
}
- jsonData, err := json.Marshal(logEntry)
- if err != nil {
- return err
+
+ var bytes []byte
+
+ for _, logEntry := range logEntries {
+ if jsonLine, err := json.Marshal(logEntry); err == nil {
+ bytes = append(bytes, jsonLine...)
+ bytes = append(bytes, byte('\n'))
+ } else {
+ logger.Error().Err(err).Msg("could not convert log entry to JSON")
+ }
}
- _, err = file.Write(append(jsonData, byte('\n')))
- if err != nil {
- return err
+
+ if _, err = file.Write(bytes); err != nil {
+ logger.Error().Err(err).Msg("could not write out log entries")
}
+
return file.Close()
}
diff --git a/server/services/log/service.go b/server/services/log/service.go
index 5cc53d1e9..da8f98146 100644
--- a/server/services/log/service.go
+++ b/server/services/log/service.go
@@ -4,6 +4,6 @@ import "go.woodpecker-ci.org/woodpecker/v2/server/model"
type Service interface {
LogFind(step *model.Step) ([]*model.LogEntry, error)
- LogAppend(logEntry *model.LogEntry) error
+ LogAppend(step *model.Step, logEntries []*model.LogEntry) error
LogDelete(step *model.Step) error
}
diff --git a/server/services/manager.go b/server/services/manager.go
index 079222a02..e38b140e9 100644
--- a/server/services/manager.go
+++ b/server/services/manager.go
@@ -19,7 +19,7 @@ import (
"time"
"github.com/jellydator/ttlcache/v3"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/server/forge"
"go.woodpecker-ci.org/woodpecker/v2/server/model"
@@ -30,7 +30,7 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/server/store"
)
-//go:generate mockery --name Manager --output mocks --case underscore
+//go:generate mockery --name Manager --output mocks --case underscore --note "+build test"
const forgeCacheTTL = 10 * time.Minute
@@ -46,7 +46,7 @@ type Manager interface {
EnvironmentService() environment.Service
ForgeFromRepo(repo *model.Repo) (forge.Forge, error)
ForgeFromUser(user *model.User) (forge.Forge, error)
- ForgeMain() (forge.Forge, error)
+ ForgeByID(forgeID int64) (forge.Forge, error)
}
type manager struct {
@@ -61,7 +61,7 @@ type manager struct {
setupForge SetupForge
}
-func NewManager(c *cli.Context, store store.Store, setupForge SetupForge) (Manager, error) {
+func NewManager(c *cli.Command, store store.Store, setupForge SetupForge) (Manager, error) {
signaturePrivateKey, signaturePublicKey, err := setupSignatureKeys(store)
if err != nil {
return nil, err
@@ -120,18 +120,14 @@ func (m *manager) EnvironmentService() environment.Service {
}
func (m *manager) ForgeFromRepo(repo *model.Repo) (forge.Forge, error) {
- return m.getForgeByID(repo.ForgeID)
+ return m.ForgeByID(repo.ForgeID)
}
func (m *manager) ForgeFromUser(user *model.User) (forge.Forge, error) {
- return m.getForgeByID(user.ForgeID)
+ return m.ForgeByID(user.ForgeID)
}
-func (m *manager) ForgeMain() (forge.Forge, error) {
- return m.getForgeByID(1) // main forge is always 1 and is configured via environment variables
-}
-
-func (m *manager) getForgeByID(id int64) (forge.Forge, error) {
+func (m *manager) ForgeByID(id int64) (forge.Forge, error) {
item := m.forgeCache.Get(id)
if item != nil && !item.IsExpired() {
return item.Value(), nil
diff --git a/server/services/mocks/manager.go b/server/services/mocks/manager.go
index 1d64c2af3..1d94cdec8 100644
--- a/server/services/mocks/manager.go
+++ b/server/services/mocks/manager.go
@@ -1,5 +1,8 @@
// Code generated by mockery. DO NOT EDIT.
+//go:build test
+// +build test
+
package mocks
import (
@@ -65,6 +68,36 @@ func (_m *Manager) EnvironmentService() environment.Service {
return r0
}
+// ForgeByID provides a mock function with given fields: forgeID
+func (_m *Manager) ForgeByID(forgeID int64) (forge.Forge, error) {
+ ret := _m.Called(forgeID)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ForgeByID")
+ }
+
+ var r0 forge.Forge
+ var r1 error
+ if rf, ok := ret.Get(0).(func(int64) (forge.Forge, error)); ok {
+ return rf(forgeID)
+ }
+ if rf, ok := ret.Get(0).(func(int64) forge.Forge); ok {
+ r0 = rf(forgeID)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(forge.Forge)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(int64) error); ok {
+ r1 = rf(forgeID)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
// ForgeFromRepo provides a mock function with given fields: repo
func (_m *Manager) ForgeFromRepo(repo *model.Repo) (forge.Forge, error) {
ret := _m.Called(repo)
@@ -125,36 +158,6 @@ func (_m *Manager) ForgeFromUser(user *model.User) (forge.Forge, error) {
return r0, r1
}
-// ForgeMain provides a mock function with given fields:
-func (_m *Manager) ForgeMain() (forge.Forge, error) {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for ForgeMain")
- }
-
- var r0 forge.Forge
- var r1 error
- if rf, ok := ret.Get(0).(func() (forge.Forge, error)); ok {
- return rf()
- }
- if rf, ok := ret.Get(0).(func() forge.Forge); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(forge.Forge)
- }
- }
-
- if rf, ok := ret.Get(1).(func() error); ok {
- r1 = rf()
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
// RegistryService provides a mock function with given fields:
func (_m *Manager) RegistryService() registry.Service {
ret := _m.Called()
diff --git a/server/services/registry/combined.go b/server/services/registry/combined.go
index 4f52bca1a..bdb249bcd 100644
--- a/server/services/registry/combined.go
+++ b/server/services/registry/combined.go
@@ -15,7 +15,10 @@
package registry
import (
+ "errors"
+
"go.woodpecker-ci.org/woodpecker/v2/server/model"
+ "go.woodpecker-ci.org/woodpecker/v2/server/store/types"
)
type combined struct {
@@ -31,29 +34,44 @@ func NewCombined(dbRegistry Service, registries ...ReadOnlyService) Service {
}
}
-func (c *combined) RegistryFind(repo *model.Repo, name string) (*model.Registry, error) {
- for _, registry := range c.registries {
- res, err := registry.RegistryFind(repo, name)
- if err != nil {
- return nil, err
- }
- if res != nil {
- return res, nil
- }
- }
- return nil, nil
+func (c *combined) RegistryFind(repo *model.Repo, addr string) (*model.Registry, error) {
+ return c.dbRegistry.RegistryFind(repo, addr)
}
func (c *combined) RegistryList(repo *model.Repo, p *model.ListOptions) ([]*model.Registry, error) {
- var registries []*model.Registry
+ return c.dbRegistry.RegistryList(repo, p)
+}
+
+func (c *combined) RegistryListPipeline(repo *model.Repo, pipeline *model.Pipeline) ([]*model.Registry, error) {
+ dbRegistries, err := c.dbRegistry.RegistryListPipeline(repo, pipeline)
+ if err != nil {
+ return nil, err
+ }
+
+ registries := make([]*model.Registry, 0, len(dbRegistries))
+ exists := make(map[string]struct{}, len(dbRegistries))
+
+ // Assign database stored registries to the map to avoid duplicates
+ // from the combined registries so to prioritize ones in database.
+ for _, reg := range dbRegistries {
+ exists[reg.Address] = struct{}{}
+ }
+
for _, registry := range c.registries {
- list, err := registry.RegistryList(repo, &model.ListOptions{All: true})
+ list, err := registry.GlobalRegistryList(&model.ListOptions{All: true})
if err != nil {
return nil, err
}
- registries = append(registries, list...)
+ for _, reg := range list {
+ if _, ok := exists[reg.Address]; ok {
+ continue
+ }
+ exists[reg.Address] = struct{}{}
+ registries = append(registries, reg)
+ }
}
- return model.ApplyPagination(p, registries), nil
+
+ return append(registries, dbRegistries...), nil
}
func (c *combined) RegistryCreate(repo *model.Repo, registry *model.Registry) error {
@@ -64,6 +82,86 @@ func (c *combined) RegistryUpdate(repo *model.Repo, registry *model.Registry) er
return c.dbRegistry.RegistryUpdate(repo, registry)
}
-func (c *combined) RegistryDelete(repo *model.Repo, name string) error {
- return c.dbRegistry.RegistryDelete(repo, name)
+func (c *combined) RegistryDelete(repo *model.Repo, addr string) error {
+ return c.dbRegistry.RegistryDelete(repo, addr)
+}
+
+func (c *combined) OrgRegistryFind(owner int64, addr string) (*model.Registry, error) {
+ return c.dbRegistry.OrgRegistryFind(owner, addr)
+}
+
+func (c *combined) OrgRegistryList(owner int64, p *model.ListOptions) ([]*model.Registry, error) {
+ return c.dbRegistry.OrgRegistryList(owner, p)
+}
+
+func (c *combined) OrgRegistryCreate(owner int64, registry *model.Registry) error {
+ return c.dbRegistry.OrgRegistryCreate(owner, registry)
+}
+
+func (c *combined) OrgRegistryUpdate(owner int64, registry *model.Registry) error {
+ return c.dbRegistry.OrgRegistryUpdate(owner, registry)
+}
+
+func (c *combined) OrgRegistryDelete(owner int64, addr string) error {
+ return c.dbRegistry.OrgRegistryDelete(owner, addr)
+}
+
+func (c *combined) GlobalRegistryFind(addr string) (*model.Registry, error) {
+ registry, err := c.dbRegistry.GlobalRegistryFind(addr)
+ if err != nil && !errors.Is(err, types.RecordNotExist) {
+ return nil, err
+ }
+ if registry != nil {
+ return registry, nil
+ }
+ for _, reg := range c.registries {
+ if registry, err := reg.GlobalRegistryFind(addr); err == nil {
+ return registry, nil
+ }
+ }
+ return nil, types.RecordNotExist
+}
+
+func (c *combined) GlobalRegistryList(p *model.ListOptions) ([]*model.Registry, error) {
+ dbRegistries, err := c.dbRegistry.GlobalRegistryList(&model.ListOptions{All: true})
+ if err != nil {
+ return nil, err
+ }
+
+ registries := make([]*model.Registry, 0, len(dbRegistries))
+ exists := make(map[string]struct{}, len(dbRegistries))
+
+ // Assign database stored registries to the map to avoid duplicates
+ // from the combined registries so to prioritize ones in database.
+ for _, reg := range dbRegistries {
+ exists[reg.Address] = struct{}{}
+ }
+
+ for _, registry := range c.registries {
+ list, err := registry.GlobalRegistryList(&model.ListOptions{All: true})
+ if err != nil {
+ return nil, err
+ }
+ for _, reg := range list {
+ if _, ok := exists[reg.Address]; ok {
+ continue
+ }
+ exists[reg.Address] = struct{}{}
+ registries = append(registries, reg)
+ }
+ }
+
+ return model.ApplyPagination(p, append(registries, dbRegistries...)), nil
+}
+
+func (c *combined) GlobalRegistryCreate(registry *model.Registry) error {
+ return c.dbRegistry.GlobalRegistryCreate(registry)
+}
+
+func (c *combined) GlobalRegistryUpdate(registry *model.Registry) error {
+ return c.dbRegistry.GlobalRegistryUpdate(registry)
+}
+
+func (c *combined) GlobalRegistryDelete(addr string) error {
+ return c.dbRegistry.GlobalRegistryDelete(addr)
}
diff --git a/server/services/registry/db.go b/server/services/registry/db.go
index 1160905b6..6e566d27c 100644
--- a/server/services/registry/db.go
+++ b/server/services/registry/db.go
@@ -28,12 +28,45 @@ func NewDB(store store.Store) Service {
return &db{store}
}
-func (d *db) RegistryFind(repo *model.Repo, name string) (*model.Registry, error) {
- return d.store.RegistryFind(repo, name)
+func (d *db) RegistryFind(repo *model.Repo, addr string) (*model.Registry, error) {
+ return d.store.RegistryFind(repo, addr)
}
func (d *db) RegistryList(repo *model.Repo, p *model.ListOptions) ([]*model.Registry, error) {
- return d.store.RegistryList(repo, p)
+ return d.store.RegistryList(repo, false, p)
+}
+
+func (d *db) RegistryListPipeline(repo *model.Repo, _ *model.Pipeline) ([]*model.Registry, error) {
+ r, err := d.store.RegistryList(repo, true, &model.ListOptions{All: true})
+ if err != nil {
+ return nil, err
+ }
+
+ // Return only registries with unique address
+ // Priority order in case of duplicate addresses are repository, user/organization, global
+ registries := make([]*model.Registry, 0, len(r))
+ uniq := make(map[string]struct{})
+ for _, condition := range []struct {
+ IsRepository bool
+ IsOrganization bool
+ IsGlobal bool
+ }{
+ {IsRepository: true},
+ {IsOrganization: true},
+ {IsGlobal: true},
+ } {
+ for _, registry := range r {
+ if registry.IsRepository() != condition.IsRepository || registry.IsOrganization() != condition.IsOrganization || registry.IsGlobal() != condition.IsGlobal {
+ continue
+ }
+ if _, ok := uniq[registry.Address]; ok {
+ continue
+ }
+ uniq[registry.Address] = struct{}{}
+ registries = append(registries, registry)
+ }
+ }
+ return registries, nil
}
func (d *db) RegistryCreate(_ *model.Repo, in *model.Registry) error {
@@ -45,5 +78,57 @@ func (d *db) RegistryUpdate(_ *model.Repo, in *model.Registry) error {
}
func (d *db) RegistryDelete(repo *model.Repo, addr string) error {
- return d.store.RegistryDelete(repo, addr)
+ registry, err := d.store.RegistryFind(repo, addr)
+ if err != nil {
+ return err
+ }
+ return d.store.RegistryDelete(registry)
+}
+
+func (d *db) OrgRegistryFind(owner int64, name string) (*model.Registry, error) {
+ return d.store.OrgRegistryFind(owner, name)
+}
+
+func (d *db) OrgRegistryList(owner int64, p *model.ListOptions) ([]*model.Registry, error) {
+ return d.store.OrgRegistryList(owner, p)
+}
+
+func (d *db) OrgRegistryCreate(_ int64, in *model.Registry) error {
+ return d.store.RegistryCreate(in)
+}
+
+func (d *db) OrgRegistryUpdate(_ int64, in *model.Registry) error {
+ return d.store.RegistryUpdate(in)
+}
+
+func (d *db) OrgRegistryDelete(owner int64, addr string) error {
+ registry, err := d.store.OrgRegistryFind(owner, addr)
+ if err != nil {
+ return err
+ }
+ return d.store.RegistryDelete(registry)
+}
+
+func (d *db) GlobalRegistryFind(addr string) (*model.Registry, error) {
+ return d.store.GlobalRegistryFind(addr)
+}
+
+func (d *db) GlobalRegistryList(p *model.ListOptions) ([]*model.Registry, error) {
+ return d.store.GlobalRegistryList(p)
+}
+
+func (d *db) GlobalRegistryCreate(in *model.Registry) error {
+ return d.store.RegistryCreate(in)
+}
+
+func (d *db) GlobalRegistryUpdate(in *model.Registry) error {
+ return d.store.RegistryUpdate(in)
+}
+
+func (d *db) GlobalRegistryDelete(addr string) error {
+ registry, err := d.store.GlobalRegistryFind(addr)
+ if err != nil {
+ return err
+ }
+ return d.store.RegistryDelete(registry)
}
diff --git a/server/services/registry/filesystem.go b/server/services/registry/filesystem.go
index 8faf400f5..959c69834 100644
--- a/server/services/registry/filesystem.go
+++ b/server/services/registry/filesystem.go
@@ -25,6 +25,7 @@ import (
"github.com/docker/cli/cli/config/types"
"go.woodpecker-ci.org/woodpecker/v2/server/model"
+ model_types "go.woodpecker-ci.org/woodpecker/v2/server/store/types"
)
type filesystem struct {
@@ -79,17 +80,29 @@ func parseDockerConfig(path string) ([]*model.Registry, error) {
Address: key,
Username: auth.Username,
Password: auth.Password,
+ ReadOnly: true,
})
}
return registries, nil
}
-func (f *filesystem) RegistryFind(*model.Repo, string) (*model.Registry, error) {
- return nil, nil
+func (f *filesystem) GlobalRegistryFind(addr string) (*model.Registry, error) {
+ registries, err := f.GlobalRegistryList(&model.ListOptions{All: true})
+ if err != nil {
+ return nil, err
+ }
+
+ for _, reg := range registries {
+ if reg.Address == addr {
+ return reg, nil
+ }
+ }
+
+ return nil, model_types.RecordNotExist
}
-func (f *filesystem) RegistryList(_ *model.Repo, p *model.ListOptions) ([]*model.Registry, error) {
+func (f *filesystem) GlobalRegistryList(p *model.ListOptions) ([]*model.Registry, error) {
regs, err := parseDockerConfig(f.path)
if err != nil {
return nil, err
diff --git a/server/services/registry/mocks/service.go b/server/services/registry/mocks/service.go
new file mode 100644
index 000000000..ecce0a414
--- /dev/null
+++ b/server/services/registry/mocks/service.go
@@ -0,0 +1,399 @@
+// Code generated by mockery. DO NOT EDIT.
+
+package mocks
+
+import (
+ mock "github.com/stretchr/testify/mock"
+ model "go.woodpecker-ci.org/woodpecker/v2/server/model"
+)
+
+// Service is an autogenerated mock type for the Service type
+type Service struct {
+ mock.Mock
+}
+
+// GlobalRegistryCreate provides a mock function with given fields: _a0
+func (_m *Service) GlobalRegistryCreate(_a0 *model.Registry) error {
+ ret := _m.Called(_a0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GlobalRegistryCreate")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(*model.Registry) error); ok {
+ r0 = rf(_a0)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// GlobalRegistryDelete provides a mock function with given fields: _a0
+func (_m *Service) GlobalRegistryDelete(_a0 string) error {
+ ret := _m.Called(_a0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GlobalRegistryDelete")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(string) error); ok {
+ r0 = rf(_a0)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// GlobalRegistryFind provides a mock function with given fields: _a0
+func (_m *Service) GlobalRegistryFind(_a0 string) (*model.Registry, error) {
+ ret := _m.Called(_a0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GlobalRegistryFind")
+ }
+
+ var r0 *model.Registry
+ var r1 error
+ if rf, ok := ret.Get(0).(func(string) (*model.Registry, error)); ok {
+ return rf(_a0)
+ }
+ if rf, ok := ret.Get(0).(func(string) *model.Registry); ok {
+ r0 = rf(_a0)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*model.Registry)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(string) error); ok {
+ r1 = rf(_a0)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// GlobalRegistryList provides a mock function with given fields: _a0
+func (_m *Service) GlobalRegistryList(_a0 *model.ListOptions) ([]*model.Registry, error) {
+ ret := _m.Called(_a0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GlobalRegistryList")
+ }
+
+ var r0 []*model.Registry
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*model.ListOptions) ([]*model.Registry, error)); ok {
+ return rf(_a0)
+ }
+ if rf, ok := ret.Get(0).(func(*model.ListOptions) []*model.Registry); ok {
+ r0 = rf(_a0)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]*model.Registry)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*model.ListOptions) error); ok {
+ r1 = rf(_a0)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// GlobalRegistryUpdate provides a mock function with given fields: _a0
+func (_m *Service) GlobalRegistryUpdate(_a0 *model.Registry) error {
+ ret := _m.Called(_a0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GlobalRegistryUpdate")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(*model.Registry) error); ok {
+ r0 = rf(_a0)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// OrgRegistryCreate provides a mock function with given fields: _a0, _a1
+func (_m *Service) OrgRegistryCreate(_a0 int64, _a1 *model.Registry) error {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for OrgRegistryCreate")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(int64, *model.Registry) error); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// OrgRegistryDelete provides a mock function with given fields: _a0, _a1
+func (_m *Service) OrgRegistryDelete(_a0 int64, _a1 string) error {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for OrgRegistryDelete")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(int64, string) error); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// OrgRegistryFind provides a mock function with given fields: _a0, _a1
+func (_m *Service) OrgRegistryFind(_a0 int64, _a1 string) (*model.Registry, error) {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for OrgRegistryFind")
+ }
+
+ var r0 *model.Registry
+ var r1 error
+ if rf, ok := ret.Get(0).(func(int64, string) (*model.Registry, error)); ok {
+ return rf(_a0, _a1)
+ }
+ if rf, ok := ret.Get(0).(func(int64, string) *model.Registry); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*model.Registry)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(int64, string) error); ok {
+ r1 = rf(_a0, _a1)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OrgRegistryList provides a mock function with given fields: _a0, _a1
+func (_m *Service) OrgRegistryList(_a0 int64, _a1 *model.ListOptions) ([]*model.Registry, error) {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for OrgRegistryList")
+ }
+
+ var r0 []*model.Registry
+ var r1 error
+ if rf, ok := ret.Get(0).(func(int64, *model.ListOptions) ([]*model.Registry, error)); ok {
+ return rf(_a0, _a1)
+ }
+ if rf, ok := ret.Get(0).(func(int64, *model.ListOptions) []*model.Registry); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]*model.Registry)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(int64, *model.ListOptions) error); ok {
+ r1 = rf(_a0, _a1)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OrgRegistryUpdate provides a mock function with given fields: _a0, _a1
+func (_m *Service) OrgRegistryUpdate(_a0 int64, _a1 *model.Registry) error {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for OrgRegistryUpdate")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(int64, *model.Registry) error); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// RegistryCreate provides a mock function with given fields: _a0, _a1
+func (_m *Service) RegistryCreate(_a0 *model.Repo, _a1 *model.Registry) error {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for RegistryCreate")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(*model.Repo, *model.Registry) error); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// RegistryDelete provides a mock function with given fields: _a0, _a1
+func (_m *Service) RegistryDelete(_a0 *model.Repo, _a1 string) error {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for RegistryDelete")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(*model.Repo, string) error); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// RegistryFind provides a mock function with given fields: _a0, _a1
+func (_m *Service) RegistryFind(_a0 *model.Repo, _a1 string) (*model.Registry, error) {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for RegistryFind")
+ }
+
+ var r0 *model.Registry
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*model.Repo, string) (*model.Registry, error)); ok {
+ return rf(_a0, _a1)
+ }
+ if rf, ok := ret.Get(0).(func(*model.Repo, string) *model.Registry); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*model.Registry)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*model.Repo, string) error); ok {
+ r1 = rf(_a0, _a1)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// RegistryList provides a mock function with given fields: _a0, _a1
+func (_m *Service) RegistryList(_a0 *model.Repo, _a1 *model.ListOptions) ([]*model.Registry, error) {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for RegistryList")
+ }
+
+ var r0 []*model.Registry
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*model.Repo, *model.ListOptions) ([]*model.Registry, error)); ok {
+ return rf(_a0, _a1)
+ }
+ if rf, ok := ret.Get(0).(func(*model.Repo, *model.ListOptions) []*model.Registry); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]*model.Registry)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*model.Repo, *model.ListOptions) error); ok {
+ r1 = rf(_a0, _a1)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// RegistryListPipeline provides a mock function with given fields: _a0, _a1
+func (_m *Service) RegistryListPipeline(_a0 *model.Repo, _a1 *model.Pipeline) ([]*model.Registry, error) {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for RegistryListPipeline")
+ }
+
+ var r0 []*model.Registry
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*model.Repo, *model.Pipeline) ([]*model.Registry, error)); ok {
+ return rf(_a0, _a1)
+ }
+ if rf, ok := ret.Get(0).(func(*model.Repo, *model.Pipeline) []*model.Registry); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]*model.Registry)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*model.Repo, *model.Pipeline) error); ok {
+ r1 = rf(_a0, _a1)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// RegistryUpdate provides a mock function with given fields: _a0, _a1
+func (_m *Service) RegistryUpdate(_a0 *model.Repo, _a1 *model.Registry) error {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for RegistryUpdate")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(*model.Repo, *model.Registry) error); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// NewService creates a new instance of Service. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewService(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *Service {
+ mock := &Service{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/server/services/registry/service.go b/server/services/registry/service.go
index 252ce9d9a..39e1e3fa9 100644
--- a/server/services/registry/service.go
+++ b/server/services/registry/service.go
@@ -16,17 +16,33 @@ package registry
import "go.woodpecker-ci.org/woodpecker/v2/server/model"
+//go:generate mockery --name Service --output mocks --case underscore
+
// Service defines a service for managing registries.
type Service interface {
+ RegistryListPipeline(*model.Repo, *model.Pipeline) ([]*model.Registry, error)
+ // Repository registries
RegistryFind(*model.Repo, string) (*model.Registry, error)
RegistryList(*model.Repo, *model.ListOptions) ([]*model.Registry, error)
RegistryCreate(*model.Repo, *model.Registry) error
RegistryUpdate(*model.Repo, *model.Registry) error
RegistryDelete(*model.Repo, string) error
+ // Organization registries
+ OrgRegistryFind(int64, string) (*model.Registry, error)
+ OrgRegistryList(int64, *model.ListOptions) ([]*model.Registry, error)
+ OrgRegistryCreate(int64, *model.Registry) error
+ OrgRegistryUpdate(int64, *model.Registry) error
+ OrgRegistryDelete(int64, string) error
+ // Global registries
+ GlobalRegistryFind(string) (*model.Registry, error)
+ GlobalRegistryList(*model.ListOptions) ([]*model.Registry, error)
+ GlobalRegistryCreate(*model.Registry) error
+ GlobalRegistryUpdate(*model.Registry) error
+ GlobalRegistryDelete(string) error
}
// ReadOnlyService defines a service for managing registries.
type ReadOnlyService interface {
- RegistryFind(*model.Repo, string) (*model.Registry, error)
- RegistryList(*model.Repo, *model.ListOptions) ([]*model.Registry, error)
+ GlobalRegistryFind(string) (*model.Registry, error)
+ GlobalRegistryList(*model.ListOptions) ([]*model.Registry, error)
}
diff --git a/server/services/secret/db.go b/server/services/secret/db.go
index a89dacf2a..52231ca9e 100644
--- a/server/services/secret/db.go
+++ b/server/services/secret/db.go
@@ -36,8 +36,8 @@ func (d *db) SecretList(repo *model.Repo, p *model.ListOptions) ([]*model.Secret
return d.store.SecretList(repo, false, p)
}
-func (d *db) SecretListPipeline(repo *model.Repo, _ *model.Pipeline, p *model.ListOptions) ([]*model.Secret, error) {
- s, err := d.store.SecretList(repo, true, p)
+func (d *db) SecretListPipeline(repo *model.Repo, _ *model.Pipeline) ([]*model.Secret, error) {
+ s, err := d.store.SecretList(repo, true, &model.ListOptions{All: true})
if err != nil {
return nil, err
}
diff --git a/server/services/secret/db_test.go b/server/services/secret/db_test.go
index 6f6099f57..cd1112373 100644
--- a/server/services/secret/db_test.go
+++ b/server/services/secret/db_test.go
@@ -64,7 +64,7 @@ func TestSecretListPipeline(t *testing.T) {
repoSecret,
}, nil)
- s, err := secret.NewDB(mockStore).SecretListPipeline(&model.Repo{}, &model.Pipeline{}, &model.ListOptions{})
+ s, err := secret.NewDB(mockStore).SecretListPipeline(&model.Repo{}, &model.Pipeline{})
g.Assert(err).IsNil()
g.Assert(len(s)).Equal(1)
@@ -77,7 +77,7 @@ func TestSecretListPipeline(t *testing.T) {
orgSecret,
}, nil)
- s, err := secret.NewDB(mockStore).SecretListPipeline(&model.Repo{}, &model.Pipeline{}, &model.ListOptions{})
+ s, err := secret.NewDB(mockStore).SecretListPipeline(&model.Repo{}, &model.Pipeline{})
g.Assert(err).IsNil()
g.Assert(len(s)).Equal(1)
@@ -89,7 +89,7 @@ func TestSecretListPipeline(t *testing.T) {
globalSecret,
}, nil)
- s, err := secret.NewDB(mockStore).SecretListPipeline(&model.Repo{}, &model.Pipeline{}, &model.ListOptions{})
+ s, err := secret.NewDB(mockStore).SecretListPipeline(&model.Repo{}, &model.Pipeline{})
g.Assert(err).IsNil()
g.Assert(len(s)).Equal(1)
diff --git a/server/services/secret/mocks/service.go b/server/services/secret/mocks/service.go
new file mode 100644
index 000000000..37f301d53
--- /dev/null
+++ b/server/services/secret/mocks/service.go
@@ -0,0 +1,399 @@
+// Code generated by mockery. DO NOT EDIT.
+
+package mocks
+
+import (
+ mock "github.com/stretchr/testify/mock"
+ model "go.woodpecker-ci.org/woodpecker/v2/server/model"
+)
+
+// Service is an autogenerated mock type for the Service type
+type Service struct {
+ mock.Mock
+}
+
+// GlobalSecretCreate provides a mock function with given fields: _a0
+func (_m *Service) GlobalSecretCreate(_a0 *model.Secret) error {
+ ret := _m.Called(_a0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GlobalSecretCreate")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(*model.Secret) error); ok {
+ r0 = rf(_a0)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// GlobalSecretDelete provides a mock function with given fields: _a0
+func (_m *Service) GlobalSecretDelete(_a0 string) error {
+ ret := _m.Called(_a0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GlobalSecretDelete")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(string) error); ok {
+ r0 = rf(_a0)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// GlobalSecretFind provides a mock function with given fields: _a0
+func (_m *Service) GlobalSecretFind(_a0 string) (*model.Secret, error) {
+ ret := _m.Called(_a0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GlobalSecretFind")
+ }
+
+ var r0 *model.Secret
+ var r1 error
+ if rf, ok := ret.Get(0).(func(string) (*model.Secret, error)); ok {
+ return rf(_a0)
+ }
+ if rf, ok := ret.Get(0).(func(string) *model.Secret); ok {
+ r0 = rf(_a0)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*model.Secret)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(string) error); ok {
+ r1 = rf(_a0)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// GlobalSecretList provides a mock function with given fields: _a0
+func (_m *Service) GlobalSecretList(_a0 *model.ListOptions) ([]*model.Secret, error) {
+ ret := _m.Called(_a0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GlobalSecretList")
+ }
+
+ var r0 []*model.Secret
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*model.ListOptions) ([]*model.Secret, error)); ok {
+ return rf(_a0)
+ }
+ if rf, ok := ret.Get(0).(func(*model.ListOptions) []*model.Secret); ok {
+ r0 = rf(_a0)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]*model.Secret)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*model.ListOptions) error); ok {
+ r1 = rf(_a0)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// GlobalSecretUpdate provides a mock function with given fields: _a0
+func (_m *Service) GlobalSecretUpdate(_a0 *model.Secret) error {
+ ret := _m.Called(_a0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GlobalSecretUpdate")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(*model.Secret) error); ok {
+ r0 = rf(_a0)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// OrgSecretCreate provides a mock function with given fields: _a0, _a1
+func (_m *Service) OrgSecretCreate(_a0 int64, _a1 *model.Secret) error {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for OrgSecretCreate")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(int64, *model.Secret) error); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// OrgSecretDelete provides a mock function with given fields: _a0, _a1
+func (_m *Service) OrgSecretDelete(_a0 int64, _a1 string) error {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for OrgSecretDelete")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(int64, string) error); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// OrgSecretFind provides a mock function with given fields: _a0, _a1
+func (_m *Service) OrgSecretFind(_a0 int64, _a1 string) (*model.Secret, error) {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for OrgSecretFind")
+ }
+
+ var r0 *model.Secret
+ var r1 error
+ if rf, ok := ret.Get(0).(func(int64, string) (*model.Secret, error)); ok {
+ return rf(_a0, _a1)
+ }
+ if rf, ok := ret.Get(0).(func(int64, string) *model.Secret); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*model.Secret)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(int64, string) error); ok {
+ r1 = rf(_a0, _a1)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OrgSecretList provides a mock function with given fields: _a0, _a1
+func (_m *Service) OrgSecretList(_a0 int64, _a1 *model.ListOptions) ([]*model.Secret, error) {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for OrgSecretList")
+ }
+
+ var r0 []*model.Secret
+ var r1 error
+ if rf, ok := ret.Get(0).(func(int64, *model.ListOptions) ([]*model.Secret, error)); ok {
+ return rf(_a0, _a1)
+ }
+ if rf, ok := ret.Get(0).(func(int64, *model.ListOptions) []*model.Secret); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]*model.Secret)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(int64, *model.ListOptions) error); ok {
+ r1 = rf(_a0, _a1)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OrgSecretUpdate provides a mock function with given fields: _a0, _a1
+func (_m *Service) OrgSecretUpdate(_a0 int64, _a1 *model.Secret) error {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for OrgSecretUpdate")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(int64, *model.Secret) error); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// SecretCreate provides a mock function with given fields: _a0, _a1
+func (_m *Service) SecretCreate(_a0 *model.Repo, _a1 *model.Secret) error {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SecretCreate")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(*model.Repo, *model.Secret) error); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// SecretDelete provides a mock function with given fields: _a0, _a1
+func (_m *Service) SecretDelete(_a0 *model.Repo, _a1 string) error {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SecretDelete")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(*model.Repo, string) error); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// SecretFind provides a mock function with given fields: _a0, _a1
+func (_m *Service) SecretFind(_a0 *model.Repo, _a1 string) (*model.Secret, error) {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SecretFind")
+ }
+
+ var r0 *model.Secret
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*model.Repo, string) (*model.Secret, error)); ok {
+ return rf(_a0, _a1)
+ }
+ if rf, ok := ret.Get(0).(func(*model.Repo, string) *model.Secret); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*model.Secret)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*model.Repo, string) error); ok {
+ r1 = rf(_a0, _a1)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// SecretList provides a mock function with given fields: _a0, _a1
+func (_m *Service) SecretList(_a0 *model.Repo, _a1 *model.ListOptions) ([]*model.Secret, error) {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SecretList")
+ }
+
+ var r0 []*model.Secret
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*model.Repo, *model.ListOptions) ([]*model.Secret, error)); ok {
+ return rf(_a0, _a1)
+ }
+ if rf, ok := ret.Get(0).(func(*model.Repo, *model.ListOptions) []*model.Secret); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]*model.Secret)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*model.Repo, *model.ListOptions) error); ok {
+ r1 = rf(_a0, _a1)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// SecretListPipeline provides a mock function with given fields: _a0, _a1
+func (_m *Service) SecretListPipeline(_a0 *model.Repo, _a1 *model.Pipeline) ([]*model.Secret, error) {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SecretListPipeline")
+ }
+
+ var r0 []*model.Secret
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*model.Repo, *model.Pipeline) ([]*model.Secret, error)); ok {
+ return rf(_a0, _a1)
+ }
+ if rf, ok := ret.Get(0).(func(*model.Repo, *model.Pipeline) []*model.Secret); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]*model.Secret)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*model.Repo, *model.Pipeline) error); ok {
+ r1 = rf(_a0, _a1)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// SecretUpdate provides a mock function with given fields: _a0, _a1
+func (_m *Service) SecretUpdate(_a0 *model.Repo, _a1 *model.Secret) error {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SecretUpdate")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(*model.Repo, *model.Secret) error); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// NewService creates a new instance of Service. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewService(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *Service {
+ mock := &Service{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/server/services/secret/service.go b/server/services/secret/service.go
index 24568c195..c2b25ba0f 100644
--- a/server/services/secret/service.go
+++ b/server/services/secret/service.go
@@ -16,9 +16,11 @@ package secret
import "go.woodpecker-ci.org/woodpecker/v2/server/model"
+//go:generate mockery --name Service --output mocks --case underscore
+
// Service defines a service for managing secrets.
type Service interface {
- SecretListPipeline(*model.Repo, *model.Pipeline, *model.ListOptions) ([]*model.Secret, error)
+ SecretListPipeline(*model.Repo, *model.Pipeline) ([]*model.Secret, error)
// Repository secrets
SecretFind(*model.Repo, string) (*model.Secret, error)
SecretList(*model.Repo, *model.ListOptions) ([]*model.Secret, error)
diff --git a/server/services/setup.go b/server/services/setup.go
index 305541c02..751a30ddd 100644
--- a/server/services/setup.go
+++ b/server/services/setup.go
@@ -24,7 +24,7 @@ import (
"strings"
"github.com/rs/zerolog/log"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
"go.woodpecker-ci.org/woodpecker/v2/server/model"
"go.woodpecker-ci.org/woodpecker/v2/server/services/config"
@@ -57,13 +57,13 @@ func setupSecretService(store store.Store) secret.Service {
return secret.NewDB(store)
}
-func setupConfigService(c *cli.Context, privateSignatureKey crypto.PrivateKey) (config.Service, error) {
+func setupConfigService(c *cli.Command, privateSignatureKey ed25519.PrivateKey) (config.Service, error) {
timeout := c.Duration("forge-timeout")
retries := c.Uint("forge-retry")
if retries == 0 {
return nil, fmt.Errorf("WOODPECKER_FORGE_RETRY can not be 0")
}
- configFetcher := config.NewForge(timeout, retries)
+ configFetcher := config.NewForge(timeout, uint(retries))
if endpoint := c.String("config-service-endpoint"); endpoint != "" {
httpFetcher := config.NewHTTP(endpoint, privateSignatureKey)
@@ -74,7 +74,7 @@ func setupConfigService(c *cli.Context, privateSignatureKey crypto.PrivateKey) (
}
// setupSignatureKeys generate or load key pair to sign webhooks requests (i.e. used for service extensions).
-func setupSignatureKeys(_store store.Store) (crypto.PrivateKey, crypto.PublicKey, error) {
+func setupSignatureKeys(_store store.Store) (ed25519.PrivateKey, crypto.PublicKey, error) {
privKeyID := "signature-private-key"
privKey, err := _store.ServerConfigGet(privKeyID)
@@ -100,7 +100,7 @@ func setupSignatureKeys(_store store.Store) (crypto.PrivateKey, crypto.PublicKey
return privateKey, privateKey.Public(), nil
}
-func setupForgeService(c *cli.Context, _store store.Store) error {
+func setupForgeService(c *cli.Command, _store store.Store) error {
_forge, err := _store.ForgeGet(1)
if err != nil && !errors.Is(err, types.RecordNotExist) {
return err
diff --git a/server/services/utils/http.go b/server/services/utils/http.go
index c11bfe27f..40a50269c 100644
--- a/server/services/utils/http.go
+++ b/server/services/utils/http.go
@@ -17,19 +17,19 @@ package utils
import (
"bytes"
"context"
- "crypto"
+ "crypto/ed25519"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
- "github.com/go-ap/httpsig"
+ "github.com/yaronf/httpsign"
)
// Send makes an http request to the given endpoint, writing the input
// to the request body and un-marshaling the output from the response body.
-func Send(ctx context.Context, method, path string, privateKey crypto.PrivateKey, in, out any) (int, error) {
+func Send(ctx context.Context, method, path string, privateKey ed25519.PrivateKey, in, out any) (int, error) {
uri, err := url.Parse(path)
if err != nil {
return 0, err
@@ -54,12 +54,12 @@ func Send(ctx context.Context, method, path string, privateKey crypto.PrivateKey
req.Header.Set("Content-Type", "application/json")
}
- err = SignHTTPRequest(privateKey, req)
+ client, err := signClient(privateKey)
if err != nil {
return 0, err
}
- resp, err := http.DefaultClient.Do(req)
+ resp, err := client.Do(req)
if err != nil {
return 0, err
}
@@ -79,10 +79,14 @@ func Send(ctx context.Context, method, path string, privateKey crypto.PrivateKey
return resp.StatusCode, err
}
-func SignHTTPRequest(privateKey crypto.PrivateKey, req *http.Request) error {
- pubKeyID := "woodpecker-ci-plugins"
+func signClient(privateKey ed25519.PrivateKey) (*httpsign.Client, error) {
+ pubKeyID := "woodpecker-ci-extensions"
- signer := httpsig.NewEd25519Signer(pubKeyID, privateKey, nil)
-
- return signer.Sign(req)
+ signer, err := httpsign.NewEd25519Signer(privateKey,
+ httpsign.NewSignConfig(),
+ httpsign.Headers("@request-target", "content-digest")) // The Content-Digest header will be auto-generated
+ if err != nil {
+ return nil, err
+ }
+ return httpsign.NewDefaultClient(httpsign.NewClientConfig().SetSignatureName(pubKeyID).SetSigner(signer)), nil // sign requests, don't verify responses
}
diff --git a/server/services/utils/http_test.go b/server/services/utils/http_test.go
index 3b47e8cc7..57d7eece2 100644
--- a/server/services/utils/http_test.go
+++ b/server/services/utils/http_test.go
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package utils_test
+package utils
import (
"bytes"
@@ -21,15 +21,14 @@ import (
"net/http"
"net/http/httptest"
"testing"
+ "time"
- "github.com/go-ap/httpsig"
"github.com/stretchr/testify/assert"
-
- "go.woodpecker-ci.org/woodpecker/v2/server/services/utils"
+ "github.com/yaronf/httpsign"
)
-func TestSign(t *testing.T) {
- pubKeyID := "woodpecker-ci-plugins"
+func TestSignClient(t *testing.T) {
+ pubKeyID := "woodpecker-ci-extensions"
pubEd25519Key, privEd25519Key, err := ed25519.GenerateKey(rand.Reader)
if !assert.NoError(t, err) {
@@ -38,36 +37,36 @@ func TestSign(t *testing.T) {
body := []byte("{\"foo\":\"bar\"}")
- req, err := http.NewRequest(http.MethodGet, "http://example.com", bytes.NewBuffer(body))
- if err != nil {
- t.Fatal(err)
- }
-
- req.Header.Set("Content-Type", "application/json")
-
- err = utils.SignHTTPRequest(privEd25519Key, req)
- if err != nil {
- t.Fatal(err)
- }
-
verifyHandler := func(w http.ResponseWriter, r *http.Request) {
- keystore := httpsig.NewMemoryKeyStore()
- keystore.SetKey(pubKeyID, pubEd25519Key)
-
- verifier := httpsig.NewVerifier(keystore)
- verifier.SetRequiredHeaders([]string{"(request-target)", "date"})
-
- keyID, err := verifier.Verify(r)
+ verifier, err := httpsign.NewEd25519Verifier(pubEd25519Key,
+ httpsign.NewVerifyConfig(),
+ httpsign.Headers("@request-target", "content-digest")) // The Content-Digest header will be auto-generated
+ assert.NoError(t, err)
+
+ err = httpsign.VerifyRequest(pubKeyID, *verifier, r)
assert.NoError(t, err)
- assert.Equal(t, pubKeyID, keyID)
w.WriteHeader(http.StatusOK)
}
- rr := httptest.NewRecorder()
- handler := http.HandlerFunc(verifyHandler)
+ server := httptest.NewServer(http.HandlerFunc(verifyHandler))
- handler.ServeHTTP(rr, req)
+ req, err := http.NewRequest("GET", server.URL+"/", bytes.NewBuffer(body))
+ if !assert.NoError(t, err) {
+ return
+ }
- assert.Equal(t, http.StatusOK, rr.Code)
+ req.Header.Set("Date", time.Now().Format(time.RFC3339))
+ req.Header.Set("Content-Type", "application/json")
+
+ client, err := signClient(privEd25519Key)
+ if !assert.NoError(t, err) {
+ return
+ }
+
+ rr, err := client.Do(req)
+ assert.NoError(t, err)
+ defer rr.Body.Close()
+
+ assert.Equal(t, http.StatusOK, rr.StatusCode)
}
diff --git a/server/store/datastore/config.go b/server/store/datastore/config.go
index eda41bd25..b16c415a8 100644
--- a/server/store/datastore/config.go
+++ b/server/store/datastore/config.go
@@ -29,16 +29,16 @@ import (
func (s storage) ConfigsForPipeline(pipelineID int64) ([]*model.Config, error) {
configs := make([]*model.Config, 0, perPage)
return configs, s.engine.
- Table("config").
- Join("LEFT", "pipeline_config", "config.config_id = pipeline_config.config_id").
- Where("pipeline_config.pipeline_id = ?", pipelineID).
+ Table("configs").
+ Join("LEFT", "pipeline_configs", "configs.id = pipeline_configs.config_id").
+ Where("pipeline_configs.pipeline_id = ?", pipelineID).
Find(&configs)
}
func (s storage) configFindIdentical(sess *xorm.Session, repoID int64, hash, name string) (*model.Config, error) {
conf := new(model.Config)
if err := wrapGet(sess.Where(
- builder.Eq{"config_repo_id": repoID, "config_hash": hash, "config_name": name},
+ builder.Eq{"repo_id": repoID, "hash": hash, "name": name},
).Get(conf)); err != nil {
return nil, err
}
diff --git a/server/store/datastore/cron.go b/server/store/datastore/cron.go
index ce2609269..89cf91e3e 100644
--- a/server/store/datastore/cron.go
+++ b/server/store/datastore/cron.go
@@ -35,7 +35,7 @@ func (s storage) CronFind(repo *model.Repo, id int64) (*model.Cron, error) {
func (s storage) CronList(repo *model.Repo, p *model.ListOptions) ([]*model.Cron, error) {
var crons []*model.Cron
- return crons, s.paginate(p).Where("repo_id = ?", repo.ID).Find(&crons)
+ return crons, s.paginate(p).Where("repo_id = ?", repo.ID).OrderBy("name").Find(&crons)
}
func (s storage) CronUpdate(_ *model.Repo, cron *model.Cron) error {
diff --git a/server/store/datastore/engine.go b/server/store/datastore/engine.go
index bee837a1d..8499681ac 100644
--- a/server/store/datastore/engine.go
+++ b/server/store/datastore/engine.go
@@ -15,6 +15,8 @@
package datastore
import (
+ "context"
+
"github.com/rs/zerolog"
"xorm.io/xorm"
xlog "xorm.io/xorm/log"
@@ -54,8 +56,8 @@ func (s storage) Ping() error {
}
// Migrate old storage or init new one.
-func (s storage) Migrate(allowLong bool) error {
- return migration.Migrate(s.engine, allowLong)
+func (s storage) Migrate(ctx context.Context, allowLong bool) error {
+ return migration.Migrate(ctx, s.engine, allowLong)
}
func (s storage) Close() error {
diff --git a/server/store/datastore/feed.go b/server/store/datastore/feed.go
index 926809386..d06897bf8 100644
--- a/server/store/datastore/feed.go
+++ b/server/store/datastore/feed.go
@@ -20,30 +20,30 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/server/model"
)
-var feedItemSelect = `repos.repo_id as feed_repo_id,
-pipelines.pipeline_id as feed_pipeline_id,
-pipelines.pipeline_number as feed_pipeline_number,
-pipelines.pipeline_event as feed_pipeline_event,
-pipelines.pipeline_status as feed_pipeline_status,
-pipelines.pipeline_created as feed_pipeline_created,
-pipelines.pipeline_started as feed_pipeline_started,
-pipelines.pipeline_finished as feed_pipeline_finished,
-pipelines.pipeline_commit as feed_pipeline_commit,
-pipelines.pipeline_branch as feed_pipeline_branch,
-pipelines.pipeline_ref as feed_pipeline_ref,
-pipelines.pipeline_refspec as feed_pipeline_refspec,
-pipelines.pipeline_title as feed_pipeline_title,
-pipelines.pipeline_message as feed_pipeline_message,
-pipelines.pipeline_author as feed_pipeline_author,
-pipelines.pipeline_email as feed_pipeline_email,
-pipelines.pipeline_avatar as feed_pipeline_avatar`
+var feedItemSelect = `repos.id as repo_id,
+pipelines.id as pipeline_id,
+pipelines.number as pipeline_number,
+pipelines.event as pipeline_event,
+pipelines.status as pipeline_status,
+pipelines.created as pipeline_created,
+pipelines.started as pipeline_started,
+pipelines.finished as pipeline_finished,
+'pipelines.commit' as pipeline_commit,
+pipelines.branch as pipeline_branch,
+pipelines.ref as pipeline_ref,
+pipelines.refspec as pipeline_refspec,
+pipelines.title as pipeline_title,
+pipelines.message as pipeline_message,
+pipelines.author as pipeline_author,
+pipelines.email as pipeline_email,
+pipelines.avatar as pipeline_avatar`
func (s storage) GetPipelineQueue() ([]*model.Feed, error) {
feed := make([]*model.Feed, 0, perPage)
err := s.engine.Table("pipelines").
Select(feedItemSelect).
- Join("INNER", "repos", "pipelines.pipeline_repo_id = repos.repo_id").
- In("pipelines.pipeline_status", model.StatusPending, model.StatusRunning).
+ Join("INNER", "repos", "pipelines.repo_id = repos.id").
+ In("pipelines.status", model.StatusPending, model.StatusRunning).
Find(&feed)
return feed, err
}
@@ -52,10 +52,10 @@ func (s storage) UserFeed(user *model.User) ([]*model.Feed, error) {
feed := make([]*model.Feed, 0, perPage)
err := s.engine.Table("repos").
Select(feedItemSelect).
- Join("INNER", "perms", "repos.repo_id = perms.perm_repo_id").
- Join("INNER", "pipelines", "repos.repo_id = pipelines.pipeline_repo_id").
+ Join("INNER", "perms", "repos.id = perms.repo_id").
+ Join("INNER", "pipelines", "repos.id = pipelines.repo_id").
Where(userPushOrAdminCondition(user.ID)).
- Desc("pipelines.pipeline_id").
+ Desc("pipelines.id").
Limit(perPage).
Find(&feed)
@@ -67,16 +67,16 @@ func (s storage) RepoListLatest(user *model.User) ([]*model.Feed, error) {
err := s.engine.Table("repos").
Select(feedItemSelect).
- Join("INNER", "perms", "repos.repo_id = perms.perm_repo_id").
- Join("LEFT", "pipelines", "pipelines.pipeline_id = "+`(
- SELECT pipelines.pipeline_id FROM pipelines
- WHERE pipelines.pipeline_repo_id = repos.repo_id
- ORDER BY pipelines.pipeline_id DESC
+ Join("INNER", "perms", "repos.id = perms.repo_id").
+ Join("LEFT", "pipelines", "pipelines.id = "+`(
+ SELECT pipelines.id FROM pipelines
+ WHERE pipelines.repo_id = repos.id
+ ORDER BY pipelines.id DESC
LIMIT 1
)`).
Where(userPushOrAdminCondition(user.ID)).
- And(builder.Eq{"repos.repo_active": true}).
- Asc("repos.repo_full_name").
+ And(builder.Eq{"repos.active": true}).
+ Asc("repos.full_name").
Find(&feed)
return feed, err
diff --git a/server/store/datastore/log.go b/server/store/datastore/log.go
index 68c708c63..3aedf4650 100644
--- a/server/store/datastore/log.go
+++ b/server/store/datastore/log.go
@@ -15,16 +15,33 @@
package datastore
import (
+ "github.com/rs/zerolog/log"
+
"go.woodpecker-ci.org/woodpecker/v2/server/model"
)
+// Maximum number of records to store in one PostgreSQL statement.
+// Too large a value results in `pq: got XX parameters but PostgreSQL only supports 65535 parameters`.
+const pgBatchSize = 1000
+
func (s storage) LogFind(step *model.Step) ([]*model.LogEntry, error) {
var logEntries []*model.LogEntry
return logEntries, s.engine.Asc("id").Where("step_id = ?", step.ID).Find(&logEntries)
}
-func (s storage) LogAppend(logEntry *model.LogEntry) error {
- _, err := s.engine.Insert(logEntry)
+func (s storage) LogAppend(_ *model.Step, logEntries []*model.LogEntry) error {
+ var err error
+
+ // TODO: adapted from slices.Chunk(); switch to it in Go 1.23+
+ for i := 0; i < len(logEntries); i += pgBatchSize {
+ end := min(pgBatchSize, len(logEntries[i:]))
+ chunk := logEntries[i : i+end]
+
+ if _, err = s.engine.Insert(chunk); err != nil {
+ log.Error().Err(err).Msg("could not store log entries to db")
+ }
+ }
+
return err
}
diff --git a/server/store/datastore/log_test.go b/server/store/datastore/log_test.go
index f2ee1ffc6..94897268c 100644
--- a/server/store/datastore/log_test.go
+++ b/server/store/datastore/log_test.go
@@ -45,9 +45,7 @@ func TestLogCreateFindDelete(t *testing.T) {
},
}
- for _, logEntry := range logEntries {
- assert.NoError(t, store.LogAppend(logEntry))
- }
+ assert.NoError(t, store.LogAppend(&step, logEntries))
// we want to find our inserted logs
_logEntries, err := store.LogFind(&step)
@@ -83,9 +81,7 @@ func TestLogAppend(t *testing.T) {
},
}
- for _, logEntry := range logEntries {
- assert.NoError(t, store.LogAppend(logEntry))
- }
+ assert.NoError(t, store.LogAppend(&step, logEntries))
logEntry := &model.LogEntry{
StepID: step.ID,
@@ -94,7 +90,7 @@ func TestLogAppend(t *testing.T) {
Time: 20,
}
- assert.NoError(t, store.LogAppend(logEntry))
+ assert.NoError(t, store.LogAppend(&step, []*model.LogEntry{logEntry}))
_logEntries, err := store.LogFind(&step)
assert.NoError(t, err)
diff --git a/server/store/datastore/migration/023_add_org_id.go b/server/store/datastore/migration/001_add_org_id.go
similarity index 95%
rename from server/store/datastore/migration/023_add_org_id.go
rename to server/store/datastore/migration/001_add_org_id.go
index da055421b..877ab58cd 100644
--- a/server/store/datastore/migration/023_add_org_id.go
+++ b/server/store/datastore/migration/001_add_org_id.go
@@ -26,12 +26,12 @@ import (
var addOrgID = xormigrate.Migration{
ID: "add-org-id",
MigrateSession: func(sess *xorm.Session) error {
- if err := sess.Sync(new(model.User)); err != nil {
+ if err := sess.Sync(new(userV009)); err != nil {
return fmt.Errorf("sync new models failed: %w", err)
}
// get all users
- var users []*model.User
+ var users []*userV009
if err := sess.Find(&users); err != nil {
return fmt.Errorf("find all repos failed: %w", err)
}
diff --git a/server/store/datastore/migration/001_legacy_to_xorm.go b/server/store/datastore/migration/001_legacy_to_xorm.go
deleted file mode 100644
index 47a526147..000000000
--- a/server/store/datastore/migration/001_legacy_to_xorm.go
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright 2021 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"
-
- "github.com/rs/zerolog/log"
- "src.techknowlogick.com/xormigrate"
- "xorm.io/xorm"
- "xorm.io/xorm/schemas"
-)
-
-var legacy2Xorm = xormigrate.Migration{
- ID: "xorm",
- MigrateSession: func(sess *xorm.Session) error {
- // make sure we have required migrations - else fail and point to last major version
- for _, mig := range []string{
- // users
- "create-table-users",
- "update-table-set-users-token-and-secret-length",
- // repos
- "create-table-repos",
- "alter-table-add-repo-visibility",
- "update-table-set-repo-visibility",
- "alter-table-add-repo-seq",
- "update-table-set-repo-seq",
- "update-table-set-repo-seq-default",
- "alter-table-add-repo-active",
- "update-table-set-repo-active",
- "alter-table-add-repo-fallback", // needed to drop col
- // builds
- "create-table-builds",
- "create-index-builds-repo",
- "create-index-builds-author",
- // procs
- "create-table-procs",
- "create-index-procs-build",
- // files
- "create-table-files",
- "create-index-files-builds",
- "create-index-files-procs",
- "alter-table-add-file-pid",
- "alter-table-add-file-meta-passed",
- "alter-table-add-file-meta-failed",
- "alter-table-add-file-meta-skipped",
- "alter-table-update-file-meta",
- // secrets
- "create-table-secrets",
- "create-index-secrets-repo",
- // registry
- "create-table-registry",
- "create-index-registry-repo",
- // senders
- "create-table-senders",
- "create-index-sender-repos",
- // perms
- "create-table-perms",
- "create-index-perms-repo",
- "create-index-perms-user",
- // build_config
- "create-table-build-config",
- "populate-build-config",
- } {
- exist, err := sess.Exist(&xormigrate.Migration{ID: mig})
- if err != nil {
- return fmt.Errorf("test migration existence: %w", err)
- }
- if !exist {
- log.Error().Msgf("migration step '%s' missing, please upgrade to last stable v0.14.x version first", mig)
- return fmt.Errorf("legacy migration step missing")
- }
- }
-
- { // recreate build_config
- type BuildConfig struct {
- ConfigID int64 `xorm:"NOT NULL 'config_id'"` // xorm.Sync() do not use index info of sess -> so it tries to create it twice
- BuildID int64 `xorm:"NOT NULL 'build_id'"`
- }
- if err := renameTable(sess, "build_config", "old_build_config"); err != nil {
- return err
- }
- if err := sess.Sync(new(BuildConfig)); err != nil {
- return err
- }
- if _, err := sess.Exec("INSERT INTO build_config (config_id, build_id) SELECT config_id,build_id FROM old_build_config;"); err != nil {
- return fmt.Errorf("unable to set copy data into temp table %s. Error: %w", "old_build_config", err)
- }
- if err := sess.DropTable("old_build_config"); err != nil {
- return fmt.Errorf("could not drop table '%s': %w", "old_build_config", err)
- }
- }
-
- dialect := sess.Engine().Dialect().URI().DBType
- switch dialect {
- case schemas.MYSQL:
- for _, exec := range []string{
- "DROP INDEX IF EXISTS build_number ON builds;",
- "DROP INDEX IF EXISTS ix_build_repo ON builds;",
- "DROP INDEX IF EXISTS ix_build_author ON builds;",
- "DROP INDEX IF EXISTS proc_build_ix ON procs;",
- "DROP INDEX IF EXISTS file_build_ix ON files;",
- "DROP INDEX IF EXISTS file_proc_ix ON files;",
- "DROP INDEX IF EXISTS ix_secrets_repo ON secrets;",
- "DROP INDEX IF EXISTS ix_registry_repo ON registry;",
- "DROP INDEX IF EXISTS sender_repo_ix ON senders;",
- "DROP INDEX IF EXISTS ix_perms_repo ON perms;",
- "DROP INDEX IF EXISTS ix_perms_user ON perms;",
- } {
- if _, err := sess.Exec(exec); err != nil {
- return fmt.Errorf("exec: '%s' failed: %w", exec, err)
- }
- }
- case schemas.SQLITE, schemas.POSTGRES:
- for _, exec := range []string{
- "DROP INDEX IF EXISTS ix_build_status_running;",
- "DROP INDEX IF EXISTS ix_build_repo;",
- "DROP INDEX IF EXISTS ix_build_author;",
- "DROP INDEX IF EXISTS proc_build_ix;",
- "DROP INDEX IF EXISTS file_build_ix;",
- "DROP INDEX IF EXISTS file_proc_ix;",
- "DROP INDEX IF EXISTS ix_secrets_repo;",
- "DROP INDEX IF EXISTS ix_registry_repo;",
- "DROP INDEX IF EXISTS sender_repo_ix;",
- "DROP INDEX IF EXISTS ix_perms_repo;",
- "DROP INDEX IF EXISTS ix_perms_user;",
- } {
- if _, err := sess.Exec(exec); err != nil {
- return fmt.Errorf("exec: '%s' failed: %w", exec, err)
- }
- }
- default:
- return fmt.Errorf("dialect '%s' not supported", dialect)
- }
-
- return nil
- },
-}
diff --git a/server/store/datastore/migration/002_repos_drop_fallback.go b/server/store/datastore/migration/002_repos_drop_fallback.go
deleted file mode 100644
index 111bd3eb0..000000000
--- a/server/store/datastore/migration/002_repos_drop_fallback.go
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2021 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 (
- "src.techknowlogick.com/xormigrate"
- "xorm.io/xorm"
-)
-
-var alterTableReposDropFallback = xormigrate.Migration{
- ID: "alter-table-drop-repo-fallback",
- MigrateSession: func(sess *xorm.Session) error {
- return dropTableColumns(sess, "repos", "repo_fallback")
- },
-}
diff --git a/server/store/datastore/migration/024_task_data_type.go b/server/store/datastore/migration/002_task_data_type.go
similarity index 100%
rename from server/store/datastore/migration/024_task_data_type.go
rename to server/store/datastore/migration/002_task_data_type.go
diff --git a/server/store/datastore/migration/025_config_data_type.go b/server/store/datastore/migration/003_config_data_type.go
similarity index 100%
rename from server/store/datastore/migration/025_config_data_type.go
rename to server/store/datastore/migration/003_config_data_type.go
diff --git a/server/store/datastore/migration/003_repos_drop_allow_deploys_allow_tags.go b/server/store/datastore/migration/003_repos_drop_allow_deploys_allow_tags.go
deleted file mode 100644
index d99610f56..000000000
--- a/server/store/datastore/migration/003_repos_drop_allow_deploys_allow_tags.go
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2021 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 (
- "src.techknowlogick.com/xormigrate"
- "xorm.io/xorm"
-)
-
-var alterTableReposDropAllowDeploysAllowTags = xormigrate.Migration{
- ID: "drop-allow-push-tags-deploys-columns",
- MigrateSession: func(sess *xorm.Session) error {
- return dropTableColumns(sess, "repos",
- "repo_allow_deploys",
- "repo_allow_tags",
- )
- },
-}
diff --git a/server/store/datastore/migration/004_fix_pr_secret_event_name.go b/server/store/datastore/migration/004_fix_pr_secret_event_name.go
deleted file mode 100644
index 66406a07b..000000000
--- a/server/store/datastore/migration/004_fix_pr_secret_event_name.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2021 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 (
- "src.techknowlogick.com/xormigrate"
- "xorm.io/xorm"
-
- "go.woodpecker-ci.org/woodpecker/v2/server/model"
-)
-
-var fixPRSecretEventName = xormigrate.Migration{
- ID: "fix-pr-secret-event-name",
- MigrateSession: func(sess *xorm.Session) error {
- const batchSize = 100
- for start := 0; ; start += batchSize {
- secrets := make([]*model.Secret, 0, batchSize)
- if err := sess.Limit(batchSize, start).Table("secrets").Cols("secret_id", "secret_events").Where("secret_events LIKE '%pull-request%'").Find(&secrets); err != nil {
- return err
- }
-
- if len(secrets) == 0 {
- break
- }
-
- for _, secret := range secrets {
- for i, event := range secret.Events {
- if event == "pull-request" {
- secret.Events[i] = "pull_request"
- }
- }
- if _, err := sess.ID(secret.ID).Cols("secret_events").Update(secret); err != nil {
- return err
- }
- }
- }
- return nil
- },
-}
diff --git a/server/store/datastore/migration/026_remove_secrets_plugin_only_col.go b/server/store/datastore/migration/004_remove_secrets_plugin_only_col.go
similarity index 92%
rename from server/store/datastore/migration/026_remove_secrets_plugin_only_col.go
rename to server/store/datastore/migration/004_remove_secrets_plugin_only_col.go
index 082744cca..8a91ffb36 100644
--- a/server/store/datastore/migration/026_remove_secrets_plugin_only_col.go
+++ b/server/store/datastore/migration/004_remove_secrets_plugin_only_col.go
@@ -19,7 +19,7 @@ import (
"xorm.io/xorm"
)
-type oldSecret026 struct {
+type oldSecret004 struct {
ID int64 `json:"id" xorm:"pk autoincr 'secret_id'"`
PluginsOnly bool `json:"plugins_only" xorm:"secret_plugins_only"`
SkipVerify bool `json:"-" xorm:"secret_skip_verify"`
@@ -27,7 +27,7 @@ type oldSecret026 struct {
Images []string `json:"images" xorm:"json 'secret_images'"`
}
-func (oldSecret026) TableName() string {
+func (oldSecret004) TableName() string {
return "secrets"
}
@@ -35,7 +35,7 @@ var removePluginOnlyOptionFromSecretsTable = xormigrate.Migration{
ID: "remove-plugin-only-option-from-secrets-table",
MigrateSession: func(sess *xorm.Session) (err error) {
// make sure plugin_only column exists
- if err := sess.Sync(new(oldSecret026)); err != nil {
+ if err := sess.Sync(new(oldSecret004)); err != nil {
return err
}
diff --git a/server/store/datastore/migration/027_convert_to_new_pipeline_errors_format.go b/server/store/datastore/migration/005_convert_to_new_pipeline_errors_format.go
similarity index 83%
rename from server/store/datastore/migration/027_convert_to_new_pipeline_errors_format.go
rename to server/store/datastore/migration/005_convert_to_new_pipeline_errors_format.go
index a51ac1c6a..53d18c8fd 100644
--- a/server/store/datastore/migration/027_convert_to_new_pipeline_errors_format.go
+++ b/server/store/datastore/migration/005_convert_to_new_pipeline_errors_format.go
@@ -21,20 +21,20 @@ import (
errorTypes "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors/types"
)
-// perPage027 set the size of the slice to read per page.
-var perPage027 = 100
+// perPage005 set the size of the slice to read per page.
+var perPage005 = 100
-type pipeline027 struct {
+type pipeline005 struct {
ID int64 `json:"id" xorm:"pk autoincr 'pipeline_id'"`
Error string `json:"error" xorm:"LONGTEXT 'pipeline_error'"` // old error format
Errors []*errorTypes.PipelineError `json:"errors" xorm:"json 'pipeline_errors'"` // new error format
}
-func (pipeline027) TableName() string {
+func (pipeline005) TableName() string {
return "pipelines"
}
-type PipelineError027 struct {
+type PipelineError005 struct {
Type string `json:"type"`
Message string `json:"message"`
IsWarning bool `json:"is_warning"`
@@ -46,23 +46,23 @@ var convertToNewPipelineErrorFormat = xormigrate.Migration{
Long: true,
MigrateSession: func(sess *xorm.Session) (err error) {
// make sure pipeline_error column exists
- if err := sess.Sync(new(pipeline027)); err != nil {
+ if err := sess.Sync(new(pipeline005)); err != nil {
return err
}
page := 0
- oldPipelines := make([]*pipeline027, 0, perPage027)
+ oldPipelines := make([]*pipeline005, 0, perPage005)
for {
oldPipelines = oldPipelines[:0]
- err := sess.Limit(perPage027, page*perPage027).Cols("pipeline_id", "pipeline_error").Where("pipeline_error != ''").Find(&oldPipelines)
+ err := sess.Limit(perPage005, page*perPage005).Cols("pipeline_id", "pipeline_error").Where("pipeline_error != ''").Find(&oldPipelines)
if err != nil {
return err
}
for _, oldPipeline := range oldPipelines {
- var newPipeline pipeline027
+ var newPipeline pipeline005
newPipeline.ID = oldPipeline.ID
newPipeline.Errors = []*errorTypes.PipelineError{{
Type: "generic",
@@ -74,7 +74,7 @@ var convertToNewPipelineErrorFormat = xormigrate.Migration{
}
}
- if len(oldPipelines) < perPage027 {
+ if len(oldPipelines) < perPage005 {
break
}
diff --git a/server/store/datastore/migration/028_link_to_url.go b/server/store/datastore/migration/006_link_to_url.go
similarity index 100%
rename from server/store/datastore/migration/028_link_to_url.go
rename to server/store/datastore/migration/006_link_to_url.go
diff --git a/server/store/datastore/migration/029_clean_registry_pipeline.go b/server/store/datastore/migration/007_clean_registry_pipeline.go
similarity index 89%
rename from server/store/datastore/migration/029_clean_registry_pipeline.go
rename to server/store/datastore/migration/007_clean_registry_pipeline.go
index 21eb4277b..a0b5dba87 100644
--- a/server/store/datastore/migration/029_clean_registry_pipeline.go
+++ b/server/store/datastore/migration/007_clean_registry_pipeline.go
@@ -19,17 +19,17 @@ import (
"xorm.io/xorm"
)
-type oldRegistry029 struct {
+type oldRegistry007 struct {
ID int64 `json:"id" xorm:"pk autoincr 'registry_id'"`
Token string `json:"token" xorm:"TEXT 'registry_token'"`
Email string `json:"email" xorm:"varchar(500) 'registry_email'"`
}
-func (oldRegistry029) TableName() string {
+func (oldRegistry007) TableName() string {
return "registry"
}
-type oldPipeline029 struct {
+type oldPipeline007 struct {
ID int64 `json:"id" xorm:"pk autoincr 'pipeline_id'"`
ConfigID int64 `json:"-" xorm:"pipeline_config_id"`
Enqueued int64 `json:"enqueued_at" xorm:"pipeline_enqueued"`
@@ -37,14 +37,14 @@ type oldPipeline029 struct {
}
// TableName return database table name for xorm.
-func (oldPipeline029) TableName() string {
+func (oldPipeline007) TableName() string {
return "pipelines"
}
var cleanRegistryPipeline = xormigrate.Migration{
ID: "clean-registry-pipeline",
MigrateSession: func(sess *xorm.Session) (err error) {
- if err := sess.Sync(new(oldRegistry029), new(oldPipeline029)); err != nil {
+ if err := sess.Sync(new(oldRegistry007), new(oldPipeline007)); err != nil {
return err
}
diff --git a/server/store/datastore/migration/007_log_data_type.go b/server/store/datastore/migration/007_log_data_type.go
deleted file mode 100644
index cb70c5d2c..000000000
--- a/server/store/datastore/migration/007_log_data_type.go
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2023 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 (
- "src.techknowlogick.com/xormigrate"
- "xorm.io/xorm"
- "xorm.io/xorm/schemas"
-)
-
-var alterTableLogUpdateColumnLogDataType = xormigrate.Migration{
- ID: "alter-table-logs-update-type-of-data",
- MigrateSession: func(sess *xorm.Session) (err error) {
- dialect := sess.Engine().Dialect().URI().DBType
-
- switch dialect {
- case schemas.POSTGRES:
- _, err = sess.Exec("ALTER TABLE logs ALTER COLUMN log_data TYPE BYTEA")
- case schemas.MYSQL:
- _, err = sess.Exec("ALTER TABLE logs MODIFY COLUMN log_data LONGBLOB")
- default:
- // sqlite does only know BLOB in all cases
- return nil
- }
-
- return err
- },
-}
diff --git a/server/store/datastore/migration/008_secrets_add_user.go b/server/store/datastore/migration/008_secrets_add_user.go
deleted file mode 100644
index 6755a3b62..000000000
--- a/server/store/datastore/migration/008_secrets_add_user.go
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2022 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 (
- "src.techknowlogick.com/xormigrate"
- "xorm.io/xorm"
-)
-
-type SecretV008 struct {
- Owner string `json:"-" xorm:"NOT NULL DEFAULT '' UNIQUE(s) INDEX 'secret_owner'"`
- RepoID int64 `json:"-" xorm:"NOT NULL DEFAULT 0 UNIQUE(s) INDEX 'secret_repo_id'"`
- Name string `json:"name" xorm:"NOT NULL UNIQUE(s) INDEX 'secret_name'"`
-}
-
-// TableName return database table name for xorm.
-func (SecretV008) TableName() string {
- return "secrets"
-}
-
-var alterTableSecretsAddUserCol = xormigrate.Migration{
- ID: "alter-table-add-secrets-user-id",
- MigrateSession: func(sess *xorm.Session) error {
- if err := sess.Sync(new(SecretV008)); err != nil {
- return err
- }
- if err := alterColumnDefault(sess, "secrets", "secret_repo_id", "0"); err != nil {
- return err
- }
- if err := alterColumnNull(sess, "secrets", "secret_repo_id", false); err != nil {
- return err
- }
- return alterColumnNull(sess, "secrets", "secret_name", false)
- },
-}
diff --git a/server/store/datastore/migration/008_set_default_forge_id.go b/server/store/datastore/migration/008_set_default_forge_id.go
new file mode 100644
index 000000000..4edc817f9
--- /dev/null
+++ b/server/store/datastore/migration/008_set_default_forge_id.go
@@ -0,0 +1,115 @@
+// 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/xorm"
+
+ "go.woodpecker-ci.org/woodpecker/v2/server/model"
+)
+
+type userV008 struct {
+ ID int64 `xorm:"pk autoincr 'user_id'"`
+ ForgeID int64 `xorm:"forge_id"`
+ ForgeRemoteID model.ForgeRemoteID `xorm:"forge_remote_id"`
+ Login string `xorm:"UNIQUE 'user_login'"`
+ Token string `xorm:"TEXT 'user_token'"`
+ Secret string `xorm:"TEXT 'user_secret'"`
+ Expiry int64 `xorm:"user_expiry"`
+ Email string `xorm:" varchar(500) 'user_email'"`
+ Avatar string `xorm:" varchar(500) 'user_avatar'"`
+ Admin bool `xorm:"user_admin"`
+ Hash string `xorm:"UNIQUE varchar(500) 'user_hash'"`
+ OrgID int64 `xorm:"user_org_id"`
+}
+
+func (userV008) TableName() string {
+ return "users"
+}
+
+type repoV008 struct {
+ ID int64 `xorm:"pk autoincr 'repo_id'"`
+ UserID int64 `xorm:"repo_user_id"`
+ ForgeID int64 `xorm:"forge_id"`
+ ForgeRemoteID model.ForgeRemoteID `xorm:"forge_remote_id"`
+ OrgID int64 `xorm:"repo_org_id"`
+ Owner string `xorm:"UNIQUE(name) 'repo_owner'"`
+ Name string `xorm:"UNIQUE(name) 'repo_name'"`
+ FullName string `xorm:"UNIQUE 'repo_full_name'"`
+ Avatar string `xorm:"varchar(500) 'repo_avatar'"`
+ ForgeURL string `xorm:"varchar(1000) 'repo_forge_url'"`
+ Clone string `xorm:"varchar(1000) 'repo_clone'"`
+ CloneSSH string `xorm:"varchar(1000) 'repo_clone_ssh'"`
+ Branch string `xorm:"varchar(500) 'repo_branch'"`
+ SCMKind model.SCMKind `xorm:"varchar(50) 'repo_scm'"`
+ PREnabled bool `xorm:"DEFAULT TRUE 'repo_pr_enabled'"`
+ Timeout int64 `xorm:"repo_timeout"`
+ Visibility model.RepoVisibility `xorm:"varchar(10) 'repo_visibility'"`
+ IsSCMPrivate bool `xorm:"repo_private"`
+ IsTrusted bool `xorm:"repo_trusted"`
+ IsGated bool `xorm:"repo_gated"`
+ IsActive bool `xorm:"repo_active"`
+ AllowPull bool `xorm:"repo_allow_pr"`
+ AllowDeploy bool `xorm:"repo_allow_deploy"`
+ Config string `xorm:"varchar(500) 'repo_config_path'"`
+ Hash string `xorm:"varchar(500) 'repo_hash'"`
+ Perm *model.Perm `xorm:"-"`
+ CancelPreviousPipelineEvents []model.WebhookEvent `xorm:"json 'cancel_previous_pipeline_events'"`
+ NetrcOnlyTrusted bool `xorm:"NOT NULL DEFAULT true 'netrc_only_trusted'"`
+}
+
+func (repoV008) TableName() string {
+ return "repos"
+}
+
+type forgeV008 struct {
+ ID int64 `xorm:"pk autoincr 'id'"`
+ Type model.ForgeType `xorm:"VARCHAR(250) 'type'"`
+ URL string `xorm:"VARCHAR(500) 'url'"`
+ Client string `xorm:"VARCHAR(250) 'client'"`
+ ClientSecret string `xorm:"VARCHAR(250) 'client_secret'"`
+ SkipVerify bool `xorm:"bool 'skip_verify'"`
+ OAuthHost string `xorm:"VARCHAR(250) 'oauth_host'"` // public url for oauth if different from url
+ AdditionalOptions map[string]any `xorm:"json 'additional_options'"`
+}
+
+func (forgeV008) TableName() string {
+ return "forge"
+}
+
+var setForgeID = xormigrate.Migration{
+ ID: "set-forge-id",
+ MigrateSession: func(sess *xorm.Session) (err error) {
+ if err := sess.Sync(new(userV008), new(repoV008), new(forgeV008), new(model.Org)); err != nil {
+ return fmt.Errorf("sync new models failed: %w", err)
+ }
+
+ _, err = sess.Exec(fmt.Sprintf("UPDATE `%s` SET forge_id=1;", userV008{}.TableName()))
+ if err != nil {
+ return err
+ }
+
+ _, err = sess.Exec(fmt.Sprintf("UPDATE `%s` SET forge_id=1;", model.Org{}.TableName()))
+ if err != nil {
+ return err
+ }
+
+ _, err = sess.Exec(fmt.Sprintf("UPDATE `%s` SET forge_id=1;", repoV008{}.TableName()))
+ return err
+ },
+}
diff --git a/server/store/datastore/migration/009_recreate_agents_table.go b/server/store/datastore/migration/009_recreate_agents_table.go
deleted file mode 100644
index b0a8d1f60..000000000
--- a/server/store/datastore/migration/009_recreate_agents_table.go
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2022 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 (
- "src.techknowlogick.com/xormigrate"
- "xorm.io/xorm"
-
- "go.woodpecker-ci.org/woodpecker/v2/server/model"
-)
-
-var recreateAgentsTable = xormigrate.Migration{
- ID: "recreate-agents-table",
- MigrateSession: func(sess *xorm.Session) error {
- if err := sess.DropTable("agents"); err != nil {
- return err
- }
- return sess.Sync(new(model.Agent))
- },
-}
diff --git a/server/store/datastore/migration/009_unify_columns_tables.go b/server/store/datastore/migration/009_unify_columns_tables.go
new file mode 100644
index 000000000..db8578b2f
--- /dev/null
+++ b/server/store/datastore/migration/009_unify_columns_tables.go
@@ -0,0 +1,641 @@
+// 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/xorm"
+
+ "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors/types"
+ "go.woodpecker-ci.org/woodpecker/v2/server/model"
+)
+
+type configV009 struct {
+ ID int64 `xorm:"pk autoincr 'config_id'"`
+ RepoID int64 `xorm:"UNIQUE(s) 'config_repo_id'"`
+ Hash string `xorm:"UNIQUE(s) 'config_hash'"`
+ Name string `xorm:"UNIQUE(s) 'config_name'"`
+ Data []byte `xorm:"LONGBLOB 'config_data'"`
+}
+
+func (configV009) TableName() string {
+ return "config"
+}
+
+type cronV009 struct {
+ ID int64 `xorm:"pk autoincr 'i_d'"`
+ Name string `xorm:"name UNIQUE(s) INDEX"`
+ RepoID int64 `xorm:"repo_id UNIQUE(s) INDEX"`
+ CreatorID int64 `xorm:"creator_id INDEX"`
+ NextExec int64 `xorm:"next_exec"`
+ Schedule string `xorm:"schedule NOT NULL"`
+ Created int64 `xorm:"created NOT NULL DEFAULT 0"`
+ Branch string `xorm:"branch"`
+}
+
+func (cronV009) TableName() string {
+ return "crons"
+}
+
+type permV009 struct {
+ UserID int64 `xorm:"UNIQUE(s) INDEX NOT NULL 'perm_user_id'"`
+ RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL 'perm_repo_id'"`
+ Pull bool `xorm:"perm_pull"`
+ Push bool `xorm:"perm_push"`
+ Admin bool `xorm:"perm_admin"`
+ Synced int64 `xorm:"perm_synced"`
+}
+
+func (permV009) TableName() string {
+ return "perms"
+}
+
+type pipelineV009 struct {
+ ID int64 `xorm:"pk autoincr 'pipeline_id'"`
+ RepoID int64 `xorm:"UNIQUE(s) INDEX 'pipeline_repo_id'"`
+ Number int64 `xorm:"UNIQUE(s) 'pipeline_number'"`
+ Author string `xorm:"INDEX 'pipeline_author'"`
+ Parent int64 `xorm:"pipeline_parent"`
+ Event model.WebhookEvent `xorm:"pipeline_event"`
+ Status model.StatusValue `xorm:"INDEX 'pipeline_status'"`
+ Errors []*types.PipelineError `xorm:"json 'pipeline_errors'"`
+ Created int64 `xorm:"pipeline_created"`
+ Started int64 `xorm:"pipeline_started"`
+ Finished int64 `xorm:"pipeline_finished"`
+ Deploy string `xorm:"pipeline_deploy"`
+ DeployTask string `xorm:"pipeline_deploy_task"`
+ Commit string `xorm:"pipeline_commit"`
+ Branch string `xorm:"pipeline_branch"`
+ Ref string `xorm:"pipeline_ref"`
+ Refspec string `xorm:"pipeline_refspec"`
+ Title string `xorm:"pipeline_title"`
+ Message string `xorm:"TEXT 'pipeline_message'"`
+ Timestamp int64 `xorm:"pipeline_timestamp"`
+ Sender string `xorm:"pipeline_sender"` // uses reported user for webhooks and name of cron for cron pipelines
+ Avatar string `xorm:"pipeline_avatar"`
+ Email string `xorm:"pipeline_email"`
+ ForgeURL string `xorm:"pipeline_forge_url"`
+ Reviewer string `xorm:"pipeline_reviewer"`
+ Reviewed int64 `xorm:"pipeline_reviewed"`
+}
+
+func (pipelineV009) TableName() string {
+ return "pipelines"
+}
+
+type redirectionV009 struct {
+ ID int64 `xorm:"pk autoincr 'redirection_id'"`
+}
+
+func (r redirectionV009) TableName() string {
+ return "redirections"
+}
+
+type registryV009 struct {
+ ID int64 `xorm:"pk autoincr 'registry_id'"`
+ RepoID int64 `xorm:"UNIQUE(s) INDEX 'registry_repo_id'"`
+ Address string `xorm:"UNIQUE(s) INDEX 'registry_addr'"`
+ Username string `xorm:"varchar(2000) 'registry_username'"`
+ Password string `xorm:"TEXT 'registry_password'"`
+}
+
+func (registryV009) TableName() string {
+ return "registry"
+}
+
+type repoV009 struct {
+ ID int64 `xorm:"pk autoincr 'repo_id'"`
+ UserID int64 `xorm:"repo_user_id"`
+ OrgID int64 `xorm:"repo_org_id"`
+ Owner string `xorm:"UNIQUE(name) 'repo_owner'"`
+ Name string `xorm:"UNIQUE(name) 'repo_name'"`
+ FullName string `xorm:"UNIQUE 'repo_full_name'"`
+ Avatar string `xorm:"varchar(500) 'repo_avatar'"`
+ ForgeURL string `xorm:"varchar(1000) 'repo_forge_url'"`
+ Clone string `xorm:"varchar(1000) 'repo_clone'"`
+ CloneSSH string `xorm:"varchar(1000) 'repo_clone_ssh'"`
+ Branch string `xorm:"varchar(500) 'repo_branch'"`
+ SCMKind model.SCMKind `xorm:"varchar(50) 'repo_scm'"`
+ PREnabled bool `xorm:"DEFAULT TRUE 'repo_pr_enabled'"`
+ Timeout int64 `xorm:"repo_timeout"`
+ Visibility model.RepoVisibility `xorm:"varchar(10) 'repo_visibility'"`
+ IsSCMPrivate bool `xorm:"repo_private"`
+ IsTrusted bool `xorm:"repo_trusted"`
+ IsGated bool `xorm:"repo_gated"`
+ IsActive bool `xorm:"repo_active"`
+ AllowPull bool `xorm:"repo_allow_pr"`
+ AllowDeploy bool `xorm:"repo_allow_deploy"`
+ Config string `xorm:"varchar(500) 'repo_config_path'"`
+ Hash string `xorm:"varchar(500) 'repo_hash'"`
+}
+
+func (repoV009) TableName() string {
+ return "repos"
+}
+
+type secretV009 struct {
+ ID int64 `xorm:"pk autoincr 'secret_id'"`
+ OrgID int64 `xorm:"NOT NULL DEFAULT 0 UNIQUE(s) INDEX 'secret_org_id'"`
+ RepoID int64 `xorm:"NOT NULL DEFAULT 0 UNIQUE(s) INDEX 'secret_repo_id'"`
+ Name string `xorm:"NOT NULL UNIQUE(s) INDEX 'secret_name'"`
+ Value string `xorm:"TEXT 'secret_value'"`
+ Images []string `xorm:"json 'secret_images'"`
+ Events []model.WebhookEvent `xorm:"json 'secret_events'"`
+}
+
+func (secretV009) TableName() string {
+ return "secrets"
+}
+
+type stepV009 struct {
+ ID int64 `xorm:"pk autoincr 'step_id'"`
+ UUID string `xorm:"INDEX 'step_uuid'"`
+ PipelineID int64 `xorm:"UNIQUE(s) INDEX 'step_pipeline_id'"`
+ PID int `xorm:"UNIQUE(s) 'step_pid'"`
+ PPID int `xorm:"step_ppid"`
+ Name string `xorm:"step_name"`
+ State model.StatusValue `xorm:"step_state"`
+ Error string `xorm:"TEXT 'step_error'"`
+ Failure string `xorm:"step_failure"`
+ ExitCode int `xorm:"step_exit_code"`
+ Started int64 `xorm:"step_started"`
+ Stopped int64 `xorm:"step_stopped"`
+ Type model.StepType `xorm:"step_type"`
+}
+
+func (stepV009) TableName() string {
+ return "steps"
+}
+
+type taskV009 struct {
+ ID string `xorm:"PK UNIQUE 'task_id'"`
+ Data []byte `xorm:"LONGBLOB 'task_data'"`
+ Labels map[string]string `xorm:"json 'task_labels'"`
+ Dependencies []string `xorm:"json 'task_dependencies'"`
+ RunOn []string `xorm:"json 'task_run_on'"`
+ DepStatus map[string]model.StatusValue `xorm:"json 'task_dep_status'"`
+}
+
+func (taskV009) TableName() string {
+ return "tasks"
+}
+
+type userV009 struct {
+ ID int64 `xorm:"pk autoincr 'user_id'"`
+ Login string `xorm:"UNIQUE 'user_login'"`
+ Token string `xorm:"TEXT 'user_token'"`
+ Secret string `xorm:"TEXT 'user_secret'"`
+ Expiry int64 `xorm:"user_expiry"`
+ Email string `xorm:" varchar(500) 'user_email'"`
+ Avatar string `xorm:" varchar(500) 'user_avatar'"`
+ Admin bool `xorm:"user_admin"`
+ Hash string `xorm:"UNIQUE varchar(500) 'user_hash'"`
+ OrgID int64 `xorm:"user_org_id"`
+}
+
+func (userV009) TableName() string {
+ return "users"
+}
+
+type workflowV009 struct {
+ ID int64 `xorm:"pk autoincr 'workflow_id'"`
+ PipelineID int64 `xorm:"UNIQUE(s) INDEX 'workflow_pipeline_id'"`
+ PID int `xorm:"UNIQUE(s) 'workflow_pid'"`
+ Name string `xorm:"workflow_name"`
+ State model.StatusValue `xorm:"workflow_state"`
+ Error string `xorm:"TEXT 'workflow_error'"`
+ Started int64 `xorm:"workflow_started"`
+ Stopped int64 `xorm:"workflow_stopped"`
+ AgentID int64 `xorm:"workflow_agent_id"`
+ Platform string `xorm:"workflow_platform"`
+ Environ map[string]string `xorm:"json 'workflow_environ'"`
+ AxisID int `xorm:"workflow_axis_id"`
+}
+
+func (workflowV009) TableName() string {
+ return "workflows"
+}
+
+type serverConfigV009 struct {
+ Key string `xorm:"pk 'key'"`
+ Value string `xorm:"value"`
+}
+
+func (serverConfigV009) TableName() string {
+ return "server_config"
+}
+
+var unifyColumnsTables = xormigrate.Migration{
+ ID: "unify-columns-tables",
+ MigrateSession: func(sess *xorm.Session) (err error) {
+ if err := sess.Sync(new(configV009), new(cronV009), new(permV009), new(pipelineV009), new(redirectionV009), new(registryV009), new(repoV009), new(secretV009), new(stepV009), new(taskV009), new(userV009), new(workflowV009), new(serverConfigV009)); err != nil {
+ return fmt.Errorf("sync models failed: %w", err)
+ }
+
+ // Config
+ if err := renameColumn(sess, "config", "config_id", "id"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "config", "config_repo_id", "repo_id"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "config", "config_hash", "hash"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "config", "config_name", "name"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "config", "config_data", "data"); err != nil {
+ return err
+ }
+ if err := renameTable(sess, "config", "configs"); err != nil {
+ return err
+ }
+
+ // PipelineConfig
+ if err := renameTable(sess, "pipeline_config", "pipeline_configs"); err != nil {
+ return err
+ }
+
+ // Cron
+ if err := renameColumn(sess, "crons", "i_d", "id"); err != nil {
+ return err
+ }
+
+ // Forge
+ if err := renameTable(sess, "forge", "forges"); err != nil {
+ return err
+ }
+
+ // Perm
+ if err := renameColumn(sess, "perms", "perm_user_id", "user_id"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "perms", "perm_repo_id", "repo_id"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "perms", "perm_pull", "pull"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "perms", "perm_push", "push"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "perms", "perm_admin", "admin"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "perms", "perm_synced", "synced"); err != nil {
+ return err
+ }
+
+ // Pipeline
+ if err := renameColumn(sess, "pipelines", "pipeline_id", "id"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_repo_id", "repo_id"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_number", "number"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_author", "author"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_parent", "parent"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_event", "event"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_status", "status"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_errors", "errors"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_created", "created"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_started", "started"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_finished", "finished"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_deploy", "deploy"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_deploy_task", "deploy_task"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_commit", "commit"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_branch", "branch"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_ref", "ref"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_refspec", "refspec"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_title", "title"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_message", "message"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_timestamp", "timestamp"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_sender", "sender"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_avatar", "avatar"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_email", "email"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_forge_url", "forge_url"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_reviewer", "reviewer"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "pipelines", "pipeline_reviewed", "reviewed"); err != nil {
+ return err
+ }
+
+ // Redirection
+ if err := renameColumn(sess, "redirections", "redirection_id", "id"); err != nil {
+ return err
+ }
+
+ // Registry
+ if err := renameColumn(sess, "registry", "registry_id", "id"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "registry", "registry_repo_id", "repo_id"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "registry", "registry_addr", "address"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "registry", "registry_username", "username"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "registry", "registry_password", "password"); err != nil {
+ return err
+ }
+ if err := renameTable(sess, "registry", "registries"); err != nil {
+ return err
+ }
+
+ // Repo
+ if err := renameColumn(sess, "repos", "repo_id", "id"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "repos", "repo_user_id", "user_id"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "repos", "repo_org_id", "org_id"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "repos", "repo_owner", "owner"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "repos", "repo_name", "name"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "repos", "repo_full_name", "full_name"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "repos", "repo_avatar", "avatar"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "repos", "repo_forge_url", "forge_url"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "repos", "repo_clone", "clone"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "repos", "repo_clone_ssh", "clone_ssh"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "repos", "repo_branch", "branch"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "repos", "repo_scm", "scm"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "repos", "repo_pr_enabled", "pr_enabled"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "repos", "repo_timeout", "timeout"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "repos", "repo_visibility", "visibility"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "repos", "repo_private", "private"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "repos", "repo_trusted", "trusted"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "repos", "repo_gated", "gated"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "repos", "repo_active", "active"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "repos", "repo_allow_pr", "allow_pr"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "repos", "repo_allow_deploy", "allow_deploy"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "repos", "repo_config_path", "config_path"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "repos", "repo_hash", "hash"); err != nil {
+ return err
+ }
+
+ // Secrets
+ if err := renameColumn(sess, "secrets", "secret_id", "id"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "secrets", "secret_org_id", "org_id"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "secrets", "secret_repo_id", "repo_id"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "secrets", "secret_name", "name"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "secrets", "secret_value", "value"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "secrets", "secret_images", "images"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "secrets", "secret_events", "events"); err != nil {
+ return err
+ }
+
+ // ServerConfig
+ if err := renameTable(sess, "server_config", "server_configs"); err != nil {
+ return err
+ }
+
+ // Step
+ if err := renameColumn(sess, "steps", "step_id", "id"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "steps", "step_uuid", "uuid"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "steps", "step_pipeline_id", "pipeline_id"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "steps", "step_pid", "pid"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "steps", "step_ppid", "ppid"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "steps", "step_name", "name"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "steps", "step_state", "state"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "steps", "step_error", "error"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "steps", "step_failure", "failure"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "steps", "step_exit_code", "exit_code"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "steps", "step_started", "started"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "steps", "step_stopped", "stopped"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "steps", "step_type", "type"); err != nil {
+ return err
+ }
+
+ // Task
+ if err := renameColumn(sess, "tasks", "task_id", "id"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "tasks", "task_data", "data"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "tasks", "task_labels", "labels"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "tasks", "task_dependencies", "dependencies"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "tasks", "task_run_on", "run_on"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "tasks", "task_dep_status", "dependencies_status"); err != nil {
+ return err
+ }
+
+ // User
+ if err := renameColumn(sess, "users", "user_id", "id"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "users", "user_login", "login"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "users", "user_token", "token"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "users", "user_secret", "secret"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "users", "user_expiry", "expiry"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "users", "user_email", "email"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "users", "user_avatar", "avatar"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "users", "user_admin", "admin"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "users", "user_hash", "hash"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "users", "user_org_id", "org_id"); err != nil {
+ return err
+ }
+
+ // Workflow
+ if err := renameColumn(sess, "workflows", "workflow_id", "id"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "workflows", "workflow_pipeline_id", "pipeline_id"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "workflows", "workflow_pid", "pid"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "workflows", "workflow_name", "name"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "workflows", "workflow_state", "state"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "workflows", "workflow_error", "error"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "workflows", "workflow_started", "started"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "workflows", "workflow_stopped", "stopped"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "workflows", "workflow_agent_id", "agent_id"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "workflows", "workflow_platform", "platform"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "workflows", "workflow_environ", "environ"); err != nil {
+ return err
+ }
+ if err := renameColumn(sess, "workflows", "workflow_axis_id", "axis_id"); err != nil {
+ return err
+ }
+
+ return nil
+ },
+}
diff --git a/server/store/datastore/migration/010_rename_builds_to_pipeline.go b/server/store/datastore/migration/010_registries_add_user.go
similarity index 61%
rename from server/store/datastore/migration/010_rename_builds_to_pipeline.go
rename to server/store/datastore/migration/010_registries_add_user.go
index 9fd042425..df8d29eb6 100644
--- a/server/store/datastore/migration/010_rename_builds_to_pipeline.go
+++ b/server/store/datastore/migration/010_registries_add_user.go
@@ -1,10 +1,10 @@
-// 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.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -19,17 +19,15 @@ import (
"xorm.io/xorm"
)
-var renameBuildsToPipeline = xormigrate.Migration{
- ID: "rename-builds-to-pipeline",
+var alterTableRegistriesFixRequiredFields = xormigrate.Migration{
+ ID: "alter-table-registries-fix-required-fields",
MigrateSession: func(sess *xorm.Session) error {
- err := renameTable(sess, "builds", "pipelines")
- if err != nil {
+ if err := alterColumnDefault(sess, "registries", "repo_id", "0"); err != nil {
return err
}
- err = renameTable(sess, "build_config", "pipeline_config")
- if err != nil {
+ if err := alterColumnNull(sess, "registries", "repo_id", false); err != nil {
return err
}
- return nil
+ return alterColumnNull(sess, "registries", "address", false)
},
}
diff --git a/server/store/datastore/migration/011_columns_rename_builds_to_pipeline.go b/server/store/datastore/migration/011_columns_rename_builds_to_pipeline.go
deleted file mode 100644
index b80a465e5..000000000
--- a/server/store/datastore/migration/011_columns_rename_builds_to_pipeline.go
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2022 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 (
- "strings"
-
- "src.techknowlogick.com/xormigrate"
- "xorm.io/xorm"
-)
-
-type oldTable struct {
- table string
- columns []string
-}
-
-var renameColumnsBuildsToPipeline = xormigrate.Migration{
- ID: "rename-columns-builds-to-pipeline",
- MigrateSession: func(sess *xorm.Session) error {
- var oldColumns []*oldTable
-
- oldColumns = append(oldColumns, &oldTable{
- table: "pipelines",
- columns: []string{
- "build_id",
- "build_repo_id",
- "build_number",
- "build_author",
- "build_config_id",
- "build_parent",
- "build_event",
- "build_status",
- "build_error",
- "build_enqueued",
- "build_created",
- "build_started",
- "build_finished",
- "build_deploy",
- "build_commit",
- "build_branch",
- "build_ref",
- "build_refspec",
- "build_remote",
- "build_title",
- "build_message",
- "build_timestamp",
- "build_sender",
- "build_avatar",
- "build_email",
- "build_link",
- "build_signed",
- "build_verified",
- "build_reviewer",
- "build_reviewed",
- },
- },
- )
-
- oldColumns = append(oldColumns, &oldTable{
- table: "pipeline_config",
- columns: []string{"build_id"},
- })
-
- oldColumns = append(oldColumns, &oldTable{
- table: "files",
- columns: []string{"file_build_id"},
- })
-
- oldColumns = append(oldColumns, &oldTable{
- table: "procs",
- columns: []string{"proc_build_id"},
- })
-
- for _, table := range oldColumns {
- for _, column := range table.columns {
- err := renameColumn(sess, table.table, column, strings.Replace(column, "build_", "pipeline_", 1))
- if err != nil {
- return err
- }
- }
- }
-
- return nil
- },
-}
diff --git a/server/store/datastore/migration/030_set_default_forge_id.go b/server/store/datastore/migration/011_cron_without_sec.go
similarity index 59%
rename from server/store/datastore/migration/030_set_default_forge_id.go
rename to server/store/datastore/migration/011_cron_without_sec.go
index 994ebee16..12e5b257f 100644
--- a/server/store/datastore/migration/030_set_default_forge_id.go
+++ b/server/store/datastore/migration/011_cron_without_sec.go
@@ -16,6 +16,7 @@ package migration
import (
"fmt"
+ "strings"
"src.techknowlogick.com/xormigrate"
"xorm.io/xorm"
@@ -23,24 +24,31 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/server/model"
)
-var setForgeID = xormigrate.Migration{
- ID: "set-forge-id",
- MigrateSession: func(sess *xorm.Session) (err error) {
- if err := sess.Sync(new(model.User), new(model.Repo), new(model.Forge), new(model.Org)); err != nil {
+var cronWithoutSec = xormigrate.Migration{
+ ID: "cron-without-sec",
+ MigrateSession: func(sess *xorm.Session) error {
+ if err := sess.Sync(new(model.Cron)); err != nil {
return fmt.Errorf("sync new models failed: %w", err)
}
- _, err = sess.Exec(fmt.Sprintf("UPDATE `%s` SET forge_id=1;", model.User{}.TableName()))
- if err != nil {
+ var crons []*model.Cron
+ if err := sess.Find(&crons); err != nil {
return err
}
- _, err = sess.Exec(fmt.Sprintf("UPDATE `%s` SET forge_id=1;", model.Org{}.TableName()))
- if err != nil {
- return err
+ for _, c := range crons {
+ if strings.HasPrefix(strings.TrimSpace(c.Schedule), "@") {
+ // something like "@daily"
+ continue
+ }
+
+ if _, err := sess.Update(&model.Cron{
+ Schedule: strings.SplitN(strings.TrimSpace(c.Schedule), " ", 2)[1],
+ }, c); err != nil {
+ return err
+ }
}
- _, err = sess.Exec(fmt.Sprintf("UPDATE `%s` SET forge_id=1;", model.Repo{}.TableName()))
- return err
+ return nil
},
}
diff --git a/server/store/datastore/migration/012_columns_rename_procs_to_steps.go b/server/store/datastore/migration/012_columns_rename_procs_to_steps.go
deleted file mode 100644
index 015bdac4f..000000000
--- a/server/store/datastore/migration/012_columns_rename_procs_to_steps.go
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2022 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 (
- "strings"
-
- "src.techknowlogick.com/xormigrate"
- "xorm.io/xorm"
-)
-
-var renameTableProcsToSteps = xormigrate.Migration{
- ID: "rename-procs-to-steps",
- MigrateSession: func(sess *xorm.Session) error {
- err := renameTable(sess, "procs", "steps")
- if err != nil {
- return err
- }
-
- oldProcColumns := []*oldTable{
- {
- table: "steps",
- columns: []string{
- "proc_id",
- "proc_pipeline_id",
- "proc_pid",
- "proc_ppid",
- "proc_pgid",
- "proc_name",
- "proc_state",
- "proc_error",
- "proc_exit_code",
- "proc_started",
- "proc_stopped",
- "proc_machine",
- "proc_platform",
- "proc_environ",
- },
- },
- {
- table: "files",
- columns: []string{"file_proc_id"},
- },
- }
-
- for _, table := range oldProcColumns {
- for _, column := range table.columns {
- err := renameColumn(sess, table.table, column, strings.Replace(column, "proc_", "step_", 1))
- if err != nil {
- return err
- }
- }
- }
-
- oldJobColumns := []*oldTable{
- {
- table: "logs",
- columns: []string{
- "log_job_id",
- },
- },
- }
-
- for _, table := range oldJobColumns {
- for _, column := range table.columns {
- err := renameColumn(sess, table.table, column, strings.Replace(column, "job_", "step_", 1))
- if err != nil {
- return err
- }
- }
- }
-
- return nil
- },
-}
diff --git a/server/store/datastore/migration/012_rename_start_end_time.go b/server/store/datastore/migration/012_rename_start_end_time.go
new file mode 100644
index 000000000..e710c7f0a
--- /dev/null
+++ b/server/store/datastore/migration/012_rename_start_end_time.go
@@ -0,0 +1,59 @@
+// 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/xorm"
+)
+
+type stepV012 struct {
+ Finished int64 `xorm:"stopped"`
+}
+
+func (stepV012) TableName() string {
+ return "steps"
+}
+
+type workflowV012 struct {
+ Finished int64 `xorm:"stopped"`
+}
+
+func (workflowV012) TableName() string {
+ return "workflows"
+}
+
+var renameStartEndTime = xormigrate.Migration{
+ ID: "rename-start-end-time",
+ MigrateSession: func(sess *xorm.Session) (err error) {
+ if err := sess.Sync(new(stepV012), new(workflowV012)); err != nil {
+ return fmt.Errorf("sync models failed: %w", err)
+ }
+
+ // Step
+ if err := renameColumn(sess, "steps", "stopped", "finished"); err != nil {
+ return err
+ }
+
+ // Workflow
+ if err := renameColumn(sess, "workflows", "stopped", "finished"); err != nil {
+ return err
+ }
+
+ return nil
+ },
+}
diff --git a/server/store/datastore/migration/009_lowercase_secret_names.go b/server/store/datastore/migration/013_fix_v31_registries.go
similarity index 67%
rename from server/store/datastore/migration/009_lowercase_secret_names.go
rename to server/store/datastore/migration/013_fix_v31_registries.go
index 5402dc36c..988e49541 100644
--- a/server/store/datastore/migration/009_lowercase_secret_names.go
+++ b/server/store/datastore/migration/013_fix_v31_registries.go
@@ -1,10 +1,10 @@
-// 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.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -19,10 +19,17 @@ import (
"xorm.io/xorm"
)
-var lowercaseSecretNames = xormigrate.Migration{
- ID: "lowercase-secret-names",
+var fixV31Registries = xormigrate.Migration{
+ ID: "fix-v31-registries",
MigrateSession: func(sess *xorm.Session) (err error) {
- _, err = sess.Exec("UPDATE secrets SET secret_name = LOWER(secret_name);")
- return err
+ has, err := sess.IsTableExist("registry_v031")
+ if err != nil {
+ return err
+ }
+ if has {
+ return sess.DropTable("registry_v031")
+ }
+
+ return nil
},
}
diff --git a/server/store/datastore/migration/013_rename_remote_to_forge.go b/server/store/datastore/migration/013_rename_remote_to_forge.go
deleted file mode 100644
index 78eff328b..000000000
--- a/server/store/datastore/migration/013_rename_remote_to_forge.go
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2022 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 (
- "src.techknowlogick.com/xormigrate"
- "xorm.io/xorm"
-)
-
-type oldRepo013 struct {
- ID int64 `xorm:"pk autoincr 'repo_id'"`
- RemoteID string `xorm:"remote_id"`
-}
-
-func (oldRepo013) TableName() string {
- return "repos"
-}
-
-var renameRemoteToForge = xormigrate.Migration{
- ID: "rename-remote-to-forge",
- MigrateSession: func(sess *xorm.Session) error {
- if err := renameColumn(sess, "pipelines", "pipeline_remote", "pipeline_clone_url"); err != nil {
- return err
- }
-
- // make sure the column exist before rename it
- if err := sess.Sync(new(oldRepo013)); err != nil {
- return err
- }
-
- return renameColumn(sess, "repos", "remote_id", "forge_id")
- },
-}
diff --git a/server/store/datastore/migration/014_remove_old_migrations_of_v1.go b/server/store/datastore/migration/014_remove_old_migrations_of_v1.go
new file mode 100644
index 000000000..5f49d559b
--- /dev/null
+++ b/server/store/datastore/migration/014_remove_old_migrations_of_v1.go
@@ -0,0 +1,54 @@
+// 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 (
+ "src.techknowlogick.com/xormigrate"
+ "xorm.io/xorm"
+)
+
+var removeOldMigrationsOfV1 = xormigrate.Migration{
+ ID: "remove-old-migrations-of-v1",
+ MigrateSession: func(sess *xorm.Session) (err error) {
+ _, err = sess.Table(&xormigrate.Migration{}).In("id", []string{
+ "xorm",
+ "alter-table-drop-repo-fallback",
+ "drop-allow-push-tags-deploys-columns",
+ "fix-pr-secret-event-name",
+ "alter-table-drop-counter",
+ "drop-senders",
+ "alter-table-logs-update-type-of-data",
+ "alter-table-add-secrets-user-id",
+ "lowercase-secret-names",
+ "recreate-agents-table",
+ "rename-builds-to-pipeline",
+ "rename-columns-builds-to-pipeline",
+ "rename-procs-to-steps",
+ "rename-remote-to-forge",
+ "rename-forge-id-to-forge-remote-id",
+ "remove-active-from-users",
+ "remove-inactive-repos",
+ "drop-files",
+ "remove-machine-col",
+ "drop-old-col",
+ "init-log_entries",
+ "migrate-logs-to-log_entries",
+ "parent-steps-to-workflows",
+ "add-orgs",
+ }).Delete()
+
+ return err
+ },
+}
diff --git a/server/store/datastore/migration/014_rename_forge_id_to_forge_remote_id.go b/server/store/datastore/migration/014_rename_forge_id_to_forge_remote_id.go
deleted file mode 100644
index 60a58660d..000000000
--- a/server/store/datastore/migration/014_rename_forge_id_to_forge_remote_id.go
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2022 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 (
- "src.techknowlogick.com/xormigrate"
- "xorm.io/xorm"
-)
-
-var renameForgeIDToForgeRemoteID = xormigrate.Migration{
- ID: "rename-forge-id-to-forge-remote-id",
- MigrateSession: func(sess *xorm.Session) error {
- return renameColumn(sess, "repos", "forge_id", "forge_remote_id")
- },
-}
diff --git a/server/store/datastore/migration/016_remove_inactive_repos.go b/server/store/datastore/migration/016_remove_inactive_repos.go
deleted file mode 100644
index 48742f89b..000000000
--- a/server/store/datastore/migration/016_remove_inactive_repos.go
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2022 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 (
- "src.techknowlogick.com/xormigrate"
- "xorm.io/xorm"
-)
-
-var removeInactiveRepos = xormigrate.Migration{
- ID: "remove-inactive-repos",
- MigrateSession: func(sess *xorm.Session) error {
- // If the timeout is 0, the repo was never activated, so we remove it.
- _, err := sess.Table("repos").Where("repo_active = ?", false).And("repo_timeout = ?", 0).Delete()
- if err != nil {
- return err
- }
-
- return dropTableColumns(sess, "users", "user_synced")
- },
-}
diff --git a/server/store/datastore/migration/018_remove_machine_col.go b/server/store/datastore/migration/018_remove_machine_col.go
deleted file mode 100644
index 791104479..000000000
--- a/server/store/datastore/migration/018_remove_machine_col.go
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2023 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 (
- "src.techknowlogick.com/xormigrate"
- "xorm.io/xorm"
-)
-
-type oldStep018 struct {
- ID int64 `xorm:"pk autoincr 'step_id'"`
- Machine string `xorm:"step_machine"`
-}
-
-func (oldStep018) TableName() string {
- return "steps"
-}
-
-var removeMachineCol = xormigrate.Migration{
- ID: "remove-machine-col",
- MigrateSession: func(sess *xorm.Session) error {
- // make sure step_machine column exists
- if err := sess.Sync(new(oldStep018)); err != nil {
- return err
- }
- return dropTableColumns(sess, "steps", "step_machine")
- },
-}
diff --git a/server/store/datastore/migration/019_drop_old_cols.go b/server/store/datastore/migration/019_drop_old_cols.go
deleted file mode 100644
index f380c924e..000000000
--- a/server/store/datastore/migration/019_drop_old_cols.go
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2023 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 (
- "src.techknowlogick.com/xormigrate"
- "xorm.io/xorm"
-)
-
-type oldPipeline019 struct {
- ID int64 `xorm:"pk autoincr 'pipeline_id'"`
- Signed bool `xorm:"pipeline_signed"`
- Verified bool `xorm:"pipeline_verified"`
-}
-
-func (oldPipeline019) TableName() string {
- return "pipelines"
-}
-
-var dropOldCols = xormigrate.Migration{
- ID: "drop-old-col",
- MigrateSession: func(sess *xorm.Session) error {
- // make sure columns on pipelines exist
- if err := sess.Sync(new(oldPipeline019)); err != nil {
- return err
- }
- if err := dropTableColumns(sess, "steps", "step_pgid"); err != nil {
- return err
- }
-
- return dropTableColumns(sess, "pipelines", "pipeline_signed", "pipeline_verified")
- },
-}
diff --git a/server/store/datastore/migration/020_alter_logs_table.go b/server/store/datastore/migration/020_alter_logs_table.go
deleted file mode 100644
index 33e050f32..000000000
--- a/server/store/datastore/migration/020_alter_logs_table.go
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright 2023 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 (
- "context"
- "encoding/json"
- "fmt"
- "runtime"
-
- "github.com/rs/zerolog/log"
- "github.com/tevino/abool/v2"
- "src.techknowlogick.com/xormigrate"
- "xorm.io/xorm"
-
- "go.woodpecker-ci.org/woodpecker/v2/shared/utils"
-)
-
-// perPage020 sets the size of the slice to read per page.
-var perPage020 = 100
-
-type oldLogs020 struct {
- ID int64 `xorm:"pk autoincr 'log_id'"`
- StepID int64 `xorm:"UNIQUE 'log_step_id'"`
- Data []byte `xorm:"LONGBLOB 'log_data'"`
-}
-
-func (oldLogs020) TableName() string {
- return "logs"
-}
-
-type oldLogEntry020 struct {
- Step string `json:"step,omitempty"`
- Time int64 `json:"time,omitempty"`
- Type int `json:"type,omitempty"`
- Pos int `json:"pos,omitempty"`
- Out string `json:"out,omitempty"`
-}
-
-type newLogEntry020 struct {
- ID int64 `xorm:"pk autoincr 'id'"`
- StepID int64 `xorm:"'step_id'"`
- Time int64
- Line int
- Data []byte `xorm:"LONGBLOB"`
- Created int64 `xorm:"created"`
- Type int
-}
-
-func (newLogEntry020) TableName() string {
- return "log_entries"
-}
-
-var initLogsEntriesTable = xormigrate.Migration{
- ID: "init-log_entries",
- MigrateSession: func(sess *xorm.Session) error {
- return sess.Sync(new(newLogEntry020))
- },
-}
-
-var migrateLogs2LogEntries = xormigrate.Migration{
- ID: "migrate-logs-to-log_entries",
- Long: true,
- Migrate: func(e *xorm.Engine) error {
- // make sure old logs table exists
- if exist, err := e.IsTableExist(new(oldLogs020)); !exist || err != nil {
- return err
- }
-
- if err := e.Sync(new(oldLogs020)); err != nil {
- return err
- }
-
- hasJSONErrors := false
-
- page := 0
- offset := 0
- logs := make([]*oldLogs020, 0, perPage020)
- logEntries := make([]*oldLogEntry020, 0, 50)
-
- sigterm := abool.New()
- ctx, cancelCtx := context.WithCancelCause(context.Background())
- defer cancelCtx(nil)
- _ = utils.WithContextSigtermCallback(ctx, func() {
- log.Info().Msg("ctrl+c received, stopping current migration")
- sigterm.Set()
- })
-
- for {
- if sigterm.IsSet() {
- return fmt.Errorf("migration 'migrate-logs-to-log_entries' gracefully aborted")
- }
-
- sess := e.NewSession().NoCache()
- defer sess.Close()
- if err := sess.Begin(); err != nil {
- return err
- }
- logs = logs[:0]
-
- err := sess.Limit(perPage020, offset).Find(&logs)
- if err != nil {
- return err
- }
-
- log.Trace().Msgf("migrate-logs-to-log_entries: process page %d", page)
-
- for _, l := range logs {
- logEntries = logEntries[:0]
- if err := json.Unmarshal(l.Data, &logEntries); err != nil {
- hasJSONErrors = true
- offset++
- continue
- }
-
- time := int64(0)
- for _, logEntry := range logEntries {
-
- if logEntry.Time > time {
- time = logEntry.Time
- }
-
- log := &newLogEntry020{
- StepID: l.StepID,
- Data: []byte(logEntry.Out),
- Line: logEntry.Pos,
- Time: time,
- Type: logEntry.Type,
- }
-
- if _, err := sess.Insert(log); err != nil {
- return err
- }
- }
-
- if _, err := sess.Delete(l); err != nil {
- return err
- }
- }
-
- if err := sess.Commit(); err != nil {
- return err
- }
-
- if len(logs) < perPage020 {
- break
- }
-
- runtime.GC()
- page++
- }
-
- if hasJSONErrors {
- return fmt.Errorf("skipped some logs as json could not be deserialized for them")
- }
-
- return e.DropTables("logs")
- },
-}
diff --git a/server/store/datastore/migration/021_parent_steps_to_workflows.go b/server/store/datastore/migration/021_parent_steps_to_workflows.go
deleted file mode 100644
index a9831a19e..000000000
--- a/server/store/datastore/migration/021_parent_steps_to_workflows.go
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2022 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 (
- "src.techknowlogick.com/xormigrate"
- "xorm.io/xorm"
-
- "go.woodpecker-ci.org/woodpecker/v2/server/model"
-)
-
-type oldStep021 struct {
- ID int64 `xorm:"pk autoincr 'step_id'"`
- PipelineID int64 `xorm:"UNIQUE(s) INDEX 'step_pipeline_id'"`
- PID int `xorm:"UNIQUE(s) 'step_pid'"`
- PPID int `xorm:"step_ppid"`
- Name string `xorm:"step_name"`
- State model.StatusValue `xorm:"step_state"`
- Error string `xorm:"TEXT 'step_error'"`
- Started int64 `xorm:"step_started"`
- Stopped int64 `xorm:"step_stopped"`
- AgentID int64 `xorm:"step_agent_id"`
- Platform string `xorm:"step_platform"`
- Environ map[string]string `xorm:"json 'step_environ'"`
-}
-
-func (oldStep021) TableName() string {
- return "steps"
-}
-
-var parentStepsToWorkflows = xormigrate.Migration{
- ID: "parent-steps-to-workflows",
- MigrateSession: func(sess *xorm.Session) error {
- if err := sess.Sync(new(model.Workflow)); err != nil {
- return err
- }
- // make sure the columns exist before removing them
- if err := sess.Sync(new(oldStep021)); err != nil {
- return err
- }
-
- var parentSteps []*oldStep021
- err := sess.Where("step_ppid = ?", 0).Find(&parentSteps)
- if err != nil {
- return err
- }
-
- for _, p := range parentSteps {
- asWorkflow := &model.Workflow{
- PipelineID: p.PipelineID,
- PID: p.PID,
- Name: p.Name,
- State: p.State,
- Error: p.Error,
- Started: p.Started,
- Stopped: p.Stopped,
- AgentID: p.AgentID,
- Platform: p.Platform,
- Environ: p.Environ,
- }
-
- _, err = sess.Insert(asWorkflow)
- if err != nil {
- return err
- }
-
- _, err = sess.Delete(&oldStep021{ID: p.ID})
- if err != nil {
- return err
- }
- }
-
- return dropTableColumns(sess, "steps", "step_agent_id", "step_platform", "step_environ")
- },
-}
diff --git a/server/store/datastore/migration/022_add_orgs.go b/server/store/datastore/migration/022_add_orgs.go
deleted file mode 100644
index 35064fef6..000000000
--- a/server/store/datastore/migration/022_add_orgs.go
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2022 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"
- "strings"
-
- "src.techknowlogick.com/xormigrate"
- "xorm.io/builder"
- "xorm.io/xorm"
-
- "go.woodpecker-ci.org/woodpecker/v2/server/model"
-)
-
-type oldSecret022 struct {
- ID int64 `xorm:"pk autoincr 'secret_id'"`
- Owner string `xorm:"'secret_owner'"`
- OrgID int64 `xorm:"NOT NULL DEFAULT 0 'secret_org_id'"`
- RepoID int64 `xorm:"NOT NULL DEFAULT 0 'secret_repo_id'"`
- Name string `xorm:"NOT NULL INDEX 'secret_name'"`
-}
-
-func (oldSecret022) TableName() string {
- return "secrets"
-}
-
-type syncRepo022 struct {
- OrgID int64 `json:"org_id" xorm:"repo_org_id"`
-}
-
-// TableName return database table name for xorm.
-func (syncRepo022) TableName() string {
- return "repos"
-}
-
-type repo022 struct {
- ID int64 `json:"id,omitempty" xorm:"pk autoincr 'repo_id'"`
- OrgID int64 `json:"org_id" xorm:"repo_org_id"`
- Owner string `json:"owner" xorm:"UNIQUE(name) 'repo_owner'"`
-}
-
-// TableName return database table name for xorm.
-func (repo022) TableName() string {
- return "repos"
-}
-
-var addOrgs = xormigrate.Migration{
- ID: "add-orgs",
- MigrateSession: func(sess *xorm.Session) error {
- if exist, err := sess.IsTableExist("orgs"); exist && err == nil {
- if err := sess.DropTable("orgs"); err != nil {
- return fmt.Errorf("drop old orgs table failed: %w", err)
- }
- }
-
- if err := sess.Sync(new(model.Org), new(syncRepo022), new(model.User)); err != nil {
- return fmt.Errorf("sync new models failed: %w", err)
- }
-
- // make sure the columns exist before removing them
- if _, err := sess.SyncWithOptions(xorm.SyncOptions{IgnoreConstrains: true, IgnoreIndices: true}, new(oldSecret022)); err != nil {
- return fmt.Errorf("sync old secrets models failed: %w", err)
- }
-
- // get all org names from repos
- var repos []*repo022
- if err := sess.Find(&repos); err != nil {
- return fmt.Errorf("find all repos failed: %w", err)
- }
-
- orgs := make(map[string]*model.Org)
- users := make(map[string]bool)
- for _, repo := range repos {
- orgName := strings.ToLower(repo.Owner)
-
- // check if it's a registered user
- if _, ok := users[orgName]; !ok {
- exist, err := sess.Where("user_login = ?", orgName).Exist(new(model.User))
- if err != nil {
- return fmt.Errorf("check if user '%s' exist failed: %w", orgName, err)
- }
- users[orgName] = exist
- }
-
- // create org if not already created
- if _, ok := orgs[orgName]; !ok {
- org := &model.Org{
- Name: orgName,
- IsUser: users[orgName],
- }
- if _, err := sess.Insert(org); err != nil {
- return fmt.Errorf("insert org %#v failed: %w", org, err)
- }
- orgs[orgName] = org
-
- // update org secrets
- var secrets []*oldSecret022
- if err := sess.Where(builder.Eq{"secret_owner": orgName, "secret_repo_id": 0}).Find(&secrets); err != nil {
- return fmt.Errorf("get org secrets failed: %w", err)
- }
-
- for _, secret := range secrets {
- secret.OrgID = org.ID
- if _, err := sess.ID(secret.ID).Cols("secret_org_id").Update(secret); err != nil {
- return fmt.Errorf("update org secret %d failed: %w", secret.ID, err)
- }
- }
- }
-
- // update the repo
- repo.OrgID = orgs[orgName].ID
- if _, err := sess.ID(repo.ID).Cols("repo_org_id").Update(repo); err != nil {
- return fmt.Errorf("update repos failed: %w", err)
- }
- }
-
- return dropTableColumns(sess, "secrets", "secret_owner")
- },
-}
diff --git a/server/store/datastore/migration/common.go b/server/store/datastore/migration/common.go
index 23a51ecd0..0ba2ff0d5 100644
--- a/server/store/datastore/migration/common.go
+++ b/server/store/datastore/migration/common.go
@@ -185,7 +185,26 @@ func dropTableColumns(sess *xorm.Session, tableName string, columnNames ...strin
func alterColumnDefault(sess *xorm.Session, table, column, defValue string) error {
dialect := sess.Engine().Dialect().URI().DBType
switch dialect {
- case schemas.MYSQL, schemas.POSTGRES:
+ case schemas.MYSQL:
+ sql := fmt.Sprintf("SHOW COLUMNS FROM `%s` WHERE lower(field) = '%s'", table, strings.ToLower(column))
+ res, err := sess.Query(sql)
+ if err != nil {
+ return err
+ }
+
+ if len(res) == 0 || len(res[0]["Type"]) == 0 {
+ return fmt.Errorf("column %s data type in table %s can not be detected", column, table)
+ }
+
+ dataType := string(res[0]["Type"])
+ var nullable string
+ if string(res[0]["Null"]) == "NO" {
+ nullable = "NOT NULL"
+ }
+
+ _, err = sess.Exec(fmt.Sprintf("ALTER TABLE `%s` MODIFY `%s` %s %s DEFAULT %s;", table, column, dataType, nullable, defValue))
+ return err
+ case schemas.POSTGRES:
_, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` ALTER COLUMN `%s` SET DEFAULT %s;", table, column, defValue))
return err
case schemas.SQLITE:
@@ -203,7 +222,26 @@ func alterColumnNull(sess *xorm.Session, table, column string, null bool) error
dialect := sess.Engine().Dialect().URI().DBType
switch dialect {
case schemas.MYSQL:
- _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` COLUMN `%s` SET %s;", table, column, val))
+ sql := fmt.Sprintf("SHOW COLUMNS FROM `%s` WHERE lower(field) = '%s'", table, strings.ToLower(column))
+ res, err := sess.Query(sql)
+ if err != nil {
+ return err
+ }
+
+ if len(res) == 0 || len(res[0]["Type"]) == 0 {
+ return fmt.Errorf("column %s data type in table %s can not be detected", column, table)
+ }
+
+ dataType := string(res[0]["Type"])
+ defValue := string(res[0]["Default"])
+
+ if defValue != "NULL" && defValue != "" {
+ defValue = fmt.Sprintf("DEFAULT '%s'", defValue)
+ } else {
+ defValue = ""
+ }
+
+ _, err = sess.Exec(fmt.Sprintf("ALTER TABLE `%s` MODIFY `%s` %s %s %s;", table, column, dataType, val, defValue))
return err
case schemas.POSTGRES:
_, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` ALTER COLUMN `%s` SET %s;", table, column, val))
diff --git a/server/store/datastore/migration/migration.go b/server/store/datastore/migration/migration.go
index ac21feb1c..d82a3a336 100644
--- a/server/store/datastore/migration/migration.go
+++ b/server/store/datastore/migration/migration.go
@@ -15,6 +15,7 @@
package migration
import (
+ "context"
"fmt"
"reflect"
@@ -28,30 +29,6 @@ import (
// They are executed in order and if one fails Xormigrate will try to rollback that specific one and quits.
var migrationTasks = []*xormigrate.Migration{
&legacyToXormigrate,
- &legacy2Xorm,
- &alterTableReposDropFallback,
- &alterTableReposDropAllowDeploysAllowTags,
- &fixPRSecretEventName,
- &alterTableReposDropCounter,
- &dropSenders,
- &alterTableLogUpdateColumnLogDataType,
- &alterTableSecretsAddUserCol,
- &recreateAgentsTable,
- &lowercaseSecretNames,
- &renameBuildsToPipeline,
- &renameColumnsBuildsToPipeline,
- &renameTableProcsToSteps,
- &renameRemoteToForge,
- &renameForgeIDToForgeRemoteID,
- &removeActiveFromUsers,
- &removeInactiveRepos,
- &dropFiles,
- &removeMachineCol,
- &dropOldCols,
- &initLogsEntriesTable,
- &migrateLogs2LogEntries,
- &parentStepsToWorkflows,
- &addOrgs,
&addOrgID,
&alterTableTasksUpdateColumnTaskDataType,
&alterTableConfigUpdateColumnConfigDataType,
@@ -60,6 +37,12 @@ var migrationTasks = []*xormigrate.Migration{
&renameLinkToURL,
&cleanRegistryPipeline,
&setForgeID,
+ &unifyColumnsTables,
+ &alterTableRegistriesFixRequiredFields,
+ &cronWithoutSec,
+ &renameStartEndTime,
+ &fixV31Registries,
+ &removeOldMigrationsOfV1,
}
var allBeans = []any{
@@ -83,7 +66,8 @@ var allBeans = []any{
new(model.Org),
}
-func Migrate(e *xorm.Engine, allowLong bool) error {
+// TODO: make xormigrate context aware
+func Migrate(_ context.Context, e *xorm.Engine, allowLong bool) error {
e.SetDisableGlobalCache(true)
m := xormigrate.New(e, migrationTasks)
diff --git a/server/store/datastore/migration/migration_test.go b/server/store/datastore/migration/migration_test.go
index cf4b1a761..661bd01ac 100644
--- a/server/store/datastore/migration/migration_test.go
+++ b/server/store/datastore/migration/migration_test.go
@@ -15,6 +15,7 @@
package migration
import (
+ "context"
"os"
"testing"
"time"
@@ -95,7 +96,7 @@ func testDB(t *testing.T, new bool) (engine *xorm.Engine, closeDB func()) {
func TestMigrate(t *testing.T) {
// init new db
engine, closeDB := testDB(t, true)
- assert.NoError(t, Migrate(engine, true))
+ assert.NoError(t, Migrate(context.Background(), engine, true))
closeDB()
dbType := engine.Dialect().URI().DBType
@@ -106,6 +107,6 @@ func TestMigrate(t *testing.T) {
// migrate old db
engine, closeDB = testDB(t, false)
- assert.NoError(t, Migrate(engine, true))
+ assert.NoError(t, Migrate(context.Background(), engine, true))
closeDB()
}
diff --git a/server/store/datastore/migration/test-files/sqlite.db b/server/store/datastore/migration/test-files/sqlite.db
index 219e5184a..731dfe5cd 100644
Binary files a/server/store/datastore/migration/test-files/sqlite.db and b/server/store/datastore/migration/test-files/sqlite.db differ
diff --git a/server/store/datastore/org.go b/server/store/datastore/org.go
index 05cdbb434..b432fb65c 100644
--- a/server/store/datastore/org.go
+++ b/server/store/datastore/org.go
@@ -56,12 +56,12 @@ func (s storage) OrgDelete(id int64) error {
}
func (s storage) orgDelete(sess *xorm.Session, id int64) error {
- if _, err := sess.Where("secret_org_id = ?", id).Delete(new(model.Secret)); err != nil {
+ if _, err := sess.Where("org_id = ?", id).Delete(new(model.Secret)); err != nil {
return err
}
var repos []*model.Repo
- if err := sess.Where("repo_org_id = ?", id).Find(&repos); err != nil {
+ if err := sess.Where("org_id = ?", id).Find(&repos); err != nil {
return err
}
@@ -84,7 +84,7 @@ func (s storage) OrgFindByName(name string) (*model.Org, error) {
func (s storage) OrgRepoList(org *model.Org, p *model.ListOptions) ([]*model.Repo, error) {
var repos []*model.Repo
- return repos, s.paginate(p).OrderBy("repo_id").Where("repo_org_id = ?", org.ID).Find(&repos)
+ return repos, s.paginate(p).OrderBy("id").Where("org_id = ?", org.ID).Find(&repos)
}
func (s storage) OrgList(p *model.ListOptions) ([]*model.Org, error) {
diff --git a/server/store/datastore/permission.go b/server/store/datastore/permission.go
index 16e95edb6..22736fdc3 100644
--- a/server/store/datastore/permission.go
+++ b/server/store/datastore/permission.go
@@ -26,7 +26,7 @@ import (
func (s storage) PermFind(user *model.User, repo *model.Repo) (*model.Perm, error) {
perm := new(model.Perm)
return perm, wrapGet(s.engine.
- Where(builder.Eq{"perm_user_id": user.ID, "perm_repo_id": repo.ID}).
+ Where(builder.Eq{"user_id": user.ID, "repo_id": repo.ID}).
Get(perm))
}
@@ -75,11 +75,11 @@ func (s storage) permUpsert(sess *xorm.Session, perm *model.Perm) error {
// userPushOrAdminCondition return condition where user must have push or admin rights
// if used make sure to have permission table ("perms") joined.
func userPushOrAdminCondition(userID int64) builder.Cond {
- return builder.Eq{"perms.perm_user_id": userID}.
- And(builder.Eq{"perms.perm_push": true}.
- Or(builder.Eq{"perms.perm_admin": true}))
+ return builder.Eq{"perms.user_id": userID}.
+ And(builder.Eq{"perms.push": true}.
+ Or(builder.Eq{"perms.admin": true}))
}
func userIDAndRepoIDCond(perm *model.Perm) builder.Cond {
- return builder.Eq{"perm_user_id": perm.UserID, "perm_repo_id": perm.RepoID}
+ return builder.Eq{"user_id": perm.UserID, "repo_id": perm.RepoID}
}
diff --git a/server/store/datastore/pipeline.go b/server/store/datastore/pipeline.go
index fc210a43e..41cc1e780 100644
--- a/server/store/datastore/pipeline.go
+++ b/server/store/datastore/pipeline.go
@@ -31,44 +31,44 @@ func (s storage) GetPipeline(id int64) (*model.Pipeline, error) {
func (s storage) GetPipelineNumber(repo *model.Repo, num int64) (*model.Pipeline, error) {
pipeline := new(model.Pipeline)
return pipeline, wrapGet(s.engine.Where(
- builder.Eq{"pipeline_repo_id": repo.ID, "pipeline_number": num},
+ builder.Eq{"repo_id": repo.ID, "number": num},
).Get(pipeline))
}
func (s storage) GetPipelineLast(repo *model.Repo, branch string) (*model.Pipeline, error) {
pipeline := new(model.Pipeline)
return pipeline, wrapGet(s.engine.
- Desc("pipeline_number").
- Where(builder.Eq{"pipeline_repo_id": repo.ID, "pipeline_branch": branch, "pipeline_event": model.EventPush}).
+ Desc("number").
+ Where(builder.Eq{"repo_id": repo.ID, "branch": branch, "event": model.EventPush}).
Get(pipeline))
}
func (s storage) GetPipelineLastBefore(repo *model.Repo, branch string, num int64) (*model.Pipeline, error) {
pipeline := new(model.Pipeline)
return pipeline, wrapGet(s.engine.
- Desc("pipeline_number").
- Where(builder.Lt{"pipeline_id": num}.
- And(builder.Eq{"pipeline_repo_id": repo.ID, "pipeline_branch": branch})).
+ Desc("number").
+ Where(builder.Lt{"id": num}.
+ And(builder.Eq{"repo_id": repo.ID, "branch": branch})).
Get(pipeline))
}
func (s storage) GetPipelineList(repo *model.Repo, p *model.ListOptions, f *model.PipelineFilter) ([]*model.Pipeline, error) {
pipelines := make([]*model.Pipeline, 0, 16)
- cond := builder.NewCond().And(builder.Eq{"pipeline_repo_id": repo.ID})
+ cond := builder.NewCond().And(builder.Eq{"repo_id": repo.ID})
if f != nil {
if f.After != 0 {
- cond = cond.And(builder.Gt{"pipeline_created": f.After})
+ cond = cond.And(builder.Gt{"created": f.After})
}
if f.Before != 0 {
- cond = cond.And(builder.Lt{"pipeline_created": f.Before})
+ cond = cond.And(builder.Lt{"created": f.Before})
}
}
return pipelines, s.paginate(p).Where(cond).
- Desc("pipeline_number").
+ Desc("number").
Find(&pipelines)
}
@@ -76,9 +76,9 @@ func (s storage) GetPipelineList(repo *model.Repo, p *model.ListOptions, f *mode
func (s storage) GetActivePipelineList(repo *model.Repo) ([]*model.Pipeline, error) {
pipelines := make([]*model.Pipeline, 0)
query := s.engine.
- Where("pipeline_repo_id = ?", repo.ID).
- In("pipeline_status", model.StatusPending, model.StatusRunning, model.StatusBlocked).
- Desc("pipeline_number")
+ Where("repo_id = ?", repo.ID).
+ In("status", model.StatusPending, model.StatusRunning, model.StatusBlocked).
+ Desc("number")
return pipelines, query.Find(&pipelines)
}
@@ -93,7 +93,7 @@ func (s storage) CreatePipeline(pipeline *model.Pipeline, stepList ...*model.Ste
return err
}
- repoExist, err := sess.Where("repo_id = ?", pipeline.RepoID).Exist(&model.Repo{})
+ repoExist, err := sess.Where("id = ?", pipeline.RepoID).Exist(&model.Repo{})
if err != nil {
return err
}
@@ -104,9 +104,9 @@ func (s storage) CreatePipeline(pipeline *model.Pipeline, stepList ...*model.Ste
// calc pipeline number
var number int64
- if _, err := sess.Select("MAX(pipeline_number)").
+ if _, err := sess.Select("MAX(number)").
Table(new(model.Pipeline)).
- Where("pipeline_repo_id = ?", pipeline.RepoID).
+ Where("repo_id = ?", pipeline.RepoID).
Get(&number); err != nil {
return err
}
@@ -154,7 +154,7 @@ func (s storage) deletePipeline(sess *xorm.Session, pipelineID int64) error {
}
if !exist {
// this config is only used for this pipeline. so delete it
- if _, err := sess.Where(builder.Eq{"config_id": confID}).Delete(new(model.Config)); err != nil {
+ if _, err := sess.Where(builder.Eq{"id": confID}).Delete(new(model.Config)); err != nil {
return err
}
}
diff --git a/server/store/datastore/registry.go b/server/store/datastore/registry.go
index 782d98c4d..49687783e 100644
--- a/server/store/datastore/registry.go
+++ b/server/store/datastore/registry.go
@@ -20,16 +20,28 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/server/model"
)
+const orderRegistriesBy = "id"
+
func (s storage) RegistryFind(repo *model.Repo, addr string) (*model.Registry, error) {
reg := new(model.Registry)
return reg, wrapGet(s.engine.Where(
- builder.Eq{"registry_repo_id": repo.ID, "registry_addr": addr},
+ builder.Eq{"repo_id": repo.ID, "address": addr},
).Get(reg))
}
-func (s storage) RegistryList(repo *model.Repo, p *model.ListOptions) ([]*model.Registry, error) {
+func (s storage) RegistryList(repo *model.Repo, includeGlobalAndOrg bool, p *model.ListOptions) ([]*model.Registry, error) {
var regs []*model.Registry
- return regs, s.paginate(p).OrderBy("registry_id").Where("registry_repo_id = ?", repo.ID).Find(®s)
+ var cond builder.Cond = builder.Eq{"repo_id": repo.ID}
+ if includeGlobalAndOrg {
+ cond = cond.Or(builder.Eq{"org_id": repo.OrgID}).
+ Or(builder.And(builder.Eq{"org_id": 0}, builder.Eq{"repo_id": 0}))
+ }
+ return regs, s.paginate(p).Where(cond).OrderBy(orderRegistriesBy).Find(®s)
+}
+
+func (s storage) RegistryListAll() ([]*model.Registry, error) {
+ var registries []*model.Registry
+ return registries, s.engine.Find(®istries)
}
func (s storage) RegistryCreate(registry *model.Registry) error {
@@ -43,10 +55,32 @@ func (s storage) RegistryUpdate(registry *model.Registry) error {
return err
}
-func (s storage) RegistryDelete(repo *model.Repo, addr string) error {
- registry, err := s.RegistryFind(repo, addr)
- if err != nil {
- return err
- }
+func (s storage) RegistryDelete(registry *model.Registry) error {
return wrapDelete(s.engine.ID(registry.ID).Delete(new(model.Registry)))
}
+
+func (s storage) OrgRegistryFind(orgID int64, name string) (*model.Registry, error) {
+ registry := new(model.Registry)
+ return registry, wrapGet(s.engine.Where(
+ builder.Eq{"org_id": orgID, "address": name},
+ ).Get(registry))
+}
+
+func (s storage) OrgRegistryList(orgID int64, p *model.ListOptions) ([]*model.Registry, error) {
+ registries := make([]*model.Registry, 0)
+ return registries, s.paginate(p).Where("org_id = ?", orgID).OrderBy(orderRegistriesBy).Find(®istries)
+}
+
+func (s storage) GlobalRegistryFind(name string) (*model.Registry, error) {
+ registry := new(model.Registry)
+ return registry, wrapGet(s.engine.Where(
+ builder.Eq{"org_id": 0, "repo_id": 0, "address": name},
+ ).Get(registry))
+}
+
+func (s storage) GlobalRegistryList(p *model.ListOptions) ([]*model.Registry, error) {
+ registries := make([]*model.Registry, 0)
+ return registries, s.paginate(p).Where(
+ builder.Eq{"org_id": 0, "repo_id": 0},
+ ).OrderBy(orderRegistriesBy).Find(®istries)
+}
diff --git a/server/store/datastore/registry_test.go b/server/store/datastore/registry_test.go
index 35c7bfc14..e6f3f5f05 100644
--- a/server/store/datastore/registry_test.go
+++ b/server/store/datastore/registry_test.go
@@ -18,6 +18,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
"go.woodpecker-ci.org/woodpecker/v2/server/model"
"go.woodpecker-ci.org/woodpecker/v2/server/store/types"
@@ -60,7 +61,7 @@ func TestRegistryList(t *testing.T) {
Password: "bar",
}))
- list, err := store.RegistryList(&model.Repo{ID: 1}, &model.ListOptions{Page: 1, PerPage: 50})
+ list, err := store.RegistryList(&model.Repo{ID: 1}, false, &model.ListOptions{Page: 1, PerPage: 50})
assert.NoError(t, err)
assert.Len(t, list, 2)
}
@@ -117,6 +118,88 @@ func TestRegistryDelete(t *testing.T) {
return
}
- assert.NoError(t, store.RegistryDelete(&model.Repo{ID: 1}, "index.docker.io"))
- assert.ErrorIs(t, store.RegistryDelete(&model.Repo{ID: 1}, "index.docker.io"), types.RecordNotExist)
+ assert.NoError(t, store.RegistryDelete(reg1))
+ assert.ErrorIs(t, store.RegistryDelete(reg1), types.RecordNotExist)
+}
+
+func createTestRegistries(t *testing.T, store *storage) {
+ assert.NoError(t, store.RegistryCreate(&model.Registry{
+ OrgID: 12,
+ Address: "my.regsitry.local",
+ }))
+ assert.NoError(t, store.RegistryCreate(&model.Registry{
+ RepoID: 1,
+ Address: "private.registry.local",
+ }))
+ assert.NoError(t, store.RegistryCreate(&model.Registry{
+ RepoID: 1,
+ Address: "very-private.registry.local",
+ }))
+ assert.NoError(t, store.RegistryCreate(&model.Registry{
+ Address: "index.docker.io",
+ }))
+}
+
+func TestOrgRegistryFind(t *testing.T) {
+ store, closer := newTestStore(t, new(model.Registry))
+ defer closer()
+
+ err := store.RegistryCreate(&model.Registry{
+ OrgID: 12,
+ Address: "my.regsitry.local",
+ Username: "username",
+ Password: "password",
+ })
+ assert.NoError(t, err)
+
+ registry, err := store.OrgRegistryFind(12, "my.regsitry.local")
+ assert.NoError(t, err)
+ assert.EqualValues(t, 12, registry.OrgID)
+ assert.Equal(t, "my.regsitry.local", registry.Address)
+ assert.Equal(t, "username", registry.Username)
+ assert.Equal(t, "password", registry.Password)
+}
+
+func TestOrgRegistryList(t *testing.T) {
+ store, closer := newTestStore(t, new(model.Registry))
+ defer closer()
+
+ createTestRegistries(t, store)
+
+ list, err := store.OrgRegistryList(12, &model.ListOptions{All: true})
+ assert.NoError(t, err)
+ require.Len(t, list, 1)
+
+ assert.True(t, list[0].IsOrganization())
+}
+
+func TestGlobalRegistryFind(t *testing.T) {
+ store, closer := newTestStore(t, new(model.Registry))
+ defer closer()
+
+ err := store.RegistryCreate(&model.Registry{
+ Address: "my.regsitry.local",
+ Username: "username",
+ Password: "password",
+ })
+ assert.NoError(t, err)
+
+ registry, err := store.GlobalRegistryFind("my.regsitry.local")
+ assert.NoError(t, err)
+ assert.Equal(t, "my.regsitry.local", registry.Address)
+ assert.Equal(t, "username", registry.Username)
+ assert.Equal(t, "password", registry.Password)
+}
+
+func TestGlobalRegistryList(t *testing.T) {
+ store, closer := newTestStore(t, new(model.Registry))
+ defer closer()
+
+ createTestRegistries(t, store)
+
+ list, err := store.GlobalRegistryList(&model.ListOptions{All: true})
+ assert.NoError(t, err)
+ assert.Len(t, list, 1)
+
+ assert.True(t, list[0].IsGlobal())
}
diff --git a/server/store/datastore/repo.go b/server/store/datastore/repo.go
index fdc2043fb..f373b17cd 100644
--- a/server/store/datastore/repo.go
+++ b/server/store/datastore/repo.go
@@ -73,11 +73,11 @@ func (s storage) GetRepoName(fullName string) (*model.Repo, error) {
func (s storage) getRepoName(e *xorm.Session, fullName string) (*model.Repo, error) {
repo := new(model.Repo)
- return repo, wrapGet(e.Where("LOWER(repo_full_name) = ?", strings.ToLower(fullName)).Get(repo))
+ return repo, wrapGet(e.Where("LOWER(full_name) = ?", strings.ToLower(fullName)).Get(repo))
}
func (s storage) GetRepoCount() (int64, error) {
- return s.engine.Where(builder.Eq{"repo_active": true}).Count(new(model.Repo))
+ return s.engine.Where(builder.Eq{"active": true}).Count(new(model.Repo))
}
func (s storage) CreateRepo(repo *model.Repo) error {
@@ -105,16 +105,16 @@ func (s storage) DeleteRepo(repo *model.Repo) error {
func (s storage) deleteRepo(sess *xorm.Session, repo *model.Repo) error {
const batchSize = perPage
- if _, err := sess.Where("config_repo_id = ?", repo.ID).Delete(new(model.Config)); err != nil {
+ if _, err := sess.Where("repo_id = ?", repo.ID).Delete(new(model.Config)); err != nil {
return err
}
- if _, err := sess.Where("perm_repo_id = ?", repo.ID).Delete(new(model.Perm)); err != nil {
+ if _, err := sess.Where("repo_id = ?", repo.ID).Delete(new(model.Perm)); err != nil {
return err
}
- if _, err := sess.Where("registry_repo_id = ?", repo.ID).Delete(new(model.Registry)); err != nil {
+ if _, err := sess.Where("repo_id = ?", repo.ID).Delete(new(model.Registry)); err != nil {
return err
}
- if _, err := sess.Where("secret_repo_id = ?", repo.ID).Delete(new(model.Secret)); err != nil {
+ if _, err := sess.Where("repo_id = ?", repo.ID).Delete(new(model.Secret)); err != nil {
return err
}
if _, err := sess.Where("repo_id = ?", repo.ID).Delete(new(model.Redirection)); err != nil {
@@ -124,7 +124,7 @@ func (s storage) deleteRepo(sess *xorm.Session, repo *model.Repo) error {
// delete related pipelines
for startPipelines := 0; ; startPipelines += batchSize {
pipelineIDs := make([]int64, 0, batchSize)
- if err := sess.Limit(batchSize, startPipelines).Table("pipelines").Cols("pipeline_id").Where("pipeline_repo_id = ?", repo.ID).Find(&pipelineIDs); err != nil {
+ if err := sess.Limit(batchSize, startPipelines).Table("pipelines").Cols("id").Where("repo_id = ?", repo.ID).Find(&pipelineIDs); err != nil {
return err
}
if len(pipelineIDs) == 0 {
@@ -146,16 +146,16 @@ func (s storage) deleteRepo(sess *xorm.Session, repo *model.Repo) error {
func (s storage) RepoList(user *model.User, owned, active bool) ([]*model.Repo, error) {
repos := make([]*model.Repo, 0)
sess := s.engine.Table("repos").
- Join("INNER", "perms", "perms.perm_repo_id = repos.repo_id").
- Where("perms.perm_user_id = ?", user.ID)
+ Join("INNER", "perms", "perms.repo_id = repos.id").
+ Where("perms.user_id = ?", user.ID)
if owned {
- sess = sess.And(builder.Eq{"perms.perm_push": true}.Or(builder.Eq{"perms.perm_admin": true}))
+ sess = sess.And(builder.Eq{"perms.push": true}.Or(builder.Eq{"perms.admin": true}))
}
if active {
- sess = sess.And(builder.Eq{"repos.repo_active": true})
+ sess = sess.And(builder.Eq{"repos.active": true})
}
return repos, sess.
- Asc("repo_full_name").
+ Asc("full_name").
Find(&repos)
}
@@ -164,9 +164,9 @@ func (s storage) RepoListAll(active bool, p *model.ListOptions) ([]*model.Repo,
repos := make([]*model.Repo, 0)
sess := s.paginate(p).Table("repos")
if active {
- sess = sess.And(builder.Eq{"repos.repo_active": true})
+ sess = sess.And(builder.Eq{"repos.active": true})
}
return repos, sess.
- Asc("repo_full_name").
+ Asc("full_name").
Find(&repos)
}
diff --git a/server/store/datastore/secret.go b/server/store/datastore/secret.go
index 85100e49a..9a481ab1b 100644
--- a/server/store/datastore/secret.go
+++ b/server/store/datastore/secret.go
@@ -20,21 +20,21 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/server/model"
)
-const orderSecretsBy = "secret_name"
+const orderSecretsBy = "name"
func (s storage) SecretFind(repo *model.Repo, name string) (*model.Secret, error) {
secret := new(model.Secret)
return secret, wrapGet(s.engine.Where(
- builder.Eq{"secret_repo_id": repo.ID, "secret_name": name},
+ builder.Eq{"repo_id": repo.ID, "name": name},
).Get(secret))
}
func (s storage) SecretList(repo *model.Repo, includeGlobalAndOrgSecrets bool, p *model.ListOptions) ([]*model.Secret, error) {
var secrets []*model.Secret
- var cond builder.Cond = builder.Eq{"secret_repo_id": repo.ID}
+ var cond builder.Cond = builder.Eq{"repo_id": repo.ID}
if includeGlobalAndOrgSecrets {
- cond = cond.Or(builder.Eq{"secret_org_id": repo.OrgID}).
- Or(builder.And(builder.Eq{"secret_org_id": 0}, builder.Eq{"secret_repo_id": 0}))
+ cond = cond.Or(builder.Eq{"org_id": repo.OrgID}).
+ Or(builder.And(builder.Eq{"org_id": 0}, builder.Eq{"repo_id": 0}))
}
return secrets, s.paginate(p).Where(cond).OrderBy(orderSecretsBy).Find(&secrets)
}
@@ -62,25 +62,25 @@ func (s storage) SecretDelete(secret *model.Secret) error {
func (s storage) OrgSecretFind(orgID int64, name string) (*model.Secret, error) {
secret := new(model.Secret)
return secret, wrapGet(s.engine.Where(
- builder.Eq{"secret_org_id": orgID, "secret_name": name},
+ builder.Eq{"org_id": orgID, "name": name},
).Get(secret))
}
func (s storage) OrgSecretList(orgID int64, p *model.ListOptions) ([]*model.Secret, error) {
secrets := make([]*model.Secret, 0)
- return secrets, s.paginate(p).Where("secret_org_id = ?", orgID).OrderBy(orderSecretsBy).Find(&secrets)
+ return secrets, s.paginate(p).Where("org_id = ?", orgID).OrderBy(orderSecretsBy).Find(&secrets)
}
func (s storage) GlobalSecretFind(name string) (*model.Secret, error) {
secret := new(model.Secret)
return secret, wrapGet(s.engine.Where(
- builder.Eq{"secret_org_id": 0, "secret_repo_id": 0, "secret_name": name},
+ builder.Eq{"org_id": 0, "repo_id": 0, "name": name},
).Get(secret))
}
func (s storage) GlobalSecretList(p *model.ListOptions) ([]*model.Secret, error) {
secrets := make([]*model.Secret, 0)
return secrets, s.paginate(p).Where(
- builder.Eq{"secret_org_id": 0, "secret_repo_id": 0},
+ builder.Eq{"org_id": 0, "repo_id": 0},
).OrderBy(orderSecretsBy).Find(&secrets)
}
diff --git a/server/store/datastore/server_config.go b/server/store/datastore/server_config.go
index 2dd52f406..a18517edb 100644
--- a/server/store/datastore/server_config.go
+++ b/server/store/datastore/server_config.go
@@ -31,7 +31,13 @@ func (s storage) ServerConfigSet(key, value string) error {
Key: key,
}
- count, err := s.engine.Count(config)
+ sess := s.engine.NewSession()
+ defer sess.Close()
+ if err := sess.Begin(); err != nil {
+ return err
+ }
+
+ count, err := sess.Count(config)
if err != nil {
return err
}
@@ -39,12 +45,15 @@ func (s storage) ServerConfigSet(key, value string) error {
config.Value = value
if count == 0 {
- _, err := s.engine.Insert(config)
+ _, err = sess.Insert(config)
+ } else {
+ _, err = sess.Where("`key` = ?", config.Key).Cols("value").Update(config)
+ }
+ if err != nil {
return err
}
- _, err = s.engine.Where("`key` = ?", config.Key).Cols("value").Update(config)
- return err
+ return sess.Commit()
}
func (s storage) ServerConfigDelete(key string) error {
diff --git a/server/store/datastore/step.go b/server/store/datastore/step.go
index f7739f4ad..3a4a43b80 100644
--- a/server/store/datastore/step.go
+++ b/server/store/datastore/step.go
@@ -29,29 +29,29 @@ func (s storage) StepLoad(id int64) (*model.Step, error) {
func (s storage) StepFind(pipeline *model.Pipeline, pid int) (*model.Step, error) {
step := new(model.Step)
return step, wrapGet(s.engine.Where(
- builder.Eq{"step_pipeline_id": pipeline.ID, "step_pid": pid},
+ builder.Eq{"pipeline_id": pipeline.ID, "pid": pid},
).Get(step))
}
func (s storage) StepByUUID(uuid string) (*model.Step, error) {
step := new(model.Step)
return step, wrapGet(s.engine.Where(
- builder.Eq{"step_uuid": uuid},
+ builder.Eq{"uuid": uuid},
).Get(step))
}
func (s storage) StepChild(pipeline *model.Pipeline, ppid int, child string) (*model.Step, error) {
step := new(model.Step)
return step, wrapGet(s.engine.Where(
- builder.Eq{"step_pipeline_id": pipeline.ID, "step_ppid": ppid, "step_name": child},
+ builder.Eq{"pipeline_id": pipeline.ID, "ppid": ppid, "name": child},
).Get(step))
}
func (s storage) StepList(pipeline *model.Pipeline) ([]*model.Step, error) {
stepList := make([]*model.Step, 0)
return stepList, s.engine.
- Where("step_pipeline_id = ?", pipeline.ID).
- OrderBy("step_pid").
+ Where("pipeline_id = ?", pipeline.ID).
+ OrderBy("pid").
Find(&stepList)
}
@@ -62,9 +62,9 @@ func (s storage) StepListFromWorkflowFind(workflow *model.Workflow) ([]*model.St
func (s storage) stepListWorkflow(sess *xorm.Session, workflow *model.Workflow) ([]*model.Step, error) {
stepList := make([]*model.Step, 0)
return stepList, sess.
- Where("step_pipeline_id = ?", workflow.PipelineID).
- Where("step_ppid = ?", workflow.PID).
- OrderBy("step_pid").
+ Where("pipeline_id = ?", workflow.PipelineID).
+ Where("ppid = ?", workflow.PID).
+ OrderBy("pid").
Find(&stepList)
}
@@ -84,7 +84,7 @@ func (s storage) StepUpdate(step *model.Step) error {
}
func deleteStep(sess *xorm.Session, stepID int64) error {
- if _, err := sess.Where("step_id = ?", stepID).Delete(new(model.LogEntry)); err != nil {
+ if _, err := sess.Where("id = ?", stepID).Delete(new(model.LogEntry)); err != nil {
return err
}
return wrapDelete(sess.ID(stepID).Delete(new(model.Step)))
diff --git a/server/store/datastore/task.go b/server/store/datastore/task.go
index 67e8d9797..44296dff1 100644
--- a/server/store/datastore/task.go
+++ b/server/store/datastore/task.go
@@ -30,5 +30,5 @@ func (s storage) TaskInsert(task *model.Task) error {
}
func (s storage) TaskDelete(id string) error {
- return wrapDelete(s.engine.Where("task_id = ?", id).Delete(new(model.Task)))
+ return wrapDelete(s.engine.Where("id = ?", id).Delete(new(model.Task)))
}
diff --git a/server/store/datastore/user.go b/server/store/datastore/user.go
index 39f09af75..c1900062e 100644
--- a/server/store/datastore/user.go
+++ b/server/store/datastore/user.go
@@ -30,7 +30,7 @@ func (s storage) GetUserRemoteID(remoteID model.ForgeRemoteID, login string) (*m
user := new(model.User)
err := wrapGet(sess.Where("forge_remote_id = ?", remoteID).Get(user))
if err != nil {
- user, err = s.getUserLogin(sess, login)
+ return s.getUserLogin(sess, login)
}
return user, err
}
@@ -41,12 +41,12 @@ func (s storage) GetUserLogin(login string) (*model.User, error) {
func (s storage) getUserLogin(sess *xorm.Session, login string) (*model.User, error) {
user := new(model.User)
- return user, wrapGet(sess.Where("user_login=?", login).Get(user))
+ return user, wrapGet(sess.Where("login=?", login).Get(user))
}
func (s storage) GetUserList(p *model.ListOptions) ([]*model.User, error) {
var users []*model.User
- return users, s.paginate(p).OrderBy("user_id").Find(&users)
+ return users, s.paginate(p).OrderBy("login").Find(&users)
}
func (s storage) GetUserCount() (int64, error) {
@@ -89,7 +89,7 @@ func (s storage) DeleteUser(user *model.User) error {
return err
}
- if _, err := sess.Where("perm_user_id = ?", user.ID).Delete(new(model.Perm)); err != nil {
+ if _, err := sess.Where("user_id = ?", user.ID).Delete(new(model.Perm)); err != nil {
return err
}
diff --git a/server/store/datastore/workflow.go b/server/store/datastore/workflow.go
index b3325b9a0..8e76df90c 100644
--- a/server/store/datastore/workflow.go
+++ b/server/store/datastore/workflow.go
@@ -87,7 +87,7 @@ func (s storage) workflowsDelete(sess *xorm.Session, pipelineID int64) error {
// delete related steps
for startSteps := 0; ; startSteps += perPage {
stepIDs := make([]int64, 0, perPage)
- if err := sess.Limit(perPage, startSteps).Table("steps").Cols("step_id").Where("step_pipeline_id = ?", pipelineID).Find(&stepIDs); err != nil {
+ if err := sess.Limit(perPage, startSteps).Table("steps").Cols("id").Where("pipeline_id = ?", pipelineID).Find(&stepIDs); err != nil {
return err
}
if len(stepIDs) == 0 {
@@ -101,7 +101,7 @@ func (s storage) workflowsDelete(sess *xorm.Session, pipelineID int64) error {
}
}
- _, err := sess.Where("workflow_pipeline_id = ?", pipelineID).Delete(new(model.Workflow))
+ _, err := sess.Where("pipeline_id = ?", pipelineID).Delete(new(model.Workflow))
return err
}
@@ -112,8 +112,8 @@ func (s storage) WorkflowList(pipeline *model.Pipeline) ([]*model.Workflow, erro
// workflowList lists workflows without child steps.
func (s storage) workflowList(sess *xorm.Session, pipeline *model.Pipeline) ([]*model.Workflow, error) {
var wfList []*model.Workflow
- err := sess.Where("workflow_pipeline_id = ?", pipeline.ID).
- OrderBy("workflow_pid").
+ err := sess.Where("pipeline_id = ?", pipeline.ID).
+ OrderBy("pid").
Find(&wfList)
if err != nil {
return nil, err
diff --git a/server/store/mocks/store.go b/server/store/mocks/store.go
index ee1a825d0..df88e436d 100644
--- a/server/store/mocks/store.go
+++ b/server/store/mocks/store.go
@@ -1,8 +1,13 @@
// Code generated by mockery. DO NOT EDIT.
+//go:build test
+// +build test
+
package mocks
import (
+ context "context"
+
mock "github.com/stretchr/testify/mock"
model "go.woodpecker-ci.org/woodpecker/v2/server/model"
)
@@ -1187,6 +1192,66 @@ func (_m *Store) GetUserRemoteID(_a0 model.ForgeRemoteID, _a1 string) (*model.Us
return r0, r1
}
+// GlobalRegistryFind provides a mock function with given fields: _a0
+func (_m *Store) GlobalRegistryFind(_a0 string) (*model.Registry, error) {
+ ret := _m.Called(_a0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GlobalRegistryFind")
+ }
+
+ var r0 *model.Registry
+ var r1 error
+ if rf, ok := ret.Get(0).(func(string) (*model.Registry, error)); ok {
+ return rf(_a0)
+ }
+ if rf, ok := ret.Get(0).(func(string) *model.Registry); ok {
+ r0 = rf(_a0)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*model.Registry)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(string) error); ok {
+ r1 = rf(_a0)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// GlobalRegistryList provides a mock function with given fields: _a0
+func (_m *Store) GlobalRegistryList(_a0 *model.ListOptions) ([]*model.Registry, error) {
+ ret := _m.Called(_a0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GlobalRegistryList")
+ }
+
+ var r0 []*model.Registry
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*model.ListOptions) ([]*model.Registry, error)); ok {
+ return rf(_a0)
+ }
+ if rf, ok := ret.Get(0).(func(*model.ListOptions) []*model.Registry); ok {
+ r0 = rf(_a0)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]*model.Registry)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*model.ListOptions) error); ok {
+ r1 = rf(_a0)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
// GlobalSecretFind provides a mock function with given fields: _a0
func (_m *Store) GlobalSecretFind(_a0 string) (*model.Secret, error) {
ret := _m.Called(_a0)
@@ -1275,17 +1340,17 @@ func (_m *Store) HasRedirectionForRepo(_a0 int64, _a1 string) (bool, error) {
return r0, r1
}
-// LogAppend provides a mock function with given fields: logEntry
-func (_m *Store) LogAppend(logEntry *model.LogEntry) error {
- ret := _m.Called(logEntry)
+// LogAppend provides a mock function with given fields: _a0, _a1
+func (_m *Store) LogAppend(_a0 *model.Step, _a1 []*model.LogEntry) error {
+ ret := _m.Called(_a0, _a1)
if len(ret) == 0 {
panic("no return value specified for LogAppend")
}
var r0 error
- if rf, ok := ret.Get(0).(func(*model.LogEntry) error); ok {
- r0 = rf(logEntry)
+ if rf, ok := ret.Get(0).(func(*model.Step, []*model.LogEntry) error); ok {
+ r0 = rf(_a0, _a1)
} else {
r0 = ret.Error(0)
}
@@ -1341,17 +1406,17 @@ func (_m *Store) LogFind(_a0 *model.Step) ([]*model.LogEntry, error) {
return r0, r1
}
-// Migrate provides a mock function with given fields: _a0
-func (_m *Store) Migrate(_a0 bool) error {
- ret := _m.Called(_a0)
+// Migrate provides a mock function with given fields: _a0, _a1
+func (_m *Store) Migrate(_a0 context.Context, _a1 bool) error {
+ ret := _m.Called(_a0, _a1)
if len(ret) == 0 {
panic("no return value specified for Migrate")
}
var r0 error
- if rf, ok := ret.Get(0).(func(bool) error); ok {
- r0 = rf(_a0)
+ if rf, ok := ret.Get(0).(func(context.Context, bool) error); ok {
+ r0 = rf(_a0, _a1)
} else {
r0 = ret.Error(0)
}
@@ -1485,6 +1550,66 @@ func (_m *Store) OrgList(_a0 *model.ListOptions) ([]*model.Org, error) {
return r0, r1
}
+// OrgRegistryFind provides a mock function with given fields: _a0, _a1
+func (_m *Store) OrgRegistryFind(_a0 int64, _a1 string) (*model.Registry, error) {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for OrgRegistryFind")
+ }
+
+ var r0 *model.Registry
+ var r1 error
+ if rf, ok := ret.Get(0).(func(int64, string) (*model.Registry, error)); ok {
+ return rf(_a0, _a1)
+ }
+ if rf, ok := ret.Get(0).(func(int64, string) *model.Registry); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*model.Registry)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(int64, string) error); ok {
+ r1 = rf(_a0, _a1)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OrgRegistryList provides a mock function with given fields: _a0, _a1
+func (_m *Store) OrgRegistryList(_a0 int64, _a1 *model.ListOptions) ([]*model.Registry, error) {
+ ret := _m.Called(_a0, _a1)
+
+ if len(ret) == 0 {
+ panic("no return value specified for OrgRegistryList")
+ }
+
+ var r0 []*model.Registry
+ var r1 error
+ if rf, ok := ret.Get(0).(func(int64, *model.ListOptions) ([]*model.Registry, error)); ok {
+ return rf(_a0, _a1)
+ }
+ if rf, ok := ret.Get(0).(func(int64, *model.ListOptions) []*model.Registry); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]*model.Registry)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(int64, *model.ListOptions) error); ok {
+ r1 = rf(_a0, _a1)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
// OrgRepoList provides a mock function with given fields: _a0, _a1
func (_m *Store) OrgRepoList(_a0 *model.Org, _a1 *model.ListOptions) ([]*model.Repo, error) {
ret := _m.Called(_a0, _a1)
@@ -1695,17 +1820,17 @@ func (_m *Store) RegistryCreate(_a0 *model.Registry) error {
return r0
}
-// RegistryDelete provides a mock function with given fields: repo, addr
-func (_m *Store) RegistryDelete(repo *model.Repo, addr string) error {
- ret := _m.Called(repo, addr)
+// RegistryDelete provides a mock function with given fields: _a0
+func (_m *Store) RegistryDelete(_a0 *model.Registry) error {
+ ret := _m.Called(_a0)
if len(ret) == 0 {
panic("no return value specified for RegistryDelete")
}
var r0 error
- if rf, ok := ret.Get(0).(func(*model.Repo, string) error); ok {
- r0 = rf(repo, addr)
+ if rf, ok := ret.Get(0).(func(*model.Registry) error); ok {
+ r0 = rf(_a0)
} else {
r0 = ret.Error(0)
}
@@ -1743,9 +1868,9 @@ func (_m *Store) RegistryFind(_a0 *model.Repo, _a1 string) (*model.Registry, err
return r0, r1
}
-// RegistryList provides a mock function with given fields: _a0, _a1
-func (_m *Store) RegistryList(_a0 *model.Repo, _a1 *model.ListOptions) ([]*model.Registry, error) {
- ret := _m.Called(_a0, _a1)
+// RegistryList provides a mock function with given fields: _a0, _a1, _a2
+func (_m *Store) RegistryList(_a0 *model.Repo, _a1 bool, _a2 *model.ListOptions) ([]*model.Registry, error) {
+ ret := _m.Called(_a0, _a1, _a2)
if len(ret) == 0 {
panic("no return value specified for RegistryList")
@@ -1753,19 +1878,49 @@ func (_m *Store) RegistryList(_a0 *model.Repo, _a1 *model.ListOptions) ([]*model
var r0 []*model.Registry
var r1 error
- if rf, ok := ret.Get(0).(func(*model.Repo, *model.ListOptions) ([]*model.Registry, error)); ok {
- return rf(_a0, _a1)
+ if rf, ok := ret.Get(0).(func(*model.Repo, bool, *model.ListOptions) ([]*model.Registry, error)); ok {
+ return rf(_a0, _a1, _a2)
}
- if rf, ok := ret.Get(0).(func(*model.Repo, *model.ListOptions) []*model.Registry); ok {
- r0 = rf(_a0, _a1)
+ if rf, ok := ret.Get(0).(func(*model.Repo, bool, *model.ListOptions) []*model.Registry); ok {
+ r0 = rf(_a0, _a1, _a2)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.Registry)
}
}
- if rf, ok := ret.Get(1).(func(*model.Repo, *model.ListOptions) error); ok {
- r1 = rf(_a0, _a1)
+ if rf, ok := ret.Get(1).(func(*model.Repo, bool, *model.ListOptions) error); ok {
+ r1 = rf(_a0, _a1, _a2)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// RegistryListAll provides a mock function with given fields:
+func (_m *Store) RegistryListAll() ([]*model.Registry, error) {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for RegistryListAll")
+ }
+
+ var r0 []*model.Registry
+ var r1 error
+ if rf, ok := ret.Get(0).(func() ([]*model.Registry, error)); ok {
+ return rf()
+ }
+ if rf, ok := ret.Get(0).(func() []*model.Registry); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]*model.Registry)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func() error); ok {
+ r1 = rf()
} else {
r1 = ret.Error(1)
}
diff --git a/server/store/store.go b/server/store/store.go
index 2a007e487..f1e958994 100644
--- a/server/store/store.go
+++ b/server/store/store.go
@@ -14,9 +14,11 @@
package store
-//go:generate mockery --name Store --output mocks --case underscore
+//go:generate mockery --name Store --output mocks --case underscore --note "+build test"
import (
+ "context"
+
"go.woodpecker-ci.org/woodpecker/v2/server/model"
)
@@ -120,10 +122,15 @@ type Store interface {
// Registries
RegistryFind(*model.Repo, string) (*model.Registry, error)
- RegistryList(*model.Repo, *model.ListOptions) ([]*model.Registry, error)
+ RegistryList(*model.Repo, bool, *model.ListOptions) ([]*model.Registry, error)
+ RegistryListAll() ([]*model.Registry, error)
RegistryCreate(*model.Registry) error
RegistryUpdate(*model.Registry) error
- RegistryDelete(repo *model.Repo, addr string) error
+ RegistryDelete(*model.Registry) error
+ OrgRegistryFind(int64, string) (*model.Registry, error)
+ OrgRegistryList(int64, *model.ListOptions) ([]*model.Registry, error)
+ GlobalRegistryFind(string) (*model.Registry, error)
+ GlobalRegistryList(*model.ListOptions) ([]*model.Registry, error)
// Steps
StepLoad(int64) (*model.Step, error)
@@ -136,7 +143,7 @@ type Store interface {
// Logs
LogFind(*model.Step) ([]*model.LogEntry, error)
- LogAppend(logEntry *model.LogEntry) error
+ LogAppend(*model.Step, []*model.LogEntry) error
LogDelete(*model.Step) error
// Tasks
@@ -195,5 +202,5 @@ type Store interface {
// Store operations
Ping() error
Close() error
- Migrate(bool) error
+ Migrate(context.Context, bool) error
}
diff --git a/shared/constant/constant.go b/shared/constant/constant.go
index ca315e987..e6cfa63ed 100644
--- a/shared/constant/constant.go
+++ b/shared/constant/constant.go
@@ -14,14 +14,7 @@
package constant
-// PrivilegedPlugins can be changed by 'WOODPECKER_ESCALATE' at runtime.
-var PrivilegedPlugins = []string{
- "plugins/docker",
- "plugins/gcr",
- "plugins/ecr",
- "woodpeckerci/plugin-docker-buildx",
- "codeberg.org/woodpecker-plugins/docker-buildx",
-}
+import "time"
// DefaultConfigOrder represent the priority in witch woodpecker search for a pipeline config by default
// folders are indicated by supplying a trailing slash.
@@ -32,11 +25,17 @@ var DefaultConfigOrder = [...]string{
}
const (
- // DefaultCloneImage can be changed by 'WOODPECKER_DEFAULT_CLONE_IMAGE' at runtime.
- DefaultCloneImage = "docker.io/woodpeckerci/plugin-git:2.4.0"
+ // DefaultClonePlugin can be changed by 'WOODPECKER_DEFAULT_CLONE_PLUGIN' at runtime.
+ // renovate: datasource=docker depName=woodpeckerci/plugin-git
+ DefaultClonePlugin = "docker.io/woodpeckerci/plugin-git:2.6.0"
)
-var TrustedCloneImages = []string{
- DefaultCloneImage,
+// TrustedClonePlugins can be changed by 'WOODPECKER_PLUGINS_TRUSTED_CLONE' at runtime.
+var TrustedClonePlugins = []string{
+ DefaultClonePlugin,
+ "docker.io/woodpeckerci/plugin-git",
"quay.io/woodpeckerci/plugin-git",
}
+
+// TaskTimeout is the time till a running task is counted as dead.
+var TaskTimeout = time.Minute
diff --git a/shared/logger/logger.go b/shared/logger/logger.go
index 916ec1b01..266777265 100644
--- a/shared/logger/logger.go
+++ b/shared/logger/logger.go
@@ -15,6 +15,7 @@
package logger
import (
+ "context"
"fmt"
"io"
"os"
@@ -22,37 +23,37 @@ import (
"github.com/6543/logfile-open"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
)
var GlobalLoggerFlags = []cli.Flag{
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_LOG_LEVEL"},
+ Sources: cli.EnvVars("WOODPECKER_LOG_LEVEL"),
Name: "log-level",
Usage: "set logging level",
Value: "info",
},
&cli.StringFlag{
- EnvVars: []string{"WOODPECKER_LOG_FILE"},
+ Sources: cli.EnvVars("WOODPECKER_LOG_FILE"),
Name: "log-file",
Usage: "Output destination for logs. 'stdout' and 'stderr' can be used as special keywords.",
Value: "stderr",
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_DEBUG_PRETTY"},
+ Sources: cli.EnvVars("WOODPECKER_DEBUG_PRETTY"),
Name: "pretty",
Usage: "enable pretty-printed debug output",
Value: isInteractiveTerminal(), // make pretty on interactive terminal by default
},
&cli.BoolFlag{
- EnvVars: []string{"WOODPECKER_DEBUG_NOCOLOR"},
+ Sources: cli.EnvVars("WOODPECKER_DEBUG_NOCOLOR"),
Name: "nocolor",
Usage: "disable colored debug output, only has effect if pretty output is set too",
Value: !isInteractiveTerminal(), // do color on interactive terminal by default
},
}
-func SetupGlobalLogger(c *cli.Context, outputLvl bool) error {
+func SetupGlobalLogger(ctx context.Context, c *cli.Command, outputLvl bool) error {
logLevel := c.String("log-level")
pretty := c.Bool("pretty")
noColor := c.Bool("nocolor")
@@ -65,7 +66,7 @@ func SetupGlobalLogger(c *cli.Context, outputLvl bool) error {
case "stdout":
file = os.Stdout
default: // a file was set
- openFile, err := logfile.OpenFileWithContext(c.Context, logFile, 0o660)
+ openFile, err := logfile.OpenFileWithContext(ctx, logFile, 0o660)
if err != nil {
return fmt.Errorf("could not open log file '%s': %w", logFile, err)
}
diff --git a/shared/token/token.go b/shared/token/token.go
index 545107f59..1f3deaa12 100644
--- a/shared/token/token.go
+++ b/shared/token/token.go
@@ -24,36 +24,53 @@ import (
type SecretFunc func(*Token) (string, error)
+type Type string
+
const (
- UserToken = "user"
- SessToken = "sess"
- HookToken = "hook"
- CsrfToken = "csrf"
- AgentToken = "agent"
+ UserToken Type = "user" // user token (exp cli)
+ SessToken Type = "sess" // session token (ui token requires csrf check)
+ HookToken Type = "hook" // repo hook token
+ CsrfToken Type = "csrf"
+ AgentToken Type = "agent"
+ OAuthStateToken Type = "oauth-state"
)
// SignerAlgo id default algorithm used to sign JWT tokens.
const SignerAlgo = "HS256"
type Token struct {
- Kind string
+ Type Type
claims jwt.MapClaims
}
-func parse(raw string, fn SecretFunc) (*Token, error) {
+func Parse(allowedTypes []Type, raw string, fn SecretFunc) (*Token, error) {
token := &Token{
claims: jwt.MapClaims{},
}
parsed, err := jwt.Parse(raw, keyFunc(token, fn))
if err != nil {
return nil, err
- } else if !parsed.Valid {
+ }
+ if !parsed.Valid {
return nil, jwt.ErrTokenUnverifiable
}
+
+ hasAllowedType := false
+ for _, k := range allowedTypes {
+ if k == token.Type {
+ hasAllowedType = true
+ break
+ }
+ }
+
+ if !hasAllowedType {
+ return nil, jwt.ErrInvalidType
+ }
+
return token, nil
}
-func ParseRequest(r *http.Request, fn SecretFunc) (*Token, error) {
+func ParseRequest(allowedTypes []Type, r *http.Request, fn SecretFunc) (*Token, error) {
// first we attempt to get the token from the
// authorization header.
token := r.Header.Get("Authorization")
@@ -63,19 +80,19 @@ func ParseRequest(r *http.Request, fn SecretFunc) (*Token, error) {
if _, err := fmt.Sscanf(token, "Bearer %s", &bearer); err != nil {
return nil, err
}
- return parse(bearer, fn)
+ return Parse(allowedTypes, bearer, fn)
}
token = r.Header.Get("X-Gitlab-Token")
if len(token) != 0 {
- return parse(token, fn)
+ return Parse(allowedTypes, token, fn)
}
// then we attempt to get the token from the
// access_token url query parameter
token = r.FormValue("access_token")
if len(token) != 0 {
- return parse(token, fn)
+ return Parse(allowedTypes, token, fn)
}
// and finally we attempt to get the token from
@@ -84,7 +101,7 @@ func ParseRequest(r *http.Request, fn SecretFunc) (*Token, error) {
if err != nil {
return nil, err
}
- return parse(cookie.Value, fn)
+ return Parse(allowedTypes, cookie.Value, fn)
}
func CheckCsrf(r *http.Request, fn SecretFunc) error {
@@ -97,12 +114,12 @@ func CheckCsrf(r *http.Request, fn SecretFunc) error {
// parse the raw CSRF token value and validate
raw := r.Header.Get("X-CSRF-TOKEN")
- _, err := parse(raw, fn)
+ _, err := Parse([]Type{CsrfToken}, raw, fn)
return err
}
-func New(kind string) *Token {
- return &Token{Kind: kind, claims: jwt.MapClaims{}}
+func New(tokenType Type) *Token {
+ return &Token{Type: tokenType, claims: jwt.MapClaims{}}
}
// Sign signs the token using the given secret hash
@@ -124,7 +141,7 @@ func (t *Token) SignExpires(secret string, exp int64) (string, error) {
claims[k] = v
}
- claims["type"] = t.Kind
+ claims["type"] = t.Type
if exp > 0 {
claims["exp"] = float64(exp)
}
@@ -157,12 +174,12 @@ func keyFunc(token *Token, fn SecretFunc) jwt.Keyfunc {
return nil, jwt.ErrSignatureInvalid
}
- // extract the token kind and cast to the expected type
- kind, ok := claims["type"]
+ // extract the token type and cast to the expected type
+ tokenType, ok := claims["type"].(string)
if !ok {
return nil, jwt.ErrInvalidType
}
- token.Kind, _ = kind.(string)
+ token.Type = Type(tokenType)
// copy custom claims
for k, v := range claims {
diff --git a/shared/token/token_test.go b/shared/token/token_test.go
new file mode 100644
index 000000000..fb77ef609
--- /dev/null
+++ b/shared/token/token_test.go
@@ -0,0 +1,62 @@
+package token_test
+
+import (
+ "testing"
+
+ "github.com/franela/goblin"
+ "github.com/gin-gonic/gin"
+ "github.com/golang-jwt/jwt/v5"
+ "github.com/stretchr/testify/assert"
+
+ "go.woodpecker-ci.org/woodpecker/v2/shared/token"
+)
+
+func TestToken(t *testing.T) {
+ gin.SetMode(gin.TestMode)
+
+ g := goblin.Goblin(t)
+ g.Describe("Token", func() {
+ jwtSecret := "secret-to-sign-the-token"
+
+ g.It("should parse a valid token", func() {
+ _token := token.New(token.UserToken)
+ _token.Set("user-id", "1")
+ signedToken, err := _token.Sign(jwtSecret)
+ assert.NoError(g, err)
+
+ parsed, err := token.Parse([]token.Type{token.UserToken}, signedToken, func(_ *token.Token) (string, error) {
+ return jwtSecret, nil
+ })
+
+ assert.NoError(g, err)
+ assert.NotNil(g, parsed)
+ assert.Equal(g, "1", parsed.Get("user-id"))
+ })
+
+ g.It("should fail to parse a token with a wrong type", func() {
+ _token := token.New(token.UserToken)
+ _token.Set("user-id", "1")
+ signedToken, err := _token.Sign(jwtSecret)
+ assert.NoError(g, err)
+
+ _, err = token.Parse([]token.Type{token.AgentToken}, signedToken, func(_ *token.Token) (string, error) {
+ return jwtSecret, nil
+ })
+
+ assert.ErrorIs(g, err, jwt.ErrInvalidType)
+ })
+
+ g.It("should fail to parse a token with a wrong secret", func() {
+ _token := token.New(token.UserToken)
+ _token.Set("user-id", "1")
+ signedToken, err := _token.Sign(jwtSecret)
+ assert.NoError(g, err)
+
+ _, err = token.Parse([]token.Type{token.UserToken}, signedToken, func(_ *token.Token) (string, error) {
+ return "this-is-a-wrong-secret", nil
+ })
+
+ assert.ErrorIs(g, err, jwt.ErrSignatureInvalid)
+ })
+ })
+}
diff --git a/web/components.d.ts b/web/components.d.ts
index 72c5ae49e..deb27eae3 100644
--- a/web/components.d.ts
+++ b/web/components.d.ts
@@ -14,6 +14,7 @@ declare module 'vue' {
AdminOrgsTab: typeof import('./src/components/admin/settings/AdminOrgsTab.vue')['default']
AdminQueueStats: typeof import('./src/components/admin/settings/queue/AdminQueueStats.vue')['default']
AdminQueueTab: typeof import('./src/components/admin/settings/AdminQueueTab.vue')['default']
+ AdminRegistriesTab: typeof import('./src/components/admin/settings/AdminRegistriesTab.vue')['default']
AdminReposTab: typeof import('./src/components/admin/settings/AdminReposTab.vue')['default']
AdminSecretsTab: typeof import('./src/components/admin/settings/AdminSecretsTab.vue')['default']
AdminUsersTab: typeof import('./src/components/admin/settings/AdminUsersTab.vue')['default']
@@ -85,6 +86,7 @@ declare module 'vue' {
ManualPipelinePopup: typeof import('./src/components/layout/popups/ManualPipelinePopup.vue')['default']
Navbar: typeof import('./src/components/layout/header/Navbar.vue')['default']
NumberField: typeof import('./src/components/form/NumberField.vue')['default']
+ OrgRegistriesTab: typeof import('./src/components/org/settings/OrgRegistriesTab.vue')['default']
OrgSecretsTab: typeof import('./src/components/org/settings/OrgSecretsTab.vue')['default']
Panel: typeof import('./src/components/layout/Panel.vue')['default']
PipelineFeedItem: typeof import('./src/components/pipeline-feed/PipelineFeedItem.vue')['default']
@@ -99,6 +101,8 @@ declare module 'vue' {
Popup: typeof import('./src/components/layout/Popup.vue')['default']
RadioField: typeof import('./src/components/form/RadioField.vue')['default']
RegistriesTab: typeof import('./src/components/repo/settings/RegistriesTab.vue')['default']
+ RegistryEdit: typeof import('./src/components/registry/RegistryEdit.vue')['default']
+ RegistryList: typeof import('./src/components/registry/RegistryList.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
Scaffold: typeof import('./src/components/layout/scaffold/Scaffold.vue')['default']
@@ -112,6 +116,7 @@ declare module 'vue' {
TextField: typeof import('./src/components/form/TextField.vue')['default']
UserCLIAndAPITab: typeof import('./src/components/user/UserCLIAndAPITab.vue')['default']
UserGeneralTab: typeof import('./src/components/user/UserGeneralTab.vue')['default']
+ UserRegistriesTab: typeof import('./src/components/user/UserRegistriesTab.vue')['default']
UserSecretsTab: typeof import('./src/components/user/UserSecretsTab.vue')['default']
Warning: typeof import('./src/components/atomic/Warning.vue')['default']
}
diff --git a/web/eslint.config.js b/web/eslint.config.js
index d218b3d99..1b704b719 100644
--- a/web/eslint.config.js
+++ b/web/eslint.config.js
@@ -4,6 +4,7 @@
import antfu from '@antfu/eslint-config';
import js from '@eslint/js';
import vueI18n from '@intlify/eslint-plugin-vue-i18n';
+import eslintPromise from 'eslint-plugin-promise';
import eslintPluginVueScopedCSS from 'eslint-plugin-vue-scoped-css';
export default antfu(
@@ -20,23 +21,54 @@ export default antfu(
},
js.configs.recommended,
- // eslintPromise.configs.recommended,
-
- // TypeScript
- //...tseslint.configs.recommended,
- //...tseslint.configs.recommendedTypeChecked,
- //...tseslint.configs.strictTypeChecked,
- //...tseslint.configs.stylisticTypeChecked,
+ eslintPromise.configs['flat/recommended'],
+ ...eslintPluginVueScopedCSS.configs['flat/recommended'],
+ ...vueI18n.configs['flat/recommended'],
{
rules: {
'import/order': 'off',
'sort-imports': 'off',
+ 'perfectionist/sort-imports': 'off',
+ 'perfectionist/sort-named-imports': 'off',
+ 'promise/prefer-await-to-callbacks': 'error',
+
+ // Vue I18n
+ '@intlify/vue-i18n/no-raw-text': [
+ 'error',
+ {
+ attributes: {
+ '/.+/': ['label'],
+ },
+ },
+ ],
+ '@intlify/vue-i18n/key-format-style': ['error', 'snake_case'],
+ '@intlify/vue-i18n/no-duplicate-keys-in-locale': 'error',
+ '@intlify/vue-i18n/no-dynamic-keys': 'error',
+ '@intlify/vue-i18n/no-deprecated-i18n-component': 'error',
+ '@intlify/vue-i18n/no-deprecated-tc': 'error',
+ '@intlify/vue-i18n/no-i18n-t-path-prop': 'error',
+ '@intlify/vue-i18n/no-missing-keys-in-other-locales': 'off',
+ '@intlify/vue-i18n/valid-message-syntax': 'error',
+ '@intlify/vue-i18n/no-missing-keys': 'error',
+ '@intlify/vue-i18n/no-unknown-locale': 'error',
+ '@intlify/vue-i18n/no-unused-keys': ['error', { extensions: ['.ts', '.vue'] }],
+ '@intlify/vue-i18n/prefer-sfc-lang-attr': 'error',
+ '@intlify/vue-i18n/no-html-messages': 'error',
+ '@intlify/vue-i18n/prefer-linked-key-with-paren': 'error',
+ '@intlify/vue-i18n/sfc-locale-attr': 'error',
+ },
+ settings: {
+ // Vue I18n
+ 'vue-i18n': {
+ localeDir: './src/assets/locales/en.json',
+ // Specify the version of `vue-i18n` you are using.
+ // If not specified, the message will be parsed twice.
+ messageSyntaxVersion: '^9.0.0',
+ },
},
},
- ...eslintPluginVueScopedCSS.configs['flat/recommended'],
-
// Vue
{
files: ['**/*.vue'],
@@ -64,44 +96,6 @@ export default antfu(
},
},
- // Vue I18n
- ...vueI18n.configs['flat/recommended'],
- {
- rules: {
- '@intlify/vue-i18n/no-raw-text': [
- 'error',
- {
- attributes: {
- '/.+/': ['label'],
- },
- },
- ],
- '@intlify/vue-i18n/key-format-style': ['error', 'snake_case'],
- '@intlify/vue-i18n/no-duplicate-keys-in-locale': 'error',
- '@intlify/vue-i18n/no-dynamic-keys': 'error',
- '@intlify/vue-i18n/no-deprecated-i18n-component': 'error',
- '@intlify/vue-i18n/no-deprecated-tc': 'error',
- '@intlify/vue-i18n/no-i18n-t-path-prop': 'error',
- '@intlify/vue-i18n/no-missing-keys-in-other-locales': 'off',
- '@intlify/vue-i18n/valid-message-syntax': 'error',
- '@intlify/vue-i18n/no-missing-keys': 'error',
- '@intlify/vue-i18n/no-unknown-locale': 'error',
- '@intlify/vue-i18n/no-unused-keys': ['error', { extensions: ['.ts', '.vue'] }],
- '@intlify/vue-i18n/prefer-sfc-lang-attr': 'error',
- '@intlify/vue-i18n/no-html-messages': 'error',
- '@intlify/vue-i18n/prefer-linked-key-with-paren': 'error',
- '@intlify/vue-i18n/sfc-locale-attr': 'error',
- },
- settings: {
- 'vue-i18n': {
- localeDir: './src/assets/locales/en.json',
- // Specify the version of `vue-i18n` you are using.
- // If not specified, the message will be parsed twice.
- messageSyntaxVersion: '^9.0.0',
- },
- },
- },
-
// Ignore list
{
ignores: [
diff --git a/web/package.json b/web/package.json
index f0f14c6b1..73658eaa8 100644
--- a/web/package.json
+++ b/web/package.json
@@ -20,6 +20,7 @@
"dependencies": {
"@intlify/unplugin-vue-i18n": "^4.0.0",
"@kyvg/vue3-notification": "^3.2.1",
+ "@mdi/js": "^7.4.47",
"@vueuse/core": "^10.10.0",
"ansi_up": "^6.0.2",
"dayjs": "^1.11.11",
@@ -30,20 +31,19 @@
"pinia": "^2.1.7",
"prismjs": "^1.29.0",
"semver": "^7.6.2",
+ "simple-icons": "^13.0.0",
"vue": "^3.4.27",
"vue-i18n": "^9.13.1",
"vue-router": "^4.3.2"
},
"devDependencies": {
- "@antfu/eslint-config": "^2.20.0",
+ "@antfu/eslint-config": "^3.0.0",
"@eslint/js": "^9.4.0",
"@ianvs/prettier-plugin-sort-imports": "^4.2.1",
- "@iconify/json": "^2.2.216",
- "@intlify/eslint-plugin-vue-i18n": "3.0.0-next.13",
+ "@intlify/eslint-plugin-vue-i18n": "3.0.0",
"@types/eslint__js": "^8.42.3",
"@types/lodash": "^4.17.4",
"@types/node": "^20.14.2",
- "@types/node-emoji": "^2.1.0",
"@types/prismjs": "^1.26.4",
"@types/semver": "^7.5.8",
"@types/tinycolor2": "^1.4.6",
@@ -51,21 +51,18 @@
"@vue/compiler-sfc": "^3.4.27",
"@vue/test-utils": "^2.4.6",
"eslint": "^9.4.0",
- "eslint-plugin-promise": "^6.2.0",
+ "eslint-plugin-promise": "^7.0.0",
"eslint-plugin-vue-scoped-css": "^2.8.0",
- "jsdom": "^24.1.0",
+ "jsdom": "^25.0.0",
"prettier": "^3.3.0",
- "replace-in-file": "^7.2.0",
+ "replace-in-file": "^8.0.0",
"tinycolor2": "^1.6.0",
- "typescript": "5.4.5",
- "typescript-eslint": "^7.12.0",
- "unplugin-icons": "^0.18.5",
- "unplugin-vue-components": "^0.26.0",
+ "typescript": "5.5.4",
"vite": "^5.2.12",
"vite-plugin-prismjs": "^0.0.11",
"vite-plugin-windicss": "^1.9.3",
"vite-svg-loader": "^5.1.0",
- "vitest": "^1.6.0",
+ "vitest": "^2.0.0",
"vue-tsc": "^2.0.19",
"windicss": "^3.5.6"
},
diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml
index 6ebe6c539..33185d220 100644
--- a/web/pnpm-lock.yaml
+++ b/web/pnpm-lock.yaml
@@ -13,19 +13,22 @@ importers:
dependencies:
'@intlify/unplugin-vue-i18n':
specifier: ^4.0.0
- version: 4.0.0(rollup@4.18.0)(vue-i18n@9.13.1(vue@3.4.29(typescript@5.4.5)))
+ version: 4.0.0(rollup@4.20.0)(vue-i18n@9.13.1(vue@3.4.38(typescript@5.5.4)))
'@kyvg/vue3-notification':
specifier: ^3.2.1
- version: 3.2.1(vue@3.4.29(typescript@5.4.5))
+ version: 3.2.1(vue@3.4.38(typescript@5.5.4))
+ '@mdi/js':
+ specifier: ^7.4.47
+ version: 7.4.47
'@vueuse/core':
specifier: ^10.10.0
- version: 10.11.0(vue@3.4.29(typescript@5.4.5))
+ version: 10.11.1(vue@3.4.38(typescript@5.5.4))
ansi_up:
specifier: ^6.0.2
version: 6.0.2
dayjs:
specifier: ^1.11.11
- version: 1.11.11
+ version: 1.11.12
fuse.js:
specifier: ^7.0.0
version: 7.0.0
@@ -40,50 +43,47 @@ importers:
version: 2.1.3
pinia:
specifier: ^2.1.7
- version: 2.1.7(typescript@5.4.5)(vue@3.4.29(typescript@5.4.5))
+ version: 2.2.1(typescript@5.5.4)(vue@3.4.38(typescript@5.5.4))
prismjs:
specifier: ^1.29.0
version: 1.29.0
semver:
specifier: ^7.6.2
- version: 7.6.2
+ version: 7.6.3
+ simple-icons:
+ specifier: ^13.0.0
+ version: 13.5.0
vue:
specifier: ^3.4.27
- version: 3.4.29(typescript@5.4.5)
+ version: 3.4.38(typescript@5.5.4)
vue-i18n:
specifier: ^9.13.1
- version: 9.13.1(vue@3.4.29(typescript@5.4.5))
+ version: 9.13.1(vue@3.4.38(typescript@5.5.4))
vue-router:
specifier: ^4.3.2
- version: 4.3.3(vue@3.4.29(typescript@5.4.5))
+ version: 4.4.3(vue@3.4.38(typescript@5.5.4))
devDependencies:
'@antfu/eslint-config':
- specifier: ^2.20.0
- version: 2.21.1(@vue/compiler-sfc@3.4.29)(eslint@9.5.0)(typescript@5.4.5)(vitest@1.6.0(@types/node@20.14.5)(jsdom@24.1.0)(stylus@0.57.0))
+ specifier: ^3.0.0
+ version: 3.3.2(@typescript-eslint/utils@8.4.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4))(@vue/compiler-sfc@3.4.38)(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)(vitest@2.0.5(@types/node@20.14.15)(jsdom@25.0.0)(stylus@0.57.0))
'@eslint/js':
specifier: ^9.4.0
- version: 9.5.0
+ version: 9.9.0
'@ianvs/prettier-plugin-sort-imports':
specifier: ^4.2.1
- version: 4.2.1(@vue/compiler-sfc@3.4.29)(prettier@3.3.2)
- '@iconify/json':
- specifier: ^2.2.216
- version: 2.2.220
+ version: 4.3.1(@vue/compiler-sfc@3.4.38)(prettier@3.3.3)
'@intlify/eslint-plugin-vue-i18n':
- specifier: 3.0.0-next.13
- version: 3.0.0-next.13(eslint@9.5.0)
+ specifier: 3.0.0
+ version: 3.0.0(eslint@9.9.0(jiti@1.21.6))
'@types/eslint__js':
specifier: ^8.42.3
version: 8.42.3
'@types/lodash':
specifier: ^4.17.4
- version: 4.17.5
+ version: 4.17.7
'@types/node':
specifier: ^20.14.2
- version: 20.14.5
- '@types/node-emoji':
- specifier: ^2.1.0
- version: 2.1.0
+ version: 20.14.15
'@types/prismjs':
specifier: ^1.26.4
version: 1.26.4
@@ -95,64 +95,55 @@ importers:
version: 1.4.6
'@vitejs/plugin-vue':
specifier: ^5.0.5
- version: 5.0.5(vite@5.3.1(@types/node@20.14.5)(stylus@0.57.0))(vue@3.4.29(typescript@5.4.5))
+ version: 5.1.2(vite@5.4.1(@types/node@20.14.15)(stylus@0.57.0))(vue@3.4.38(typescript@5.5.4))
'@vue/compiler-sfc':
specifier: ^3.4.27
- version: 3.4.29
+ version: 3.4.38
'@vue/test-utils':
specifier: ^2.4.6
version: 2.4.6
eslint:
specifier: ^9.4.0
- version: 9.5.0
+ version: 9.9.0(jiti@1.21.6)
eslint-plugin-promise:
- specifier: ^6.2.0
- version: 6.2.0(eslint@9.5.0)
+ specifier: ^7.0.0
+ version: 7.1.0(eslint@9.9.0(jiti@1.21.6))
eslint-plugin-vue-scoped-css:
specifier: ^2.8.0
- version: 2.8.0(eslint@9.5.0)(vue-eslint-parser@9.4.3(eslint@9.5.0))
+ version: 2.8.1(eslint@9.9.0(jiti@1.21.6))(vue-eslint-parser@9.4.3(eslint@9.9.0(jiti@1.21.6)))
jsdom:
- specifier: ^24.1.0
- version: 24.1.0
+ specifier: ^25.0.0
+ version: 25.0.0
prettier:
specifier: ^3.3.0
- version: 3.3.2
+ version: 3.3.3
replace-in-file:
- specifier: ^7.2.0
- version: 7.2.0
+ specifier: ^8.0.0
+ version: 8.1.0
tinycolor2:
specifier: ^1.6.0
version: 1.6.0
typescript:
- specifier: 5.4.5
- version: 5.4.5
- typescript-eslint:
- specifier: ^7.12.0
- version: 7.13.1(eslint@9.5.0)(typescript@5.4.5)
- unplugin-icons:
- specifier: ^0.18.5
- version: 0.18.5(@vue/compiler-sfc@3.4.29)(vue-template-compiler@2.7.16)
- unplugin-vue-components:
- specifier: ^0.26.0
- version: 0.26.0(@babel/parser@7.24.7)(rollup@4.18.0)(vue@3.4.29(typescript@5.4.5))
+ specifier: 5.5.4
+ version: 5.5.4
vite:
specifier: ^5.2.12
- version: 5.3.1(@types/node@20.14.5)(stylus@0.57.0)
+ version: 5.4.1(@types/node@20.14.15)(stylus@0.57.0)
vite-plugin-prismjs:
specifier: ^0.0.11
version: 0.0.11(prismjs@1.29.0)
vite-plugin-windicss:
specifier: ^1.9.3
- version: 1.9.3(vite@5.3.1(@types/node@20.14.5)(stylus@0.57.0))
+ version: 1.9.3(vite@5.4.1(@types/node@20.14.15)(stylus@0.57.0))
vite-svg-loader:
specifier: ^5.1.0
- version: 5.1.0(vue@3.4.29(typescript@5.4.5))
+ version: 5.1.0(vue@3.4.38(typescript@5.5.4))
vitest:
- specifier: ^1.6.0
- version: 1.6.0(@types/node@20.14.5)(jsdom@24.1.0)(stylus@0.57.0)
+ specifier: ^2.0.0
+ version: 2.0.5(@types/node@20.14.15)(jsdom@25.0.0)(stylus@0.57.0)
vue-tsc:
specifier: ^2.0.19
- version: 2.0.21(typescript@5.4.5)
+ version: 2.0.29(typescript@5.5.4)
windicss:
specifier: ^3.5.6
version: 3.5.6
@@ -163,24 +154,24 @@ packages:
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
engines: {node: '>=6.0.0'}
- '@antfu/eslint-config@2.21.1':
- resolution: {integrity: sha512-CG7U7nihU73zufrxe5Rr4pxsHrW60GXl9yzRpRY+ImGQ2CVhd0eb3fqJYdNwDJBgKgqHGWX4p1ovYvno/jfWHA==}
+ '@antfu/eslint-config@3.3.2':
+ resolution: {integrity: sha512-cHWbGP7CccmuUz/Aj6KORuLitkxuj2sONX+4PN+fvfJKTkVc2WXs9xlhO4AxhF1CU4Pn05M07OjDBXErqEmHzw==}
hasBin: true
peerDependencies:
'@eslint-react/eslint-plugin': ^1.5.8
'@prettier/plugin-xml': ^3.4.1
'@unocss/eslint-plugin': '>=0.50.0'
astro-eslint-parser: ^1.0.2
- eslint: '>=8.40.0'
+ eslint: ^9.5.0
eslint-plugin-astro: ^1.2.0
eslint-plugin-format: '>=0.1.0'
eslint-plugin-react-hooks: ^4.6.0
eslint-plugin-react-refresh: ^0.4.4
- eslint-plugin-solid: ^0.13.2
+ eslint-plugin-solid: ^0.14.3
eslint-plugin-svelte: '>=2.35.1'
prettier-plugin-astro: ^0.13.0
prettier-plugin-slidev: ^1.0.5
- svelte-eslint-parser: ^0.33.1
+ svelte-eslint-parser: '>=0.37.0'
peerDependenciesMeta:
'@eslint-react/eslint-plugin':
optional: true
@@ -209,53 +200,38 @@ packages:
svelte-eslint-parser:
optional: true
- '@antfu/install-pkg@0.1.1':
- resolution: {integrity: sha512-LyB/8+bSfa0DFGC06zpCEfs89/XoWZwws5ygEa5D+Xsm3OfI+aXQ86VgVG7Acyef+rSZ5HE7J8rrxzrQeM3PjQ==}
+ '@antfu/install-pkg@0.4.1':
+ resolution: {integrity: sha512-T7yB5QNG29afhWVkVq7XeIMBa5U/vs9mX69YqayXypPRmYzUmzwnYltplHmPtZ4HPCn+sQKeXW8I47wCbuBOjw==}
- '@antfu/install-pkg@0.3.3':
- resolution: {integrity: sha512-nHHsk3NXQ6xkCfiRRC8Nfrg8pU5kkr3P3Y9s9dKqiuRmBD0Yap7fymNDjGFKeWhZQHqqbCS5CfeMy9wtExM24w==}
-
- '@antfu/utils@0.7.8':
- resolution: {integrity: sha512-rWQkqXRESdjXtc+7NRfK9lASQjpXJu1ayp7qi1d23zZorY+wBHVLHHoVcMsEnkqEBWTFqbztO7/QdJFzyEcLTg==}
+ '@antfu/utils@0.7.10':
+ resolution: {integrity: sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==}
'@babel/code-frame@7.24.7':
resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==}
engines: {node: '>=6.9.0'}
- '@babel/compat-data@7.24.7':
- resolution: {integrity: sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==}
+ '@babel/compat-data@7.25.2':
+ resolution: {integrity: sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==}
engines: {node: '>=6.9.0'}
- '@babel/core@7.24.7':
- resolution: {integrity: sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==}
+ '@babel/core@7.25.2':
+ resolution: {integrity: sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==}
engines: {node: '>=6.9.0'}
- '@babel/generator@7.24.7':
- resolution: {integrity: sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==}
+ '@babel/generator@7.25.0':
+ resolution: {integrity: sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==}
engines: {node: '>=6.9.0'}
- '@babel/helper-compilation-targets@7.24.7':
- resolution: {integrity: sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-environment-visitor@7.24.7':
- resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-function-name@7.24.7':
- resolution: {integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-hoist-variables@7.24.7':
- resolution: {integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==}
+ '@babel/helper-compilation-targets@7.25.2':
+ resolution: {integrity: sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==}
engines: {node: '>=6.9.0'}
'@babel/helper-module-imports@7.24.7':
resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==}
engines: {node: '>=6.9.0'}
- '@babel/helper-module-transforms@7.24.7':
- resolution: {integrity: sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==}
+ '@babel/helper-module-transforms@7.25.2':
+ resolution: {integrity: sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
@@ -264,49 +240,50 @@ packages:
resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==}
engines: {node: '>=6.9.0'}
- '@babel/helper-split-export-declaration@7.24.7':
- resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-string-parser@7.24.7':
- resolution: {integrity: sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==}
+ '@babel/helper-string-parser@7.24.8':
+ resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==}
engines: {node: '>=6.9.0'}
'@babel/helper-validator-identifier@7.24.7':
resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==}
engines: {node: '>=6.9.0'}
- '@babel/helper-validator-option@7.24.7':
- resolution: {integrity: sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==}
+ '@babel/helper-validator-option@7.24.8':
+ resolution: {integrity: sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==}
engines: {node: '>=6.9.0'}
- '@babel/helpers@7.24.7':
- resolution: {integrity: sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==}
+ '@babel/helpers@7.25.0':
+ resolution: {integrity: sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==}
engines: {node: '>=6.9.0'}
'@babel/highlight@7.24.7':
resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==}
engines: {node: '>=6.9.0'}
- '@babel/parser@7.24.7':
- resolution: {integrity: sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==}
+ '@babel/parser@7.25.0':
+ resolution: {integrity: sha512-CzdIU9jdP0dg7HdyB+bHvDJGagUv+qtzZt5rYCWwW6tITNqV9odjp6Qu41gkG0ca5UfdDUWrKkiAnHHdGRnOrA==}
engines: {node: '>=6.0.0'}
hasBin: true
- '@babel/runtime@7.24.7':
- resolution: {integrity: sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==}
+ '@babel/parser@7.25.3':
+ resolution: {integrity: sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ '@babel/runtime@7.25.0':
+ resolution: {integrity: sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==}
engines: {node: '>=6.9.0'}
- '@babel/template@7.24.7':
- resolution: {integrity: sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==}
+ '@babel/template@7.25.0':
+ resolution: {integrity: sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==}
engines: {node: '>=6.9.0'}
- '@babel/traverse@7.24.7':
- resolution: {integrity: sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==}
+ '@babel/traverse@7.25.2':
+ resolution: {integrity: sha512-s4/r+a7xTnny2O6FcZzqgT6nE4/GHEdcqj4qAeglbUOh0TeglEfmNJFAd/OLoVtGd6ZhAO8GCVvCNUO5t/VJVQ==}
engines: {node: '>=6.9.0'}
- '@babel/types@7.24.7':
- resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==}
+ '@babel/types@7.25.2':
+ resolution: {integrity: sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==}
engines: {node: '>=6.9.0'}
'@clack/core@0.3.4':
@@ -321,6 +298,10 @@ packages:
resolution: {integrity: sha512-I238eDtOolvCuvtxrnqtlBaw0BwdQuYqK7eA6XIonicMdOOOb75mqdIzkGDUbS04+1Di007rgm9snFRNeVrOog==}
engines: {node: '>=16'}
+ '@es-joy/jsdoccomment@0.48.0':
+ resolution: {integrity: sha512-G6QUWIcC+KvSwXNsJyDTHvqUdNoAVJPPgkc3+Uk4WBKqZvoXhlvazOgm9aL0HwihJLQf0l+tOE2UFzXBqCqgDw==}
+ engines: {node: '>=16'}
+
'@esbuild/aix-ppc64@0.21.5':
resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
engines: {node: '>=12'}
@@ -459,26 +440,36 @@ packages:
cpu: [x64]
os: [win32]
+ '@eslint-community/eslint-plugin-eslint-comments@4.4.0':
+ resolution: {integrity: sha512-yljsWl5Qv3IkIRmJ38h3NrHXFCm4EUl55M8doGTF6hvzvFF8kRpextgSrg2dwHev9lzBZyafCr9RelGIyQm6fw==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0
+
'@eslint-community/eslint-utils@4.4.0':
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
- '@eslint-community/regexpp@4.10.1':
- resolution: {integrity: sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==}
+ '@eslint-community/regexpp@4.11.0':
+ resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
- '@eslint/config-array@0.16.0':
- resolution: {integrity: sha512-/jmuSd74i4Czf1XXn7wGRWZCuyaUZ330NH1Bek0Pplatt4Sy1S5haN21SCLLdbeKslQ+S0wEJ+++v5YibSi+Lg==}
+ '@eslint/compat@1.1.1':
+ resolution: {integrity: sha512-lpHyRyplhGPL5mGEh6M9O5nnKk0Gz4bFI+Zu6tKlPpDUN7XshWvH9C/px4UVm87IAANE0W81CEsNGbS1KlzXpA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/config-array@0.17.1':
+ resolution: {integrity: sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/eslintrc@3.1.0':
resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@eslint/js@9.5.0':
- resolution: {integrity: sha512-A7+AOT2ICkodvtsWnxZP4Xxk3NbZ3VMHd8oihydLRGrJgqqdEz1qSeEgXYyT/Cu8h1TWWsQRejIx48mtjZ5y1w==}
+ '@eslint/js@9.9.0':
+ resolution: {integrity: sha512-hhetes6ZHP3BlXLxmd8K2SNgkhNSi+UcecbnwWKwpP7kyi/uC75DJ1lOOBO3xrC4jyojtGE3YxKZPHfk4yrgug==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/object-schema@2.1.4':
@@ -493,8 +484,8 @@ packages:
resolution: {integrity: sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==}
engines: {node: '>=18.18'}
- '@ianvs/prettier-plugin-sort-imports@4.2.1':
- resolution: {integrity: sha512-NKN1LVFWUDGDGr3vt+6Ey3qPeN/163uR1pOPAlkWpgvAqgxQ6kSdUf1F0it8aHUtKRUzEGcK38Wxd07O61d7+Q==}
+ '@ianvs/prettier-plugin-sort-imports@4.3.1':
+ resolution: {integrity: sha512-ZHwbyjkANZOjaBm3ZosADD2OUYGFzQGxfy67HmGZU94mHqe7g1LCMA7YYKB1Cq+UTPCBqlAYapY0KXAjKEw8Sg==}
peerDependencies:
'@vue/compiler-sfc': 2.7.x || 3.x
prettier: 2 || 3
@@ -502,15 +493,6 @@ packages:
'@vue/compiler-sfc':
optional: true
- '@iconify/json@2.2.220':
- resolution: {integrity: sha512-EpKZAK99E5qmgeOS5XOxzlzPaYXOkhLneypLFvbKIU3/KGmxGS/k6pgaEX6wTId4oF2HPGBDJnXyvckHiOHQiA==}
-
- '@iconify/types@2.0.0':
- resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
-
- '@iconify/utils@2.1.24':
- resolution: {integrity: sha512-H8r2KpL5uKyrkb3z9/3HD/22JcxqW3BJyjEWZhX2T7DehnYVZthEap1cNsEl/UtCDC3TlpNmwiPX8wg3y8E4dg==}
-
'@intlify/bundle-utils@8.0.0':
resolution: {integrity: sha512-1B++zykRnMwQ+20SpsZI1JCnV/YJt9Oq7AGlEurzkWJOFtFAVqaGc/oV36PBRYeiKnTbY9VYfjBimr2Vt42wLQ==}
engines: {node: '>= 14.16'}
@@ -527,8 +509,8 @@ packages:
resolution: {integrity: sha512-+bcQRkJO9pcX8d0gel9ZNfrzU22sZFSA0WVhfXrf5jdJOS24a+Bp8pozuS9sBI9Hk/tGz83pgKfmqcn/Ci7/8w==}
engines: {node: '>= 16'}
- '@intlify/eslint-plugin-vue-i18n@3.0.0-next.13':
- resolution: {integrity: sha512-Z0JNZ47LcskNNSRfjLaS4OuSwJ1YDLtQW5s6xIpiRUqE+ehGD25tLMv3or+9Ajh9uiN6/Zu8emC3+Q5ao4sFqA==}
+ '@intlify/eslint-plugin-vue-i18n@3.0.0':
+ resolution: {integrity: sha512-s4fe+VOiqMZGhDrXWnL1xLyHbcFWBcEBeD/KpVrkOtL+utH2LPTi7uZ8RvWSthMS0mUL/7L74hFJ//OUU7AYww==}
engines: {node: '>=18.0.0'}
peerDependencies:
eslint: ^8.0.0 || ^9.0.0-0
@@ -560,10 +542,6 @@ packages:
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
- '@jest/schemas@29.6.3':
- resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
'@jridgewell/gen-mapping@0.3.5':
resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
engines: {node: '>=6.0.0'}
@@ -576,21 +554,20 @@ packages:
resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
engines: {node: '>=6.0.0'}
- '@jridgewell/sourcemap-codec@1.4.15':
- resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
+ '@jridgewell/sourcemap-codec@1.5.0':
+ resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
'@jridgewell/trace-mapping@0.3.25':
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
- '@jsdevtools/ez-spawn@3.0.4':
- resolution: {integrity: sha512-f5DRIOZf7wxogefH03RjMPMdBF7ADTWUMoOs9kaJo06EfwF+aFhMZMDZxHg/Xe12hptN9xoZjGso2fdjapBRIA==}
- engines: {node: '>=10'}
-
'@kyvg/vue3-notification@3.2.1':
resolution: {integrity: sha512-qn4bCBBCxW0Ya+RmHXu2SYBVwGXWsAGdlDKqCqyLryaZTbtFXi32iSSLnuKjSUVxFqQRToFc6g1zp1XLTyHrvw==}
peerDependencies:
vue: ^3.0.0
+ '@mdi/js@7.4.47':
+ resolution: {integrity: sha512-KPnNOtm5i2pMabqZxpUz7iQf+mfrYZyKCZ8QNz85czgEt7cuHcGorWfdzUMWYA0SD+a6Hn4FmJ+YhzzzjkTZrQ==}
+
'@nodelib/fs.scandir@2.1.5':
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@@ -623,118 +600,92 @@ packages:
rollup:
optional: true
- '@rollup/rollup-android-arm-eabi@4.18.0':
- resolution: {integrity: sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==}
+ '@rollup/rollup-android-arm-eabi@4.20.0':
+ resolution: {integrity: sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==}
cpu: [arm]
os: [android]
- '@rollup/rollup-android-arm64@4.18.0':
- resolution: {integrity: sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==}
+ '@rollup/rollup-android-arm64@4.20.0':
+ resolution: {integrity: sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==}
cpu: [arm64]
os: [android]
- '@rollup/rollup-darwin-arm64@4.18.0':
- resolution: {integrity: sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==}
+ '@rollup/rollup-darwin-arm64@4.20.0':
+ resolution: {integrity: sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==}
cpu: [arm64]
os: [darwin]
- '@rollup/rollup-darwin-x64@4.18.0':
- resolution: {integrity: sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==}
+ '@rollup/rollup-darwin-x64@4.20.0':
+ resolution: {integrity: sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==}
cpu: [x64]
os: [darwin]
- '@rollup/rollup-linux-arm-gnueabihf@4.18.0':
- resolution: {integrity: sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==}
+ '@rollup/rollup-linux-arm-gnueabihf@4.20.0':
+ resolution: {integrity: sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==}
cpu: [arm]
os: [linux]
- '@rollup/rollup-linux-arm-musleabihf@4.18.0':
- resolution: {integrity: sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==}
+ '@rollup/rollup-linux-arm-musleabihf@4.20.0':
+ resolution: {integrity: sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==}
cpu: [arm]
os: [linux]
- '@rollup/rollup-linux-arm64-gnu@4.18.0':
- resolution: {integrity: sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==}
+ '@rollup/rollup-linux-arm64-gnu@4.20.0':
+ resolution: {integrity: sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==}
cpu: [arm64]
os: [linux]
- '@rollup/rollup-linux-arm64-musl@4.18.0':
- resolution: {integrity: sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==}
+ '@rollup/rollup-linux-arm64-musl@4.20.0':
+ resolution: {integrity: sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==}
cpu: [arm64]
os: [linux]
- '@rollup/rollup-linux-powerpc64le-gnu@4.18.0':
- resolution: {integrity: sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==}
+ '@rollup/rollup-linux-powerpc64le-gnu@4.20.0':
+ resolution: {integrity: sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==}
cpu: [ppc64]
os: [linux]
- '@rollup/rollup-linux-riscv64-gnu@4.18.0':
- resolution: {integrity: sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==}
+ '@rollup/rollup-linux-riscv64-gnu@4.20.0':
+ resolution: {integrity: sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==}
cpu: [riscv64]
os: [linux]
- '@rollup/rollup-linux-s390x-gnu@4.18.0':
- resolution: {integrity: sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==}
+ '@rollup/rollup-linux-s390x-gnu@4.20.0':
+ resolution: {integrity: sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==}
cpu: [s390x]
os: [linux]
- '@rollup/rollup-linux-x64-gnu@4.18.0':
- resolution: {integrity: sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==}
+ '@rollup/rollup-linux-x64-gnu@4.20.0':
+ resolution: {integrity: sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==}
cpu: [x64]
os: [linux]
- '@rollup/rollup-linux-x64-musl@4.18.0':
- resolution: {integrity: sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==}
+ '@rollup/rollup-linux-x64-musl@4.20.0':
+ resolution: {integrity: sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==}
cpu: [x64]
os: [linux]
- '@rollup/rollup-win32-arm64-msvc@4.18.0':
- resolution: {integrity: sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==}
+ '@rollup/rollup-win32-arm64-msvc@4.20.0':
+ resolution: {integrity: sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==}
cpu: [arm64]
os: [win32]
- '@rollup/rollup-win32-ia32-msvc@4.18.0':
- resolution: {integrity: sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==}
+ '@rollup/rollup-win32-ia32-msvc@4.20.0':
+ resolution: {integrity: sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==}
cpu: [ia32]
os: [win32]
- '@rollup/rollup-win32-x64-msvc@4.18.0':
- resolution: {integrity: sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==}
+ '@rollup/rollup-win32-x64-msvc@4.20.0':
+ resolution: {integrity: sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==}
cpu: [x64]
os: [win32]
- '@sinclair/typebox@0.27.8':
- resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
-
'@sindresorhus/is@4.6.0':
resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==}
engines: {node: '>=10'}
- '@stylistic/eslint-plugin-js@2.2.1':
- resolution: {integrity: sha512-M2dQkKw2R4R+b1SJ/xElJ9bDVq/vCI31VpIIxkZD9KXCqbUHvtsGpZH3eO6MzmFWOZj4PfNdEQdP332MtqjCPg==}
- engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- peerDependencies:
- eslint: '>=8.40.0'
-
- '@stylistic/eslint-plugin-jsx@2.2.1':
- resolution: {integrity: sha512-J/R4tU38v8gVqKPy6Mh22dq8btLSPWK06SuRc/ryOxT8LpW2ZdcSDP4HNvQiOte0Wy9xzgKJHP4JlYauDZ/oVw==}
- engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- peerDependencies:
- eslint: '>=8.40.0'
-
- '@stylistic/eslint-plugin-plus@2.2.1':
- resolution: {integrity: sha512-VGdTcQzZ/cZNcJnvjDos1VLzUerPapvYCVSCQZEhupMtmxt+mbITiJWzLLHYNfqGBnW7ABqViLfob+s3Q2GcKw==}
- peerDependencies:
- eslint: '*'
-
- '@stylistic/eslint-plugin-ts@2.2.1':
- resolution: {integrity: sha512-2AbpXGGorCEzDryth7RhOMJWlko+sxSs1lxL2tSXB5H/EffmXgLn1tMoMKgwYJW3s6v0BxJRr5BWj9B9JaZTUQ==}
- engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- peerDependencies:
- eslint: '>=8.40.0'
-
- '@stylistic/eslint-plugin@2.2.1':
- resolution: {integrity: sha512-YErqfwWFbRCpkyPtrcVYaJhvEn9aXE4WzxxkZ7Q3OKS4QD9CE6qZjzEw5DhcA2wL3Jo6JbzSB3/stJMNocGMgQ==}
+ '@stylistic/eslint-plugin@2.7.2':
+ resolution: {integrity: sha512-3DVLU5HEuk2pQoBmXJlzvrxbKNpu2mJ0SRqz5O/CJjyNCr12ZiPcYMEtuArTyPOk5i7bsAU44nywh1rGfe3gKQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: '>=8.40.0'
@@ -743,8 +694,14 @@ packages:
resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
engines: {node: '>=10.13.0'}
- '@types/eslint@8.56.10':
- resolution: {integrity: sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==}
+ '@types/eslint@8.56.11':
+ resolution: {integrity: sha512-sVBpJMf7UPo/wGecYOpk2aQya2VUGeHhe38WG7/mN5FufNSubf5VT9Uh9Uyp8/eLJpu1/tuhJ/qTo4mhSB4V4Q==}
+
+ '@types/eslint@9.6.0':
+ resolution: {integrity: sha512-gi6WQJ7cHRgZxtkQEoyHMppPjq9Kxo5Tjn2prSKDSmZrCz8TZ3jSRCeTJm+WoM+oB0WG37bRqLzaaU3q7JypGg==}
+
+ '@types/eslint@9.6.1':
+ resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==}
'@types/eslint__js@8.42.3':
resolution: {integrity: sha512-alfG737uhmPdnvkrLdZLcEKJ/B8s9Y4hrZ+YAdzUeoArBlSUERA2E87ROfOaS4jd/C45fzOoZzidLc1IPwLqOw==}
@@ -755,18 +712,14 @@ packages:
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
- '@types/lodash@4.17.5':
- resolution: {integrity: sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw==}
+ '@types/lodash@4.17.7':
+ resolution: {integrity: sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==}
'@types/mdast@3.0.15':
resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==}
- '@types/node-emoji@2.1.0':
- resolution: {integrity: sha512-LBGWP2LL5A+PpcvzrgXCFcHt9N1l5bqQn05ZUQFFM625k/tmc2w9ghT4kUwQN6gIPlX6qnDOfekmJmV9BywV9g==}
- deprecated: This is a stub types definition. node-emoji provides its own type definitions, so you do not need this installed.
-
- '@types/node@20.14.5':
- resolution: {integrity: sha512-aoRR+fJkZT2l0aGOJhuA8frnCSoNX6W7U2mpNq63+BxBIj5BQFt8rHy627kijCmm63ijdSdwvGgpUsU6MBsZZA==}
+ '@types/node@20.14.15':
+ resolution: {integrity: sha512-Fz1xDMCF/B00/tYSVMlmK7hVeLh7jE5f3B7X1/hmV0MJBwE27KlS7EvD/Yp+z1lm8mVhwV5w+n8jOZG8AfTlKw==}
'@types/normalize-package-data@2.4.4':
resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==}
@@ -780,152 +733,203 @@ packages:
'@types/tinycolor2@1.4.6':
resolution: {integrity: sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw==}
- '@types/unist@2.0.10':
- resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==}
+ '@types/unist@2.0.11':
+ resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==}
'@types/web-bluetooth@0.0.20':
resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
- '@typescript-eslint/eslint-plugin@7.13.1':
- resolution: {integrity: sha512-kZqi+WZQaZfPKnsflLJQCz6Ze9FFSMfXrrIOcyargekQxG37ES7DJNpJUE9Q/X5n3yTIP/WPutVNzgknQ7biLg==}
- engines: {node: ^18.18.0 || >=20.0.0}
+ '@typescript-eslint/eslint-plugin@8.4.0':
+ resolution: {integrity: sha512-rg8LGdv7ri3oAlenMACk9e+AR4wUV0yrrG+XKsGKOK0EVgeEDqurkXMPILG2836fW4ibokTB5v4b6Z9+GYQDEw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
- '@typescript-eslint/parser': ^7.0.0
- eslint: ^8.56.0
+ '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0
+ eslint: ^8.57.0 || ^9.0.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
- '@typescript-eslint/parser@7.13.1':
- resolution: {integrity: sha512-1ELDPlnLvDQ5ybTSrMhRTFDfOQEOXNM+eP+3HT/Yq7ruWpciQw+Avi73pdEbA4SooCawEWo3dtYbF68gN7Ed1A==}
- engines: {node: ^18.18.0 || >=20.0.0}
+ '@typescript-eslint/parser@8.4.0':
+ resolution: {integrity: sha512-NHgWmKSgJk5K9N16GIhQ4jSobBoJwrmURaLErad0qlLjrpP5bECYg+wxVTGlGZmJbU03jj/dfnb6V9bw+5icsA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
- eslint: ^8.56.0
+ eslint: ^8.57.0 || ^9.0.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
- '@typescript-eslint/scope-manager@7.13.1':
- resolution: {integrity: sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==}
- engines: {node: ^18.18.0 || >=20.0.0}
+ '@typescript-eslint/scope-manager@8.1.0':
+ resolution: {integrity: sha512-DsuOZQji687sQUjm4N6c9xABJa7fjvfIdjqpSIIVOgaENf2jFXiM9hIBZOL3hb6DHK9Nvd2d7zZnoMLf9e0OtQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@typescript-eslint/type-utils@7.13.1':
- resolution: {integrity: sha512-aWDbLu1s9bmgPGXSzNCxELu+0+HQOapV/y+60gPXafR8e2g1Bifxzevaa+4L2ytCWm+CHqpELq4CSoN9ELiwCg==}
- engines: {node: ^18.18.0 || >=20.0.0}
- peerDependencies:
- eslint: ^8.56.0
- typescript: '*'
- peerDependenciesMeta:
- typescript:
- optional: true
+ '@typescript-eslint/scope-manager@8.4.0':
+ resolution: {integrity: sha512-n2jFxLeY0JmKfUqy3P70rs6vdoPjHK8P/w+zJcV3fk0b0BwRXC/zxRTEnAsgYT7MwdQDt/ZEbtdzdVC+hcpF0A==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@typescript-eslint/types@7.13.1':
- resolution: {integrity: sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==}
- engines: {node: ^18.18.0 || >=20.0.0}
-
- '@typescript-eslint/typescript-estree@7.13.1':
- resolution: {integrity: sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==}
- engines: {node: ^18.18.0 || >=20.0.0}
+ '@typescript-eslint/type-utils@8.4.0':
+ resolution: {integrity: sha512-pu2PAmNrl9KX6TtirVOrbLPLwDmASpZhK/XU7WvoKoCUkdtq9zF7qQ7gna0GBZFN0hci0vHaSusiL2WpsQk37A==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
- '@typescript-eslint/utils@7.13.1':
- resolution: {integrity: sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==}
+ '@typescript-eslint/types@7.18.0':
+ resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==}
engines: {node: ^18.18.0 || >=20.0.0}
+
+ '@typescript-eslint/types@8.1.0':
+ resolution: {integrity: sha512-q2/Bxa0gMOu/2/AKALI0tCKbG2zppccnRIRCW6BaaTlRVaPKft4oVYPp7WOPpcnsgbr0qROAVCVKCvIQ0tbWog==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@typescript-eslint/types@8.4.0':
+ resolution: {integrity: sha512-T1RB3KQdskh9t3v/qv7niK6P8yvn7ja1mS7QK7XfRVL6wtZ8/mFs/FHf4fKvTA0rKnqnYxl/uHFNbnEt0phgbw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@typescript-eslint/typescript-estree@8.1.0':
+ resolution: {integrity: sha512-NTHhmufocEkMiAord/g++gWKb0Fr34e9AExBRdqgWdVBaKoei2dIyYKD9Q0jBnvfbEA5zaf8plUFMUH6kQ0vGg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
- eslint: ^8.56.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
- '@typescript-eslint/visitor-keys@7.13.1':
- resolution: {integrity: sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==}
- engines: {node: ^18.18.0 || >=20.0.0}
+ '@typescript-eslint/typescript-estree@8.4.0':
+ resolution: {integrity: sha512-kJ2OIP4dQw5gdI4uXsaxUZHRwWAGpREJ9Zq6D5L0BweyOrWsL6Sz0YcAZGWhvKnH7fm1J5YFE1JrQL0c9dd53A==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
- '@vitejs/plugin-vue@5.0.5':
- resolution: {integrity: sha512-LOjm7XeIimLBZyzinBQ6OSm3UBCNVCpLkxGC0oWmm2YPzVZoxMsdvNVimLTBzpAnR9hl/yn1SHGuRfe6/Td9rQ==}
+ '@typescript-eslint/utils@8.1.0':
+ resolution: {integrity: sha512-ypRueFNKTIFwqPeJBfeIpxZ895PQhNyH4YID6js0UoBImWYoSjBsahUn9KMiJXh94uOjVBgHD9AmkyPsPnFwJA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+
+ '@typescript-eslint/utils@8.4.0':
+ resolution: {integrity: sha512-swULW8n1IKLjRAgciCkTCafyTHHfwVQFt8DovmaF69sKbOxTSFMmIZaSHjqO9i/RV0wIblaawhzvtva8Nmm7lQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+
+ '@typescript-eslint/visitor-keys@8.1.0':
+ resolution: {integrity: sha512-ba0lNI19awqZ5ZNKh6wCModMwoZs457StTebQ0q1NP58zSi2F6MOZRXwfKZy+jB78JNJ/WH8GSh2IQNzXX8Nag==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@typescript-eslint/visitor-keys@8.4.0':
+ resolution: {integrity: sha512-zTQD6WLNTre1hj5wp09nBIDiOc2U5r/qmzo7wxPn4ZgAjHql09EofqhF9WF+fZHzL5aCyaIpPcT2hyxl73kr9A==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@vitejs/plugin-vue@5.1.2':
+ resolution: {integrity: sha512-nY9IwH12qeiJqumTCLJLE7IiNx7HZ39cbHaysEUd+Myvbz9KAqd2yq+U01Kab1R/H1BmiyM2ShTYlNH32Fzo3A==}
engines: {node: ^18.0.0 || >=20.0.0}
peerDependencies:
vite: ^5.0.0
vue: ^3.2.25
- '@vitest/expect@1.6.0':
- resolution: {integrity: sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==}
+ '@vitest/eslint-plugin@1.1.0':
+ resolution: {integrity: sha512-Ur80Y27Wbw8gFHJ3cv6vypcjXmrx6QHfw+q435h6Q2L+tf+h4Xf5pJTCL4YU/Jps9EVeggQxS85OcUZU7sdXRw==}
+ peerDependencies:
+ '@typescript-eslint/utils': '>= 8.0'
+ eslint: '>= 8.57.0'
+ typescript: '>= 5.0.0'
+ vitest: '*'
+ peerDependenciesMeta:
+ '@typescript-eslint/utils':
+ optional: true
+ typescript:
+ optional: true
+ vitest:
+ optional: true
- '@vitest/runner@1.6.0':
- resolution: {integrity: sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==}
+ '@vitest/expect@2.0.5':
+ resolution: {integrity: sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA==}
- '@vitest/snapshot@1.6.0':
- resolution: {integrity: sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==}
+ '@vitest/pretty-format@2.0.5':
+ resolution: {integrity: sha512-h8k+1oWHfwTkyTkb9egzwNMfJAEx4veaPSnMeKbVSjp4euqGSbQlm5+6VHwTr7u4FJslVVsUG5nopCaAYdOmSQ==}
- '@vitest/spy@1.6.0':
- resolution: {integrity: sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==}
+ '@vitest/runner@2.0.5':
+ resolution: {integrity: sha512-TfRfZa6Bkk9ky4tW0z20WKXFEwwvWhRY+84CnSEtq4+3ZvDlJyY32oNTJtM7AW9ihW90tX/1Q78cb6FjoAs+ig==}
- '@vitest/utils@1.6.0':
- resolution: {integrity: sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==}
+ '@vitest/snapshot@2.0.5':
+ resolution: {integrity: sha512-SgCPUeDFLaM0mIUHfaArq8fD2WbaXG/zVXjRupthYfYGzc8ztbFbu6dUNOblBG7XLMR1kEhS/DNnfCZ2IhdDew==}
- '@volar/language-core@2.3.0':
- resolution: {integrity: sha512-pvhL24WUh3VDnv7Yw5N1sjhPtdx7q9g+Wl3tggmnkMcyK8GcCNElF2zHiKznryn0DiUGk+eez/p2qQhz+puuHw==}
+ '@vitest/spy@2.0.5':
+ resolution: {integrity: sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA==}
- '@volar/source-map@2.3.0':
- resolution: {integrity: sha512-G/228aZjAOGhDjhlyZ++nDbKrS9uk+5DMaEstjvzglaAw7nqtDyhnQAsYzUg6BMP9BtwZ59RIw5HGePrutn00Q==}
+ '@vitest/utils@2.0.5':
+ resolution: {integrity: sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==}
- '@volar/typescript@2.3.0':
- resolution: {integrity: sha512-PtUwMM87WsKVeLJN33GSTUjBexlKfKgouWlOUIv7pjrOnTwhXHZNSmpc312xgXdTjQPpToK6KXSIcKu9sBQ5LQ==}
+ '@volar/language-core@2.4.0-alpha.18':
+ resolution: {integrity: sha512-JAYeJvYQQROmVRtSBIczaPjP3DX4QW1fOqW1Ebs0d3Y3EwSNRglz03dSv0Dm61dzd0Yx3WgTW3hndDnTQqgmyg==}
- '@vue/compiler-core@3.4.29':
- resolution: {integrity: sha512-TFKiRkKKsRCKvg/jTSSKK7mYLJEQdUiUfykbG49rubC9SfDyvT2JrzTReopWlz2MxqeLyxh9UZhvxEIBgAhtrg==}
+ '@volar/source-map@2.4.0-alpha.18':
+ resolution: {integrity: sha512-MTeCV9MUwwsH0sNFiZwKtFrrVZUK6p8ioZs3xFzHc2cvDXHWlYN3bChdQtwKX+FY2HG6H3CfAu1pKijolzIQ8g==}
- '@vue/compiler-dom@3.4.29':
- resolution: {integrity: sha512-A6+iZ2fKIEGnfPJejdB7b1FlJzgiD+Y/sxxKwJWg1EbJu6ZPgzaPQQ51ESGNv0CP6jm6Z7/pO6Ia8Ze6IKrX7w==}
+ '@volar/typescript@2.4.0-alpha.18':
+ resolution: {integrity: sha512-sXh5Y8sqGUkgxpMWUGvRXggxYHAVxg0Pa1C42lQZuPDrW6vHJPR0VCK8Sr7WJsAW530HuNQT/ZIskmXtxjybMQ==}
- '@vue/compiler-sfc@3.4.29':
- resolution: {integrity: sha512-zygDcEtn8ZimDlrEQyLUovoWgKQic6aEQqRXce2WXBvSeHbEbcAsXyCk9oG33ZkyWH4sl9D3tkYc1idoOkdqZQ==}
+ '@vue/compiler-core@3.4.38':
+ resolution: {integrity: sha512-8IQOTCWnLFqfHzOGm9+P8OPSEDukgg3Huc92qSG49if/xI2SAwLHQO2qaPQbjCWPBcQoO1WYfXfTACUrWV3c5A==}
- '@vue/compiler-ssr@3.4.29':
- resolution: {integrity: sha512-rFbwCmxJ16tDp3N8XCx5xSQzjhidYjXllvEcqX/lopkoznlNPz3jyy0WGJCyhAaVQK677WWFt3YO/WUEkMMUFQ==}
+ '@vue/compiler-dom@3.4.38':
+ resolution: {integrity: sha512-Osc/c7ABsHXTsETLgykcOwIxFktHfGSUDkb05V61rocEfsFDcjDLH/IHJSNJP+/Sv9KeN2Lx1V6McZzlSb9EhQ==}
+
+ '@vue/compiler-sfc@3.4.38':
+ resolution: {integrity: sha512-s5QfZ+9PzPh3T5H4hsQDJtI8x7zdJaew/dCGgqZ2630XdzaZ3AD8xGZfBqpT8oaD/p2eedd+pL8tD5vvt5ZYJQ==}
+
+ '@vue/compiler-ssr@3.4.38':
+ resolution: {integrity: sha512-YXznKFQ8dxYpAz9zLuVvfcXhc31FSPFDcqr0kyujbOwNhlmaNvL2QfIy+RZeJgSn5Fk54CWoEUeW+NVBAogGaw==}
+
+ '@vue/compiler-vue2@2.7.16':
+ resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==}
'@vue/devtools-api@6.6.3':
resolution: {integrity: sha512-0MiMsFma/HqA6g3KLKn+AGpL1kgKhFWszC9U29NfpWK5LE7bjeXxySWJrOJ77hBz+TBrBQ7o4QJqbPbqbs8rJw==}
- '@vue/language-core@2.0.21':
- resolution: {integrity: sha512-vjs6KwnCK++kIXT+eI63BGpJHfHNVJcUCr3RnvJsccT3vbJnZV5IhHR2puEkoOkIbDdp0Gqi1wEnv3hEd3WsxQ==}
+ '@vue/language-core@2.0.29':
+ resolution: {integrity: sha512-o2qz9JPjhdoVj8D2+9bDXbaI4q2uZTHQA/dbyZT4Bj1FR9viZxDJnLcKVHfxdn6wsOzRgpqIzJEEmSSvgMvDTQ==}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
- '@vue/reactivity@3.4.29':
- resolution: {integrity: sha512-w8+KV+mb1a8ornnGQitnMdLfE0kXmteaxLdccm2XwdFxXst4q/Z7SEboCV5SqJNpZbKFeaRBBJBhW24aJyGINg==}
+ '@vue/reactivity@3.4.38':
+ resolution: {integrity: sha512-4vl4wMMVniLsSYYeldAKzbk72+D3hUnkw9z8lDeJacTxAkXeDAP1uE9xr2+aKIN0ipOL8EG2GPouVTH6yF7Gnw==}
- '@vue/runtime-core@3.4.29':
- resolution: {integrity: sha512-s8fmX3YVR/Rk5ig0ic0NuzTNjK2M7iLuVSZyMmCzN/+Mjuqqif1JasCtEtmtoJWF32pAtUjyuT2ljNKNLeOmnQ==}
+ '@vue/runtime-core@3.4.38':
+ resolution: {integrity: sha512-21z3wA99EABtuf+O3IhdxP0iHgkBs1vuoCAsCKLVJPEjpVqvblwBnTj42vzHRlWDCyxu9ptDm7sI2ZMcWrQqlA==}
- '@vue/runtime-dom@3.4.29':
- resolution: {integrity: sha512-gI10atCrtOLf/2MPPMM+dpz3NGulo9ZZR9d1dWo4fYvm+xkfvRrw1ZmJ7mkWtiJVXSsdmPbcK1p5dZzOCKDN0g==}
+ '@vue/runtime-dom@3.4.38':
+ resolution: {integrity: sha512-afZzmUreU7vKwKsV17H1NDThEEmdYI+GCAK/KY1U957Ig2NATPVjCROv61R19fjZNzMmiU03n79OMnXyJVN0UA==}
- '@vue/server-renderer@3.4.29':
- resolution: {integrity: sha512-HMLCmPI2j/k8PVkSBysrA2RxcxC5DgBiCdj7n7H2QtR8bQQPqKAe8qoaxLcInzouBmzwJ+J0x20ygN/B5mYBng==}
+ '@vue/server-renderer@3.4.38':
+ resolution: {integrity: sha512-NggOTr82FbPEkkUvBm4fTGcwUY8UuTsnWC/L2YZBmvaQ4C4Jl/Ao4HHTB+l7WnFCt5M/dN3l0XLuyjzswGYVCA==}
peerDependencies:
- vue: 3.4.29
+ vue: 3.4.38
- '@vue/shared@3.4.29':
- resolution: {integrity: sha512-hQ2gAQcBO/CDpC82DCrinJNgOHI2v+FA7BDW4lMSPeBpQ7sRe2OLHWe5cph1s7D8DUQAwRt18dBDfJJ220APEA==}
+ '@vue/shared@3.4.38':
+ resolution: {integrity: sha512-q0xCiLkuWWQLzVrecPb0RMsNWyxICOjPrcrwxTUEHb1fsnvni4dcuyG7RT/Ie7VPTvnjzIaWzRMUBsrqNj/hhw==}
'@vue/test-utils@2.4.6':
resolution: {integrity: sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==}
- '@vueuse/core@10.11.0':
- resolution: {integrity: sha512-x3sD4Mkm7PJ+pcq3HX8PLPBadXCAlSDR/waK87dz0gQE+qJnaaFhc/dZVfJz+IUYzTMVGum2QlR7ImiJQN4s6g==}
+ '@vueuse/core@10.11.1':
+ resolution: {integrity: sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==}
- '@vueuse/metadata@10.11.0':
- resolution: {integrity: sha512-kQX7l6l8dVWNqlqyN3ePW3KmjCQO3ZMgXuBMddIu83CmucrsBfXlH+JoviYyRBws/yLTQO8g3Pbw+bdIoVm4oQ==}
+ '@vueuse/metadata@10.11.1':
+ resolution: {integrity: sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==}
- '@vueuse/shared@10.11.0':
- resolution: {integrity: sha512-fyNoIXEq3PfX1L3NkNhtVQUSRtqYwJtJg+Bp9rIzculIZWHTkKSysujrOk2J+NrRulLTQH9+3gGSfYLWSEWU1A==}
+ '@vueuse/shared@10.11.1':
+ resolution: {integrity: sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==}
'@windicss/config@1.9.3':
resolution: {integrity: sha512-u8GUjsfC9r5X1AGYhzb1lX3zZj8wqk6SH1DYex8XUGmZ1M2UpvnUPOFi63XFViduspQ6l2xTX84QtG+lUzhEoQ==}
@@ -942,12 +946,8 @@ packages:
peerDependencies:
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
- acorn-walk@8.3.3:
- resolution: {integrity: sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==}
- engines: {node: '>=0.4.0'}
-
- acorn@8.12.0:
- resolution: {integrity: sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==}
+ acorn@8.12.1:
+ resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==}
engines: {node: '>=0.4.0'}
hasBin: true
@@ -974,10 +974,6 @@ packages:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
- ansi-styles@5.2.0:
- resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
- engines: {node: '>=10'}
-
ansi-styles@6.2.1:
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
engines: {node: '>=12'}
@@ -1000,8 +996,9 @@ packages:
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
engines: {node: '>=8'}
- assertion-error@1.1.0:
- resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
+ assertion-error@2.0.1:
+ resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
+ engines: {node: '>=12'}
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
@@ -1036,8 +1033,13 @@ packages:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'}
- browserslist@4.23.1:
- resolution: {integrity: sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==}
+ browserslist@4.23.2:
+ resolution: {integrity: sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+
+ browserslist@4.23.3:
+ resolution: {integrity: sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
@@ -1049,19 +1051,19 @@ packages:
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'}
- call-me-maybe@1.0.2:
- resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==}
-
callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
- caniuse-lite@1.0.30001636:
- resolution: {integrity: sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==}
+ caniuse-lite@1.0.30001644:
+ resolution: {integrity: sha512-YGvlOZB4QhZuiis+ETS0VXR+MExbFf4fZYYeMTEE0aTQd/RdIjkTyZjLrbYVKnHzppDvnOhritRVv+i7Go6mHw==}
- chai@4.4.1:
- resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==}
- engines: {node: '>=4'}
+ caniuse-lite@1.0.30001651:
+ resolution: {integrity: sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==}
+
+ chai@5.1.1:
+ resolution: {integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==}
+ engines: {node: '>=12'}
chalk@2.4.2:
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
@@ -1071,6 +1073,10 @@ packages:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
+ chalk@5.3.0:
+ resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==}
+ engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
+
char-regex@1.0.2:
resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
engines: {node: '>=10'}
@@ -1084,8 +1090,9 @@ packages:
character-reference-invalid@1.1.4:
resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==}
- check-error@1.0.3:
- resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==}
+ check-error@2.1.1:
+ resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
+ engines: {node: '>= 16'}
chokidar@3.6.0:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
@@ -1147,8 +1154,8 @@ packages:
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
- core-js-compat@3.37.1:
- resolution: {integrity: sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==}
+ core-js-compat@3.38.0:
+ resolution: {integrity: sha512-75LAicdLa4OJVwFxFbQR3NdnZjNgX6ILpVcVzcC4T2smerB5lELMrJQQQoWV6TiuC/vlaFqgU2tKQx9w5s0e0A==}
cross-spawn@7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
@@ -1192,8 +1199,8 @@ packages:
resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==}
engines: {node: '>=18'}
- dayjs@1.11.11:
- resolution: {integrity: sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==}
+ dayjs@1.11.12:
+ resolution: {integrity: sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg==}
de-indent@1.0.2:
resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
@@ -1206,8 +1213,8 @@ packages:
supports-color:
optional: true
- debug@4.3.5:
- resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==}
+ debug@4.3.6:
+ resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==}
engines: {node: '>=6.0'}
peerDependencies:
supports-color: '*'
@@ -1222,8 +1229,8 @@ packages:
resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==}
engines: {node: '>=0.10'}
- deep-eql@4.1.4:
- resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==}
+ deep-eql@5.0.2:
+ resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
engines: {node: '>=6'}
deep-is@0.1.4:
@@ -1233,10 +1240,6 @@ packages:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
- diff-sequences@29.6.3:
- resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
dir-glob@3.0.1:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'}
@@ -1266,8 +1269,11 @@ packages:
engines: {node: '>=14'}
hasBin: true
- electron-to-chromium@1.4.805:
- resolution: {integrity: sha512-8W4UJwX/w9T0QSzINJckTKG6CYpAUTqsaWcWIsdud3I1FYJcMgW9QqT1/4CBff/pP/TihWh13OmiyY8neto6vw==}
+ electron-to-chromium@1.5.3:
+ resolution: {integrity: sha512-QNdYSS5i8D9axWp/6XIezRObRHqaav/ur9z1VzCDUCH1XIFOr9WQk5xmgunhsTpjjgDy3oLxO/WMOVZlpUQrlA==}
+
+ electron-to-chromium@1.5.8:
+ resolution: {integrity: sha512-4Nx0gP2tPNBLTrFxBMHpkQbtn2hidPVr/+/FTtcCiBYTucqc70zRyVZiOLj17Ui3wTO7SQ1/N+hkHYzJjBzt6A==}
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
@@ -1278,8 +1284,8 @@ packages:
emojilib@2.4.0:
resolution: {integrity: sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==}
- enhanced-resolve@5.17.0:
- resolution: {integrity: sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==}
+ enhanced-resolve@5.17.1:
+ resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==}
engines: {node: '>=10.13.0'}
entities@4.5.0:
@@ -1289,6 +1295,9 @@ packages:
error-ex@1.3.2:
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
+ es-module-lexer@1.5.4:
+ resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==}
+
esbuild@0.21.5:
resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
engines: {node: '>=12'}
@@ -1317,11 +1326,13 @@ packages:
peerDependencies:
eslint: '>=6.0.0'
- eslint-config-flat-gitignore@0.1.5:
- resolution: {integrity: sha512-hEZLwuZjDBGDERA49c2q7vxc8sCGv8EdBp6PQYzGOMcHIgrfG9YOM6s/4jx24zhD+wnK9AI8mgN5RxSss5nClQ==}
+ eslint-config-flat-gitignore@0.3.0:
+ resolution: {integrity: sha512-0Ndxo4qGhcewjTzw52TK06Mc00aDtHNTdeeW2JfONgDcLkRO/n/BteMRzNVpLQYxdCC/dFEilfM9fjjpGIJ9Og==}
+ peerDependencies:
+ eslint: ^9.5.0
- eslint-flat-config-utils@0.2.5:
- resolution: {integrity: sha512-iO+yLZtC/LKgACerkpvsZ6NoRVB2sxT04mOpnNcEM1aTwKy+6TsT46PUvrML4y2uVBS6I67hRCd2JiKAPaL/Uw==}
+ eslint-flat-config-utils@0.3.1:
+ resolution: {integrity: sha512-eFT3EaoJN1hlN97xw4FIEX//h0TiFUobgl2l5uLkIwhVN9ahGq95Pbs+i1/B5UACA78LO3rco3JzuvxLdTUOPA==}
eslint-import-resolver-node@0.3.9:
resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
@@ -1331,8 +1342,8 @@ packages:
peerDependencies:
eslint: '*'
- eslint-plugin-antfu@2.3.3:
- resolution: {integrity: sha512-TAgYNuc20QyKw8NXtpzR3LeMTTv1qAJVKkjCVzjRSGiSR1EetEY7LRgQVhcgP/C1FnI87isQERAIkKvkYyLq0Q==}
+ eslint-plugin-antfu@2.5.0:
+ resolution: {integrity: sha512-YLIWE22/ERe6Jpqt6bJdvALw8SWvf4x2DQjvVpRvAv8LrdHbwWckkoueAf8oQFgSOLsL1R/axa+exjpubPp0fw==}
peerDependencies:
eslint: '*'
@@ -1341,26 +1352,20 @@ packages:
peerDependencies:
eslint: '*'
- eslint-plugin-es-x@7.7.0:
- resolution: {integrity: sha512-aP3qj8BwiEDPttxQkZdI221DLKq9sI/qHolE2YSQL1/9+xk7dTV+tB1Fz8/IaCA+lnLA1bDEnvaS2LKs0k2Uig==}
+ eslint-plugin-es-x@7.8.0:
+ resolution: {integrity: sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==}
engines: {node: ^14.18.0 || >=16.0.0}
peerDependencies:
eslint: '>=8'
- eslint-plugin-eslint-comments@3.2.0:
- resolution: {integrity: sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==}
- engines: {node: '>=6.5.0'}
+ eslint-plugin-import-x@4.2.1:
+ resolution: {integrity: sha512-WWi2GedccIJa0zXxx3WDnTgouGQTtdYK1nhXMwywbqqAgB0Ov+p1pYBsWh3VaB0bvBOwLse6OfVII7jZD9xo5Q==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
- eslint: '>=4.19.1'
+ eslint: ^8.57.0 || ^9.0.0
- eslint-plugin-import-x@0.5.1:
- resolution: {integrity: sha512-2JK8bbFOLes+gG6tgdnM8safCxMAj4u2wjX8X1BRFPfnY7Ct2hFYESoIcVwABX/DDcdpQFLGtKmzbNEWJZD9iQ==}
- engines: {node: '>=16'}
- peerDependencies:
- eslint: ^8.56.0 || ^9.0.0-0
-
- eslint-plugin-jsdoc@48.2.12:
- resolution: {integrity: sha512-sO9sKkJx5ovWoRk9hV0YiNzXQ4Z6j27CqE/po2E3wddZVuy9wvKPSTiIhpxMTrP/qURvKayJIDB2+o9kyCW1Fw==}
+ eslint-plugin-jsdoc@50.2.2:
+ resolution: {integrity: sha512-i0ZMWA199DG7sjxlzXn5AeYZxpRfMJjDPUl7lL9eJJX8TPRoIaxJU4ys/joP5faM5AXE1eqW/dslCj3uj4Nqpg==}
engines: {node: '>=18'}
peerDependencies:
eslint: ^7.0.0 || ^8.0.0 || ^9.0.0
@@ -1371,29 +1376,30 @@ packages:
peerDependencies:
eslint: '>=6.0.0'
- eslint-plugin-markdown@5.0.0:
- resolution: {integrity: sha512-kY2u9yDhzvfZ0kmRTsvgm3mTnvZgTSGIIPeHg3yesSx4R5CTCnITUjCPhzCD1MUhNcqHU5Tr6lzx+02EclVPbw==}
+ eslint-plugin-markdown@5.1.0:
+ resolution: {integrity: sha512-SJeyKko1K6GwI0AN6xeCDToXDkfKZfXcexA6B+O2Wr2btUS9GrC+YgwSyVli5DJnctUHjFXcQ2cqTaAmVoLi2A==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: '>=8'
- eslint-plugin-n@17.9.0:
- resolution: {integrity: sha512-CPSaXDXdrT4nsrOrO4mT4VB6FMUkoySRkHWuuJJHVqsIEjIeZgMY1H7AzSwPbDScikBmLN82KeM1u7ixV7PzGg==}
+ eslint-plugin-n@17.10.2:
+ resolution: {integrity: sha512-e+s4eAf5NtJaxPhTNu3qMO0Iz40WANS93w9LQgYcvuljgvDmWi/a3rh+OrNyMHeng6aOWGJO0rCg5lH4zi8yTw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: '>=8.23.0'
- eslint-plugin-no-only-tests@3.1.0:
- resolution: {integrity: sha512-Lf4YW/bL6Un1R6A76pRZyE1dl1vr31G/ev8UzIc/geCgFWyrKil8hVjYqWVKGB/UIGmb6Slzs9T0wNezdSVegw==}
+ eslint-plugin-no-only-tests@3.3.0:
+ resolution: {integrity: sha512-brcKcxGnISN2CcVhXJ/kEQlNa0MEfGRtwKtWA16SkqXHKitaKIMrfemJKLKX1YqDU5C/5JY3PvZXd5jEW04e0Q==}
engines: {node: '>=5.0.0'}
- eslint-plugin-perfectionist@2.11.0:
- resolution: {integrity: sha512-XrtBtiu5rbQv88gl+1e2RQud9te9luYNvKIgM9emttQ2zutHPzY/AQUucwxscDKV4qlTkvLTxjOFvxqeDpPorw==}
+ eslint-plugin-perfectionist@3.4.0:
+ resolution: {integrity: sha512-vXyd1sFg3H/7aKgBUie62bA6E0EN3Dh0LCD5r4vR/IYtTljxOnyckI1AV0Arw4eYjC/W9T1X04Pl2mdLsdWtMA==}
+ engines: {node: ^18.0.0 || >=20.0.0}
peerDependencies:
astro-eslint-parser: ^1.0.2
eslint: '>=8.0.0'
svelte: '>=3.0.0'
- svelte-eslint-parser: ^0.37.0
+ svelte-eslint-parser: ^0.41.0
vue-eslint-parser: '>=9.0.0'
peerDependenciesMeta:
astro-eslint-parser:
@@ -1405,9 +1411,9 @@ packages:
vue-eslint-parser:
optional: true
- eslint-plugin-promise@6.2.0:
- resolution: {integrity: sha512-QmAqwizauvnKOlifxyDj2ObfULpHQawlg/zQdgEixur9vl0CvZGv/LCJV2rtj3210QCoeGBzVMfMXqGAOr/4fA==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ eslint-plugin-promise@7.1.0:
+ resolution: {integrity: sha512-8trNmPxdAy3W620WKDpaS65NlM5yAumod6XeC4LOb+jxlkG4IVcp68c6dXY2ev+uT4U1PtG57YDV6EGAXN0GbQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^7.0.0 || ^8.0.0 || ^9.0.0
@@ -1417,50 +1423,36 @@ packages:
peerDependencies:
eslint: '>=8.44.0'
- eslint-plugin-toml@0.11.0:
- resolution: {integrity: sha512-sau+YvPU4fWTjB+qtBt3n8WS87aoDCs+BVbSUAemGaIsRNbvR9uEk+Tt892iLHTGvp/DPWYoCX4/8DoyAbB+sQ==}
+ eslint-plugin-toml@0.11.1:
+ resolution: {integrity: sha512-Y1WuMSzfZpeMIrmlP1nUh3kT8p96mThIq4NnHrYUhg10IKQgGfBZjAWnrg9fBqguiX4iFps/x/3Hb5TxBisfdw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: '>=6.0.0'
- eslint-plugin-unicorn@53.0.0:
- resolution: {integrity: sha512-kuTcNo9IwwUCfyHGwQFOK/HjJAYzbODHN3wP0PgqbW+jbXqpNWxNVpVhj2tO9SixBwuAdmal8rVcWKBxwFnGuw==}
+ eslint-plugin-unicorn@55.0.0:
+ resolution: {integrity: sha512-n3AKiVpY2/uDcGrS3+QsYDkjPfaOrNrsfQxU9nt5nitd9KuvVXrfAvgCO9DYPSfap+Gqjw9EOrXIsBp5tlHZjA==}
engines: {node: '>=18.18'}
peerDependencies:
eslint: '>=8.56.0'
- eslint-plugin-unused-imports@3.2.0:
- resolution: {integrity: sha512-6uXyn6xdINEpxE1MtDjxQsyXB37lfyO2yKGVVgtD7WEWQGORSOZjgrD6hBhvGv4/SO+TOlS+UnC6JppRqbuwGQ==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ eslint-plugin-unused-imports@4.1.3:
+ resolution: {integrity: sha512-lqrNZIZjFMUr7P06eoKtQLwyVRibvG7N+LtfKtObYGizAAGrcqLkc3tDx+iAik2z7q0j/XI3ihjupIqxhFabFA==}
peerDependencies:
- '@typescript-eslint/eslint-plugin': 6 - 7
- eslint: '8'
+ '@typescript-eslint/eslint-plugin': ^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0
+ eslint: ^9.0.0 || ^8.0.0
peerDependenciesMeta:
'@typescript-eslint/eslint-plugin':
optional: true
- eslint-plugin-vitest@0.5.4:
- resolution: {integrity: sha512-um+odCkccAHU53WdKAw39MY61+1x990uXjSPguUCq3VcEHdqJrOb8OTMrbYlY6f9jAKx7x98kLVlIe3RJeJqoQ==}
- engines: {node: ^18.0.0 || >= 20.0.0}
- peerDependencies:
- '@typescript-eslint/eslint-plugin': '*'
- eslint: ^8.57.0 || ^9.0.0
- vitest: '*'
- peerDependenciesMeta:
- '@typescript-eslint/eslint-plugin':
- optional: true
- vitest:
- optional: true
-
- eslint-plugin-vue-scoped-css@2.8.0:
- resolution: {integrity: sha512-JXb3Um4+AhuDGxSX6FAGCI0p811xF7W8L7yxC8wmAEZEI/teTjlpC09noqQZHXn53RZ/TGQJ8Onaq4teYLxBbg==}
+ eslint-plugin-vue-scoped-css@2.8.1:
+ resolution: {integrity: sha512-V6B+zZE60ykYvHTDzdhJ3xa4C83ntmGXqFsylc8l1jdVR9PSgod2+bGFNL7OwRKgZj82ij/o904xa04z1bfCRA==}
engines: {node: ^12.22 || ^14.17 || >=16}
peerDependencies:
eslint: '>=5.0.0'
vue-eslint-parser: '>=7.1.0'
- eslint-plugin-vue@9.26.0:
- resolution: {integrity: sha512-eTvlxXgd4ijE1cdur850G6KalZqk65k1JKoOI2d1kT3hr8sPD07j1q98FRFdNnpxBELGPWxZmInxeHGF/GxtqQ==}
+ eslint-plugin-vue@9.28.0:
+ resolution: {integrity: sha512-ShrihdjIhOTxs+MfWun6oJWuk+g/LAhN+CiuOl/jjkG3l0F2AuK5NMTaWqyvBgkFtpYmyks6P4603mLmhNJW8g==}
engines: {node: ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0
@@ -1477,16 +1469,12 @@ packages:
'@vue/compiler-sfc': ^3.3.0
eslint: ^8.50.0 || ^9.0.0
- eslint-rule-composer@0.3.0:
- resolution: {integrity: sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==}
- engines: {node: '>=4.0.0'}
-
eslint-scope@7.2.2:
resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
- eslint-scope@8.0.1:
- resolution: {integrity: sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==}
+ eslint-scope@8.0.2:
+ resolution: {integrity: sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
eslint-visitor-keys@3.4.3:
@@ -1497,10 +1485,15 @@ packages:
resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- eslint@9.5.0:
- resolution: {integrity: sha512-+NAOZFrW/jFTS3dASCGBxX1pkFD0/fsO+hfAkJ4TyYKwgsXZbqzrw+seCYFCcPCYXvnD67tAnglU7GQTz6kcVw==}
+ eslint@9.9.0:
+ resolution: {integrity: sha512-JfiKJrbx0506OEerjK2Y1QlldtBxkAlLxT5OEcRF8uaQ86noDe2k31Vw9rnSWv+MXZHj7OOUV/dA0AhdLFcyvA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
hasBin: true
+ peerDependencies:
+ jiti: '*'
+ peerDependenciesMeta:
+ jiti:
+ optional: true
espree@10.1.0:
resolution: {integrity: sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==}
@@ -1515,8 +1508,8 @@ packages:
engines: {node: '>=4'}
hasBin: true
- esquery@1.5.0:
- resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
+ esquery@1.6.0:
+ resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
engines: {node: '>=0.10'}
esrecurse@4.3.0:
@@ -1537,10 +1530,6 @@ packages:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
- execa@5.1.1:
- resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
- engines: {node: '>=10'}
-
execa@8.0.1:
resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
engines: {node: '>=16.17'}
@@ -1572,6 +1561,10 @@ packages:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'}
+ find-up-simple@1.0.0:
+ resolution: {integrity: sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==}
+ engines: {node: '>=18'}
+
find-up@4.1.0:
resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
engines: {node: '>=8'}
@@ -1580,10 +1573,6 @@ packages:
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
engines: {node: '>=10'}
- find-up@7.0.0:
- resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==}
- engines: {node: '>=18'}
-
flat-cache@4.0.1:
resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
engines: {node: '>=16'}
@@ -1625,16 +1614,12 @@ packages:
get-func-name@2.0.2:
resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
- get-stream@6.0.1:
- resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
- engines: {node: '>=10'}
-
get-stream@8.0.1:
resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==}
engines: {node: '>=16'}
- get-tsconfig@4.7.5:
- resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==}
+ get-tsconfig@4.7.6:
+ resolution: {integrity: sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==}
glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
@@ -1644,20 +1629,14 @@ packages:
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
engines: {node: '>=10.13.0'}
- glob@10.4.1:
- resolution: {integrity: sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==}
- engines: {node: '>=16 || 14 >=14.18'}
+ glob@10.4.5:
+ resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
hasBin: true
glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Glob versions prior to v9 are no longer supported
- glob@8.1.0:
- resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
- engines: {node: '>=12'}
- deprecated: Glob versions prior to v9 are no longer supported
-
globals@11.12.0:
resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
engines: {node: '>=4'}
@@ -1670,8 +1649,12 @@ packages:
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
engines: {node: '>=18'}
- globals@15.6.0:
- resolution: {integrity: sha512-UzcJi88Hw//CurUIRa9Jxb0vgOCcuD/MNjwmXp633cyaRKkCWACkoqHCtfZv43b1kqXGg/fpOa8bwgacCeXsVg==}
+ globals@15.8.0:
+ resolution: {integrity: sha512-VZAJ4cewHTExBWDHR6yptdIBlx9YSSZuwojj9Nt5mBRXQzrKakDsVKQ1J63sklLvzAJm0X5+RpO4i3Y2hcOnFw==}
+ engines: {node: '>=18'}
+
+ globals@15.9.0:
+ resolution: {integrity: sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA==}
engines: {node: '>=18'}
globby@11.1.0:
@@ -1711,14 +1694,10 @@ packages:
resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
engines: {node: '>= 14'}
- https-proxy-agent@7.0.4:
- resolution: {integrity: sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==}
+ https-proxy-agent@7.0.5:
+ resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==}
engines: {node: '>= 14'}
- human-signals@2.1.0:
- resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
- engines: {node: '>=10.17.0'}
-
human-signals@5.0.0:
resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
engines: {node: '>=16.17.0'}
@@ -1731,6 +1710,10 @@ packages:
resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==}
engines: {node: '>= 4'}
+ ignore@5.3.2:
+ resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
+ engines: {node: '>= 4'}
+
import-fresh@3.3.0:
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
engines: {node: '>=6'}
@@ -1770,8 +1753,9 @@ packages:
resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==}
engines: {node: '>=6'}
- is-core-module@2.13.1:
- resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==}
+ is-core-module@2.15.0:
+ resolution: {integrity: sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==}
+ engines: {node: '>= 0.4'}
is-decimal@1.0.4:
resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==}
@@ -1805,10 +1789,6 @@ packages:
is-potential-custom-element-name@1.0.1:
resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
- is-stream@2.0.1:
- resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
- engines: {node: '>=8'}
-
is-stream@3.0.0:
resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -1816,9 +1796,8 @@ packages:
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
- jackspeak@3.4.0:
- resolution: {integrity: sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==}
- engines: {node: '>=14'}
+ jackspeak@3.4.3:
+ resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
jiti@1.21.6:
resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==}
@@ -1839,9 +1818,6 @@ packages:
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
- js-tokens@9.0.0:
- resolution: {integrity: sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==}
-
js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
@@ -1850,8 +1826,12 @@ packages:
resolution: {integrity: sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==}
engines: {node: '>=12.0.0'}
- jsdom@24.1.0:
- resolution: {integrity: sha512-6gpM7pRXCwIOKxX47cgOyvyQDN/Eh0f1MeKySBV2xGdKtqJBLj8P25eY3EVCWo2mglDDzozR2r2MW4T+JiNUZA==}
+ jsdoc-type-pratt-parser@4.1.0:
+ resolution: {integrity: sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==}
+ engines: {node: '>=12.0.0'}
+
+ jsdom@25.0.0:
+ resolution: {integrity: sha512-OhoFVT59T7aEq75TVw9xxEfkXgacpqAhQaYgP9y/fDqWQCMB/b1H66RfmPm/MaeaAIU9nDwMOVTlPN51+ao6CQ==}
engines: {node: '>=18'}
peerDependencies:
canvas: ^2.11.2
@@ -1907,10 +1887,6 @@ packages:
lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
- local-pkg@0.4.3:
- resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==}
- engines: {node: '>=14'}
-
local-pkg@0.5.0:
resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==}
engines: {node: '>=14'}
@@ -1923,10 +1899,6 @@ packages:
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
engines: {node: '>=10'}
- locate-path@7.2.0:
- resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
-
lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
@@ -1936,18 +1908,17 @@ packages:
lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
- loupe@2.3.7:
- resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==}
+ loupe@3.1.1:
+ resolution: {integrity: sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==}
- lru-cache@10.2.2:
- resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==}
- engines: {node: 14 || >=16.14}
+ lru-cache@10.4.3:
+ resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
- magic-string@0.30.10:
- resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==}
+ magic-string@0.30.11:
+ resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==}
mdast-util-from-markdown@0.8.5:
resolution: {integrity: sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==}
@@ -1983,10 +1954,6 @@ packages:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
- mimic-fn@2.1.0:
- resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
- engines: {node: '>=6'}
-
mimic-fn@4.0.0:
resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
engines: {node: '>=12'}
@@ -1998,16 +1965,12 @@ packages:
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
- minimatch@5.1.6:
- resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
- engines: {node: '>=10'}
-
minimatch@9.0.1:
resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==}
engines: {node: '>=16 || 14 >=14.17'}
- minimatch@9.0.4:
- resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==}
+ minimatch@9.0.5:
+ resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
engines: {node: '>=16 || 14 >=14.17'}
minipass@7.1.2:
@@ -2041,8 +2004,8 @@ packages:
resolution: {integrity: sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==}
engines: {node: '>=18'}
- node-releases@2.0.14:
- resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
+ node-releases@2.0.18:
+ resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==}
nopt@7.2.1:
resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==}
@@ -2056,10 +2019,6 @@ packages:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
- npm-run-path@4.0.1:
- resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
- engines: {node: '>=8'}
-
npm-run-path@5.3.0:
resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -2067,16 +2026,12 @@ packages:
nth-check@2.1.1:
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
- nwsapi@2.2.10:
- resolution: {integrity: sha512-QK0sRs7MKv0tKe1+5uZIQk/C8XGza4DAnztJG8iD+TpJIORARrCxczA738awHrZoHeTjSSoHqao2teO0dC/gFQ==}
+ nwsapi@2.2.12:
+ resolution: {integrity: sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==}
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
- onetime@5.1.2:
- resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
- engines: {node: '>=6'}
-
onetime@6.0.0:
resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
engines: {node: '>=12'}
@@ -2093,14 +2048,6 @@ packages:
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
engines: {node: '>=10'}
- p-limit@4.0.0:
- resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
-
- p-limit@5.0.0:
- resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==}
- engines: {node: '>=18'}
-
p-locate@4.1.0:
resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
engines: {node: '>=8'}
@@ -2109,14 +2056,16 @@ packages:
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
engines: {node: '>=10'}
- p-locate@6.0.0:
- resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
-
p-try@2.2.0:
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
engines: {node: '>=6'}
+ package-json-from-dist@1.0.0:
+ resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==}
+
+ package-manager-detector@0.2.0:
+ resolution: {integrity: sha512-E385OSk9qDcXhcM9LNSe4sdhx8a9mAPrZ4sMLW+tmxl5ZuGtPUcdFu+MPP2jbgiWAZ6Pfe5soGFMd+0Db5Vrog==}
+
parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
@@ -2128,6 +2077,10 @@ packages:
resolution: {integrity: sha512-RmVuCHWsfu0QPNW+mraxh/xjQVw/lhUCUru8Zni3Ctq3AoMhpDTq0OVdKS6iesd6Kqb7viCV3isAL43dciOSog==}
engines: {node: '>=14'}
+ parse-imports@2.1.1:
+ resolution: {integrity: sha512-TDT4HqzUiTMO1wJRwg/t/hYk8Wdp3iF/ToMIlAoVQfL1Xs/sTxq1dKWSMjMbQmIarfWKymOyly40+zmPHXMqCA==}
+ engines: {node: '>= 18'}
+
parse-json@5.2.0:
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
engines: {node: '>=8'}
@@ -2142,10 +2095,6 @@ packages:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
- path-exists@5.0.0:
- resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
-
path-is-absolute@1.0.1:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
@@ -2172,12 +2121,16 @@ packages:
pathe@1.1.2:
resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
- pathval@1.1.1:
- resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==}
+ pathval@2.0.0:
+ resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==}
+ engines: {node: '>= 14.16'}
picocolors@1.0.1:
resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
+ picocolors@1.1.0:
+ resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==}
+
picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
@@ -2186,8 +2139,8 @@ packages:
resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
engines: {node: '>=12'}
- pinia@2.1.7:
- resolution: {integrity: sha512-+C2AHFtcFqjPih0zpYuvof37SFxMQ7OEG2zV9jRI12i9BOy3YQVAHwdKtyyc8pDcDyIc33WCIsZaCFWU7WWxGQ==}
+ pinia@2.2.1:
+ resolution: {integrity: sha512-ltEU3xwiz5ojVMizdP93AHi84Rtfz0+yKd8ud75hr9LVyWX2alxp7vLbY1kFm7MXFmHHr/9B08Xf8Jj6IHTEiQ==}
peerDependencies:
'@vue/composition-api': ^1.4.0
typescript: '>=4.4.4'
@@ -2198,8 +2151,8 @@ packages:
typescript:
optional: true
- pkg-types@1.1.1:
- resolution: {integrity: sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==}
+ pkg-types@1.1.3:
+ resolution: {integrity: sha512-+JrgthZG6m3ckicaOB74TwQ+tBWsFl3qVQg7mN8ulwSOElJ7gBhKzj2VkCPnZ4NlF6kEquYU+RIYNVAvzd54UA==}
pluralize@8.0.0:
resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
@@ -2217,31 +2170,35 @@ packages:
peerDependencies:
postcss: ^8.4.29
- postcss-selector-parser@6.1.0:
- resolution: {integrity: sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==}
+ postcss-selector-parser@6.1.1:
+ resolution: {integrity: sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==}
+ engines: {node: '>=4'}
+
+ postcss-selector-parser@6.1.2:
+ resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==}
engines: {node: '>=4'}
postcss-styl@0.12.3:
resolution: {integrity: sha512-8I7Cd8sxiEITIp32xBK4K/Aj1ukX6vuWnx8oY/oAH35NfQI4OZaY5nd68Yx8HeN5S49uhQ6DL0rNk0ZBu/TaLg==}
engines: {node: ^8.10.0 || ^10.13.0 || ^11.10.1 || >=12.13.0}
- postcss@8.4.38:
- resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==}
+ postcss@8.4.40:
+ resolution: {integrity: sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==}
+ engines: {node: ^10 || ^12 || >=14}
+
+ postcss@8.4.41:
+ resolution: {integrity: sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==}
engines: {node: ^10 || ^12 || >=14}
prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
- prettier@3.3.2:
- resolution: {integrity: sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==}
+ prettier@3.3.3:
+ resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==}
engines: {node: '>=14'}
hasBin: true
- pretty-format@29.7.0:
- resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
-
prismjs@1.29.0:
resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==}
engines: {node: '>=6'}
@@ -2262,9 +2219,6 @@ packages:
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
- react-is@18.3.1:
- resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
-
read-pkg-up@7.0.1:
resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==}
engines: {node: '>=8'}
@@ -2296,9 +2250,9 @@ packages:
resolution: {integrity: sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==}
hasBin: true
- replace-in-file@7.2.0:
- resolution: {integrity: sha512-CiLXVop3o8/h2Kd1PwKPPimmS9wUV0Ki6Fl8+1ITD35nB3Gl/PrW5IONpTE0AXk0z4v8WYcpEpdeZqMXvSnWpg==}
- engines: {node: '>=10'}
+ replace-in-file@8.1.0:
+ resolution: {integrity: sha512-ySYfKDH6uFVC4Wt6DcZ2UX0UMCqE7xhWGVqje/15WFVwHxnel1gdZjV8nOW9Nms6h/yQE2MWyeIToeqFLZkp4w==}
+ engines: {node: '>=18'}
hasBin: true
require-directory@2.1.1:
@@ -2323,8 +2277,8 @@ packages:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
- rollup@4.18.0:
- resolution: {integrity: sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==}
+ rollup@4.20.0:
+ resolution: {integrity: sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
@@ -2351,8 +2305,8 @@ packages:
resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==}
engines: {node: ^14.0.0 || >=16.0.0}
- semver@7.6.2:
- resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==}
+ semver@7.6.3:
+ resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==}
engines: {node: '>=10'}
hasBin: true
@@ -2367,13 +2321,14 @@ packages:
siginfo@2.0.0:
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
- signal-exit@3.0.7:
- resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
-
signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
+ simple-icons@13.5.0:
+ resolution: {integrity: sha512-6VrM4xSty8EesmQbjI++Lk8FkV+gl3Ve+DnTQVc7ovZryKpc9JZSuZA8NNc7lC3Mqbh0GLlX3WXdITZlDu7bSQ==}
+ engines: {node: '>=0.12.18'}
+
sisteransi@1.0.5:
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
@@ -2385,6 +2340,9 @@ packages:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}
+ slashes@3.0.12:
+ resolution: {integrity: sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==}
+
source-map-js@1.2.0:
resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
engines: {node: '>=0.10.0'}
@@ -2416,16 +2374,15 @@ packages:
spdx-license-ids@3.0.18:
resolution: {integrity: sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==}
+ stable-hash@0.0.4:
+ resolution: {integrity: sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==}
+
stackback@0.0.2:
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
std-env@3.7.0:
resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==}
- string-argv@0.3.2:
- resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==}
- engines: {node: '>=0.6.19'}
-
string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
@@ -2442,10 +2399,6 @@ packages:
resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
engines: {node: '>=12'}
- strip-final-newline@2.0.0:
- resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
- engines: {node: '>=6'}
-
strip-final-newline@3.0.0:
resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
engines: {node: '>=12'}
@@ -2458,9 +2411,6 @@ packages:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
- strip-literal@2.1.0:
- resolution: {integrity: sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==}
-
stylus@0.57.0:
resolution: {integrity: sha512-yOI6G8WYfr0q8v8rRvE91wbxFU+rJPo760Va4MF6K0I6BZjO4r+xSynkvyPBP9tV1CIEUeRsiidjIs2rzb1CnQ==}
hasBin: true
@@ -2489,8 +2439,8 @@ packages:
resolution: {integrity: sha512-Vhf+bUa//YSTYKseDiiEuQmhGCoIF3CVBhunm3r/DQnYiGT4JssmnKQc44BIyOZRK2pKjXXAgbhfmbeoC9CJpA==}
engines: {node: '>=12.20'}
- synckit@0.9.0:
- resolution: {integrity: sha512-7RnqIMq572L8PeEzKeBINYEJDDxpcH8JEgLwUqBd3TkofhFRbkq4QLR0u+36avGAhCRbk2nnmjcW9SE531hPDg==}
+ synckit@0.9.1:
+ resolution: {integrity: sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==}
engines: {node: ^14.18.0 || >=16.0.0}
tapable@2.2.1:
@@ -2500,18 +2450,25 @@ packages:
text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
- tinybench@2.8.0:
- resolution: {integrity: sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==}
+ tinybench@2.9.0:
+ resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
tinycolor2@1.6.0:
resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==}
- tinypool@0.8.4:
- resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==}
+ tinyexec@0.3.0:
+ resolution: {integrity: sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==}
+
+ tinypool@1.0.0:
+ resolution: {integrity: sha512-KIKExllK7jp3uvrNtvRBYBWBOAXSX8ZvoaD8T+7KB/QHIuoJW3Pmr60zucywjAlMb5TeXUkcs/MWeWLu0qvuAQ==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+
+ tinyrainbow@1.2.0:
+ resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==}
engines: {node: '>=14.0.0'}
- tinyspy@2.2.1:
- resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==}
+ tinyspy@3.0.0:
+ resolution: {integrity: sha512-q5nmENpTHgiPVd1cJDDc9cVoYN5x4vCvwT3FMilvKPKneCBZAxn2YWQjDF0UMcE9k0Cay1gBiDfTMU0g+mPMQA==}
engines: {node: '>=14.0.0'}
to-fast-properties@2.0.0:
@@ -2522,8 +2479,8 @@ packages:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
- toml-eslint-parser@0.9.3:
- resolution: {integrity: sha512-moYoCvkNUAPCxSW9jmHmRElhm4tVJpHL8ItC/+uYD0EpPSFXbck7yREz9tNdJVTSpHVod8+HoipcpbQ0oE6gsw==}
+ toml-eslint-parser@0.10.0:
+ resolution: {integrity: sha512-khrZo4buq4qVmsGzS5yQjKe/WsFvV8fGfOjDQN0q4iy9FjRfPWRgTFrU8u1R2iu/SfWLhY9WnCi4Jhdrcbtg+g==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
tough-cookie@4.1.4:
@@ -2547,10 +2504,6 @@ packages:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
- type-detect@4.0.8:
- resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
- engines: {node: '>=4'}
-
type-fest@0.20.2:
resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
engines: {node: '>=10'}
@@ -2563,23 +2516,13 @@ packages:
resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==}
engines: {node: '>=8'}
- typescript-eslint@7.13.1:
- resolution: {integrity: sha512-pvLEuRs8iS9s3Cnp/Wt//hpK8nKc8hVa3cLljHqzaJJQYP8oys8GUyIFqtlev+2lT/fqMPcyQko+HJ6iYK3nFA==}
- engines: {node: ^18.18.0 || >=20.0.0}
- peerDependencies:
- eslint: ^8.56.0
- typescript: '*'
- peerDependenciesMeta:
- typescript:
- optional: true
-
- typescript@5.4.5:
- resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==}
+ typescript@5.5.4:
+ resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==}
engines: {node: '>=14.17'}
hasBin: true
- ufo@1.5.3:
- resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==}
+ ufo@1.5.4:
+ resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==}
undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
@@ -2588,10 +2531,6 @@ packages:
resolution: {integrity: sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==}
engines: {node: '>=4'}
- unicorn-magic@0.1.0:
- resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==}
- engines: {node: '>=18'}
-
unist-util-stringify-position@2.0.3:
resolution: {integrity: sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==}
@@ -2599,45 +2538,12 @@ packages:
resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
engines: {node: '>= 4.0.0'}
- unplugin-icons@0.18.5:
- resolution: {integrity: sha512-KVNAohXbZ7tVcG1C3p6QaC7wU9Qrj7etv4XvsMMJAxr5LccQZ+Iuv5LOIv/7GtqXaGN1BuFCqRO1ErsHEgEXdQ==}
- peerDependencies:
- '@svgr/core': '>=7.0.0'
- '@svgx/core': ^1.0.1
- '@vue/compiler-sfc': ^3.0.2 || ^2.7.0
- vue-template-compiler: ^2.6.12
- vue-template-es2015-compiler: ^1.9.0
- peerDependenciesMeta:
- '@svgr/core':
- optional: true
- '@svgx/core':
- optional: true
- '@vue/compiler-sfc':
- optional: true
- vue-template-compiler:
- optional: true
- vue-template-es2015-compiler:
- optional: true
-
- unplugin-vue-components@0.26.0:
- resolution: {integrity: sha512-s7IdPDlnOvPamjunVxw8kNgKNK8A5KM1YpK5j/p97jEKTjlPNrA0nZBiSfAKKlK1gWZuyWXlKL5dk3EDw874LQ==}
- engines: {node: '>=14'}
- peerDependencies:
- '@babel/parser': ^7.15.8
- '@nuxt/kit': ^3.2.2
- vue: 2 || 3
- peerDependenciesMeta:
- '@babel/parser':
- optional: true
- '@nuxt/kit':
- optional: true
-
- unplugin@1.10.1:
- resolution: {integrity: sha512-d6Mhq8RJeGA8UfKCu54Um4lFA0eSaRa3XxdAJg8tIdxbu1ubW0hBCZUL7yI2uGyYCRndvbK8FLHzqy2XKfeMsg==}
+ unplugin@1.12.0:
+ resolution: {integrity: sha512-KeczzHl2sATPQUx1gzo+EnUkmN4VmGBYRRVOZSGvGITE9rGHRDGqft6ONceP3vgXcyJ2XjX5axG5jMWUwNCYLw==}
engines: {node: '>=14.0.0'}
- update-browserslist-db@1.0.16:
- resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==}
+ update-browserslist-db@1.1.0:
+ resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==}
hasBin: true
peerDependencies:
browserslist: '>= 4.21.0'
@@ -2654,8 +2560,8 @@ packages:
validate-npm-package-license@3.0.4:
resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
- vite-node@1.6.0:
- resolution: {integrity: sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==}
+ vite-node@2.0.5:
+ resolution: {integrity: sha512-LdsW4pxj0Ot69FAoXZ1yTnA9bjGohr2yNBU7QKRxpz8ITSkhuDl6h3zS/tvgz4qrNjeRnvrWeXQ8ZF7Um4W00Q==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
@@ -2673,8 +2579,8 @@ packages:
peerDependencies:
vue: '>=3.2.13'
- vite@5.3.1:
- resolution: {integrity: sha512-XBmSKRLXLxiaPYamLv3/hnP/KXDai1NDexN0FpkTaZXTfycHvkRHoenpgl/fvuK/kPbB6xAgoyiryAhQNxYmAQ==}
+ vite@5.4.1:
+ resolution: {integrity: sha512-1oE6yuNXssjrZdblI9AfBbHCC41nnyoVoEZxQnID6yvQZAFBzxxkqoFLtHUMkYunL8hwOLEjgTuxpkRxvba3kA==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
@@ -2682,6 +2588,7 @@ packages:
less: '*'
lightningcss: ^1.21.0
sass: '*'
+ sass-embedded: '*'
stylus: '*'
sugarss: '*'
terser: ^5.4.0
@@ -2694,6 +2601,8 @@ packages:
optional: true
sass:
optional: true
+ sass-embedded:
+ optional: true
stylus:
optional: true
sugarss:
@@ -2701,15 +2610,15 @@ packages:
terser:
optional: true
- vitest@1.6.0:
- resolution: {integrity: sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==}
+ vitest@2.0.5:
+ resolution: {integrity: sha512-8GUxONfauuIdeSl5f9GTgVEpg5BTOlplET4WEDaeY2QBiN8wSm68vxN/tb5z405OwppfoCavnwXafiaYBC/xOA==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
'@edge-runtime/vm': '*'
'@types/node': ^18.0.0 || >=20.0.0
- '@vitest/browser': 1.6.0
- '@vitest/ui': 1.6.0
+ '@vitest/browser': 2.0.5
+ '@vitest/ui': 2.0.5
happy-dom: '*'
jsdom: '*'
peerDependenciesMeta:
@@ -2729,11 +2638,11 @@ packages:
vscode-uri@3.0.8:
resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==}
- vue-component-type-helpers@2.0.21:
- resolution: {integrity: sha512-3NaicyZ7N4B6cft4bfb7dOnPbE9CjLcx+6wZWAg5zwszfO4qXRh+U52dN5r5ZZfc6iMaxKCEcoH9CmxxoFZHLg==}
+ vue-component-type-helpers@2.0.29:
+ resolution: {integrity: sha512-58i+ZhUAUpwQ+9h5Hck0D+jr1qbYl4voRt5KffBx8qzELViQ4XdT/Tuo+mzq8u63teAG8K0lLaOiL5ofqW38rg==}
- vue-demi@0.14.8:
- resolution: {integrity: sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==}
+ vue-demi@0.14.10:
+ resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==}
engines: {node: '>=12'}
hasBin: true
peerDependencies:
@@ -2755,22 +2664,19 @@ packages:
peerDependencies:
vue: ^3.0.0
- vue-router@4.3.3:
- resolution: {integrity: sha512-8Q+u+WP4N2SXY38FDcF2H1dUEbYVHVPtPCPZj/GTZx8RCbiB8AtJP9+YIxn4Vs0svMTNQcLIzka4GH7Utkx9xQ==}
+ vue-router@4.4.3:
+ resolution: {integrity: sha512-sv6wmNKx2j3aqJQDMxLFzs/u/mjA9Z5LCgy6BE0f7yFWMjrPLnS/sPNn8ARY/FXw6byV18EFutn5lTO6+UsV5A==}
peerDependencies:
vue: ^3.2.0
- vue-template-compiler@2.7.16:
- resolution: {integrity: sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==}
-
- vue-tsc@2.0.21:
- resolution: {integrity: sha512-E6x1p1HaHES6Doy8pqtm7kQern79zRtIewkf9fiv7Y43Zo4AFDS5hKi+iHi2RwEhqRmuiwliB1LCEFEGwvxQnw==}
+ vue-tsc@2.0.29:
+ resolution: {integrity: sha512-MHhsfyxO3mYShZCGYNziSbc63x7cQ5g9kvijV7dRe1TTXBRLxXyL0FnXWpUF1xII2mJ86mwYpYsUmMwkmerq7Q==}
hasBin: true
peerDependencies:
- typescript: '*'
+ typescript: '>=5.0.0'
- vue@3.4.29:
- resolution: {integrity: sha512-8QUYfRcYzNlYuzKPfge1UWC6nF9ym0lx7mpGVPJYNhddxEf3DD0+kU07NTL0sXuiT2HuJuKr/iEO8WvXvT0RSQ==}
+ vue@3.4.38:
+ resolution: {integrity: sha512-f0ZgN+mZ5KFgVv9wz0f4OgVKukoXtS3nwET4c2vLBGQR50aI8G0cqbFtLlX9Yiyg3LFGBitruPHt2PxwTduJEw==}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
@@ -2809,8 +2715,8 @@ packages:
engines: {node: '>= 8'}
hasBin: true
- why-is-node-running@2.2.2:
- resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==}
+ why-is-node-running@2.3.0:
+ resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
engines: {node: '>=8'}
hasBin: true
@@ -2834,8 +2740,8 @@ packages:
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
- ws@8.17.1:
- resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==}
+ ws@8.18.0:
+ resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
@@ -2868,8 +2774,8 @@ packages:
resolution: {integrity: sha512-4wZWvE398hCP7O8n3nXKu/vdq1HcH01ixYlCREaJL5NUMwQ0g3MaGFUBNSlmBtKmhbtVG/Cm6lyYmSVTEVil8A==}
engines: {node: ^14.17.0 || >=16.0.0}
- yaml@2.4.5:
- resolution: {integrity: sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==}
+ yaml@2.5.0:
+ resolution: {integrity: sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==}
engines: {node: '>= 14'}
hasBin: true
@@ -2885,10 +2791,6 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
- yocto-queue@1.0.0:
- resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==}
- engines: {node: '>=12.20'}
-
snapshots:
'@ampproject/remapping@2.3.0':
@@ -2896,156 +2798,135 @@ snapshots:
'@jridgewell/gen-mapping': 0.3.5
'@jridgewell/trace-mapping': 0.3.25
- '@antfu/eslint-config@2.21.1(@vue/compiler-sfc@3.4.29)(eslint@9.5.0)(typescript@5.4.5)(vitest@1.6.0(@types/node@20.14.5)(jsdom@24.1.0)(stylus@0.57.0))':
+ '@antfu/eslint-config@3.3.2(@typescript-eslint/utils@8.4.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4))(@vue/compiler-sfc@3.4.38)(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)(vitest@2.0.5(@types/node@20.14.15)(jsdom@25.0.0)(stylus@0.57.0))':
dependencies:
- '@antfu/install-pkg': 0.3.3
+ '@antfu/install-pkg': 0.4.1
'@clack/prompts': 0.7.0
- '@stylistic/eslint-plugin': 2.2.1(eslint@9.5.0)(typescript@5.4.5)
- '@typescript-eslint/eslint-plugin': 7.13.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint@9.5.0)(typescript@5.4.5)
- '@typescript-eslint/parser': 7.13.1(eslint@9.5.0)(typescript@5.4.5)
- eslint: 9.5.0
- eslint-config-flat-gitignore: 0.1.5
- eslint-flat-config-utils: 0.2.5
- eslint-merge-processors: 0.1.0(eslint@9.5.0)
- eslint-plugin-antfu: 2.3.3(eslint@9.5.0)
- eslint-plugin-command: 0.2.3(eslint@9.5.0)
- eslint-plugin-eslint-comments: 3.2.0(eslint@9.5.0)
- eslint-plugin-import-x: 0.5.1(eslint@9.5.0)(typescript@5.4.5)
- eslint-plugin-jsdoc: 48.2.12(eslint@9.5.0)
- eslint-plugin-jsonc: 2.16.0(eslint@9.5.0)
- eslint-plugin-markdown: 5.0.0(eslint@9.5.0)
- eslint-plugin-n: 17.9.0(eslint@9.5.0)
- eslint-plugin-no-only-tests: 3.1.0
- eslint-plugin-perfectionist: 2.11.0(eslint@9.5.0)(typescript@5.4.5)(vue-eslint-parser@9.4.3(eslint@9.5.0))
- eslint-plugin-regexp: 2.6.0(eslint@9.5.0)
- eslint-plugin-toml: 0.11.0(eslint@9.5.0)
- eslint-plugin-unicorn: 53.0.0(eslint@9.5.0)
- eslint-plugin-unused-imports: 3.2.0(@typescript-eslint/eslint-plugin@7.13.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint@9.5.0)(typescript@5.4.5))(eslint@9.5.0)
- eslint-plugin-vitest: 0.5.4(@typescript-eslint/eslint-plugin@7.13.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint@9.5.0)(typescript@5.4.5))(eslint@9.5.0)(typescript@5.4.5)(vitest@1.6.0(@types/node@20.14.5)(jsdom@24.1.0)(stylus@0.57.0))
- eslint-plugin-vue: 9.26.0(eslint@9.5.0)
- eslint-plugin-yml: 1.14.0(eslint@9.5.0)
- eslint-processor-vue-blocks: 0.1.2(@vue/compiler-sfc@3.4.29)(eslint@9.5.0)
- globals: 15.6.0
+ '@eslint-community/eslint-plugin-eslint-comments': 4.4.0(eslint@9.9.0(jiti@1.21.6))
+ '@stylistic/eslint-plugin': 2.7.2(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)
+ '@typescript-eslint/eslint-plugin': 8.4.0(@typescript-eslint/parser@8.4.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4))(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)
+ '@typescript-eslint/parser': 8.4.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)
+ '@vitest/eslint-plugin': 1.1.0(@typescript-eslint/utils@8.4.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4))(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)(vitest@2.0.5(@types/node@20.14.15)(jsdom@25.0.0)(stylus@0.57.0))
+ eslint: 9.9.0(jiti@1.21.6)
+ eslint-config-flat-gitignore: 0.3.0(eslint@9.9.0(jiti@1.21.6))
+ eslint-flat-config-utils: 0.3.1
+ eslint-merge-processors: 0.1.0(eslint@9.9.0(jiti@1.21.6))
+ eslint-plugin-antfu: 2.5.0(eslint@9.9.0(jiti@1.21.6))
+ eslint-plugin-command: 0.2.3(eslint@9.9.0(jiti@1.21.6))
+ eslint-plugin-import-x: 4.2.1(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)
+ eslint-plugin-jsdoc: 50.2.2(eslint@9.9.0(jiti@1.21.6))
+ eslint-plugin-jsonc: 2.16.0(eslint@9.9.0(jiti@1.21.6))
+ eslint-plugin-markdown: 5.1.0(eslint@9.9.0(jiti@1.21.6))
+ eslint-plugin-n: 17.10.2(eslint@9.9.0(jiti@1.21.6))
+ eslint-plugin-no-only-tests: 3.3.0
+ eslint-plugin-perfectionist: 3.4.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)(vue-eslint-parser@9.4.3(eslint@9.9.0(jiti@1.21.6)))
+ eslint-plugin-regexp: 2.6.0(eslint@9.9.0(jiti@1.21.6))
+ eslint-plugin-toml: 0.11.1(eslint@9.9.0(jiti@1.21.6))
+ eslint-plugin-unicorn: 55.0.0(eslint@9.9.0(jiti@1.21.6))
+ eslint-plugin-unused-imports: 4.1.3(@typescript-eslint/eslint-plugin@8.4.0(@typescript-eslint/parser@8.4.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4))(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4))(eslint@9.9.0(jiti@1.21.6))
+ eslint-plugin-vue: 9.28.0(eslint@9.9.0(jiti@1.21.6))
+ eslint-plugin-yml: 1.14.0(eslint@9.9.0(jiti@1.21.6))
+ eslint-processor-vue-blocks: 0.1.2(@vue/compiler-sfc@3.4.38)(eslint@9.9.0(jiti@1.21.6))
+ globals: 15.9.0
jsonc-eslint-parser: 2.4.0
local-pkg: 0.5.0
parse-gitignore: 2.0.0
- picocolors: 1.0.1
- toml-eslint-parser: 0.9.3
- vue-eslint-parser: 9.4.3(eslint@9.5.0)
+ picocolors: 1.1.0
+ toml-eslint-parser: 0.10.0
+ vue-eslint-parser: 9.4.3(eslint@9.9.0(jiti@1.21.6))
yaml-eslint-parser: 1.2.3
yargs: 17.7.2
transitivePeerDependencies:
+ - '@typescript-eslint/utils'
- '@vue/compiler-sfc'
- supports-color
- svelte
- typescript
- vitest
- '@antfu/install-pkg@0.1.1':
+ '@antfu/install-pkg@0.4.1':
dependencies:
- execa: 5.1.1
- find-up: 5.0.0
+ package-manager-detector: 0.2.0
+ tinyexec: 0.3.0
- '@antfu/install-pkg@0.3.3':
- dependencies:
- '@jsdevtools/ez-spawn': 3.0.4
-
- '@antfu/utils@0.7.8': {}
+ '@antfu/utils@0.7.10': {}
'@babel/code-frame@7.24.7':
dependencies:
'@babel/highlight': 7.24.7
picocolors: 1.0.1
- '@babel/compat-data@7.24.7': {}
+ '@babel/compat-data@7.25.2': {}
- '@babel/core@7.24.7':
+ '@babel/core@7.25.2':
dependencies:
'@ampproject/remapping': 2.3.0
'@babel/code-frame': 7.24.7
- '@babel/generator': 7.24.7
- '@babel/helper-compilation-targets': 7.24.7
- '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7)
- '@babel/helpers': 7.24.7
- '@babel/parser': 7.24.7
- '@babel/template': 7.24.7
- '@babel/traverse': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/generator': 7.25.0
+ '@babel/helper-compilation-targets': 7.25.2
+ '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2)
+ '@babel/helpers': 7.25.0
+ '@babel/parser': 7.25.0
+ '@babel/template': 7.25.0
+ '@babel/traverse': 7.25.2
+ '@babel/types': 7.25.2
convert-source-map: 2.0.0
- debug: 4.3.5
+ debug: 4.3.6
gensync: 1.0.0-beta.2
json5: 2.2.3
- semver: 7.6.2
+ semver: 7.6.3
transitivePeerDependencies:
- supports-color
- '@babel/generator@7.24.7':
+ '@babel/generator@7.25.0':
dependencies:
- '@babel/types': 7.24.7
+ '@babel/types': 7.25.2
'@jridgewell/gen-mapping': 0.3.5
'@jridgewell/trace-mapping': 0.3.25
jsesc: 2.5.2
- '@babel/helper-compilation-targets@7.24.7':
+ '@babel/helper-compilation-targets@7.25.2':
dependencies:
- '@babel/compat-data': 7.24.7
- '@babel/helper-validator-option': 7.24.7
- browserslist: 4.23.1
+ '@babel/compat-data': 7.25.2
+ '@babel/helper-validator-option': 7.24.8
+ browserslist: 4.23.2
lru-cache: 5.1.1
- semver: 7.6.2
-
- '@babel/helper-environment-visitor@7.24.7':
- dependencies:
- '@babel/types': 7.24.7
-
- '@babel/helper-function-name@7.24.7':
- dependencies:
- '@babel/template': 7.24.7
- '@babel/types': 7.24.7
-
- '@babel/helper-hoist-variables@7.24.7':
- dependencies:
- '@babel/types': 7.24.7
+ semver: 7.6.3
'@babel/helper-module-imports@7.24.7':
dependencies:
- '@babel/traverse': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/traverse': 7.25.2
+ '@babel/types': 7.25.2
transitivePeerDependencies:
- supports-color
- '@babel/helper-module-transforms@7.24.7(@babel/core@7.24.7)':
+ '@babel/helper-module-transforms@7.25.2(@babel/core@7.25.2)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/helper-environment-visitor': 7.24.7
+ '@babel/core': 7.25.2
'@babel/helper-module-imports': 7.24.7
'@babel/helper-simple-access': 7.24.7
- '@babel/helper-split-export-declaration': 7.24.7
'@babel/helper-validator-identifier': 7.24.7
+ '@babel/traverse': 7.25.2
transitivePeerDependencies:
- supports-color
'@babel/helper-simple-access@7.24.7':
dependencies:
- '@babel/traverse': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/traverse': 7.25.2
+ '@babel/types': 7.25.2
transitivePeerDependencies:
- supports-color
- '@babel/helper-split-export-declaration@7.24.7':
- dependencies:
- '@babel/types': 7.24.7
-
- '@babel/helper-string-parser@7.24.7': {}
+ '@babel/helper-string-parser@7.24.8': {}
'@babel/helper-validator-identifier@7.24.7': {}
- '@babel/helper-validator-option@7.24.7': {}
+ '@babel/helper-validator-option@7.24.8': {}
- '@babel/helpers@7.24.7':
+ '@babel/helpers@7.25.0':
dependencies:
- '@babel/template': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/template': 7.25.0
+ '@babel/types': 7.25.2
'@babel/highlight@7.24.7':
dependencies:
@@ -3054,61 +2935,68 @@ snapshots:
js-tokens: 4.0.0
picocolors: 1.0.1
- '@babel/parser@7.24.7':
+ '@babel/parser@7.25.0':
dependencies:
- '@babel/types': 7.24.7
+ '@babel/types': 7.25.2
- '@babel/runtime@7.24.7':
+ '@babel/parser@7.25.3':
+ dependencies:
+ '@babel/types': 7.25.2
+
+ '@babel/runtime@7.25.0':
dependencies:
regenerator-runtime: 0.14.1
- '@babel/template@7.24.7':
+ '@babel/template@7.25.0':
dependencies:
'@babel/code-frame': 7.24.7
- '@babel/parser': 7.24.7
- '@babel/types': 7.24.7
+ '@babel/parser': 7.25.0
+ '@babel/types': 7.25.2
- '@babel/traverse@7.24.7':
+ '@babel/traverse@7.25.2':
dependencies:
'@babel/code-frame': 7.24.7
- '@babel/generator': 7.24.7
- '@babel/helper-environment-visitor': 7.24.7
- '@babel/helper-function-name': 7.24.7
- '@babel/helper-hoist-variables': 7.24.7
- '@babel/helper-split-export-declaration': 7.24.7
- '@babel/parser': 7.24.7
- '@babel/types': 7.24.7
- debug: 4.3.5
+ '@babel/generator': 7.25.0
+ '@babel/parser': 7.25.0
+ '@babel/template': 7.25.0
+ '@babel/types': 7.25.2
+ debug: 4.3.6
globals: 11.12.0
transitivePeerDependencies:
- supports-color
- '@babel/types@7.24.7':
+ '@babel/types@7.25.2':
dependencies:
- '@babel/helper-string-parser': 7.24.7
+ '@babel/helper-string-parser': 7.24.8
'@babel/helper-validator-identifier': 7.24.7
to-fast-properties: 2.0.0
'@clack/core@0.3.4':
dependencies:
- picocolors: 1.0.1
+ picocolors: 1.1.0
sisteransi: 1.0.5
'@clack/prompts@0.7.0':
dependencies:
'@clack/core': 0.3.4
- picocolors: 1.0.1
+ picocolors: 1.1.0
sisteransi: 1.0.5
'@es-joy/jsdoccomment@0.43.1':
dependencies:
- '@types/eslint': 8.56.10
+ '@types/eslint': 8.56.11
'@types/estree': 1.0.5
- '@typescript-eslint/types': 7.13.1
+ '@typescript-eslint/types': 7.18.0
comment-parser: 1.4.1
- esquery: 1.5.0
+ esquery: 1.6.0
jsdoc-type-pratt-parser: 4.0.0
+ '@es-joy/jsdoccomment@0.48.0':
+ dependencies:
+ comment-parser: 1.4.1
+ esquery: 1.6.0
+ jsdoc-type-pratt-parser: 4.1.0
+
'@esbuild/aix-ppc64@0.21.5':
optional: true
@@ -3178,17 +3066,25 @@ snapshots:
'@esbuild/win32-x64@0.21.5':
optional: true
- '@eslint-community/eslint-utils@4.4.0(eslint@9.5.0)':
+ '@eslint-community/eslint-plugin-eslint-comments@4.4.0(eslint@9.9.0(jiti@1.21.6))':
dependencies:
- eslint: 9.5.0
+ escape-string-regexp: 4.0.0
+ eslint: 9.9.0(jiti@1.21.6)
+ ignore: 5.3.2
+
+ '@eslint-community/eslint-utils@4.4.0(eslint@9.9.0(jiti@1.21.6))':
+ dependencies:
+ eslint: 9.9.0(jiti@1.21.6)
eslint-visitor-keys: 3.4.3
- '@eslint-community/regexpp@4.10.1': {}
+ '@eslint-community/regexpp@4.11.0': {}
- '@eslint/config-array@0.16.0':
+ '@eslint/compat@1.1.1': {}
+
+ '@eslint/config-array@0.17.1':
dependencies:
'@eslint/object-schema': 2.1.4
- debug: 4.3.5
+ debug: 4.3.6
minimatch: 3.1.2
transitivePeerDependencies:
- supports-color
@@ -3196,10 +3092,10 @@ snapshots:
'@eslint/eslintrc@3.1.0':
dependencies:
ajv: 6.12.6
- debug: 4.3.5
+ debug: 4.3.6
espree: 10.1.0
globals: 14.0.0
- ignore: 5.3.1
+ ignore: 5.3.2
import-fresh: 3.3.0
js-yaml: 4.1.0
minimatch: 3.1.2
@@ -3207,7 +3103,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@eslint/js@9.5.0': {}
+ '@eslint/js@9.9.0': {}
'@eslint/object-schema@2.1.4': {}
@@ -3215,44 +3111,25 @@ snapshots:
'@humanwhocodes/retry@0.3.0': {}
- '@ianvs/prettier-plugin-sort-imports@4.2.1(@vue/compiler-sfc@3.4.29)(prettier@3.3.2)':
+ '@ianvs/prettier-plugin-sort-imports@4.3.1(@vue/compiler-sfc@3.4.38)(prettier@3.3.3)':
dependencies:
- '@babel/core': 7.24.7
- '@babel/generator': 7.24.7
- '@babel/parser': 7.24.7
- '@babel/traverse': 7.24.7
- '@babel/types': 7.24.7
- prettier: 3.3.2
- semver: 7.6.2
+ '@babel/core': 7.25.2
+ '@babel/generator': 7.25.0
+ '@babel/parser': 7.25.0
+ '@babel/traverse': 7.25.2
+ '@babel/types': 7.25.2
+ prettier: 3.3.3
+ semver: 7.6.3
optionalDependencies:
- '@vue/compiler-sfc': 3.4.29
+ '@vue/compiler-sfc': 3.4.38
transitivePeerDependencies:
- supports-color
- '@iconify/json@2.2.220':
- dependencies:
- '@iconify/types': 2.0.0
- pathe: 1.1.2
-
- '@iconify/types@2.0.0': {}
-
- '@iconify/utils@2.1.24':
- dependencies:
- '@antfu/install-pkg': 0.1.1
- '@antfu/utils': 0.7.8
- '@iconify/types': 2.0.0
- debug: 4.3.5
- kolorist: 1.8.0
- local-pkg: 0.5.0
- mlly: 1.7.1
- transitivePeerDependencies:
- - supports-color
-
- '@intlify/bundle-utils@8.0.0(vue-i18n@9.13.1(vue@3.4.29(typescript@5.4.5)))':
+ '@intlify/bundle-utils@8.0.0(vue-i18n@9.13.1(vue@3.4.38(typescript@5.5.4)))':
dependencies:
'@intlify/message-compiler': 9.13.1
'@intlify/shared': 9.13.1
- acorn: 8.12.0
+ acorn: 8.12.1
escodegen: 2.1.0
estree-walker: 2.0.2
jsonc-eslint-parser: 2.4.0
@@ -3260,23 +3137,23 @@ snapshots:
source-map-js: 1.2.0
yaml-eslint-parser: 1.2.3
optionalDependencies:
- vue-i18n: 9.13.1(vue@3.4.29(typescript@5.4.5))
+ vue-i18n: 9.13.1(vue@3.4.38(typescript@5.5.4))
'@intlify/core-base@9.13.1':
dependencies:
'@intlify/message-compiler': 9.13.1
'@intlify/shared': 9.13.1
- '@intlify/eslint-plugin-vue-i18n@3.0.0-next.13(eslint@9.5.0)':
+ '@intlify/eslint-plugin-vue-i18n@3.0.0(eslint@9.9.0(jiti@1.21.6))':
dependencies:
'@eslint/eslintrc': 3.1.0
'@intlify/core-base': 9.13.1
'@intlify/message-compiler': 9.13.1
- debug: 4.3.5
- eslint: 9.5.0
- eslint-compat-utils: 0.5.1(eslint@9.5.0)
- glob: 10.4.1
- globals: 15.6.0
+ debug: 4.3.6
+ eslint: 9.9.0(jiti@1.21.6)
+ eslint-compat-utils: 0.5.1(eslint@9.9.0(jiti@1.21.6))
+ glob: 10.4.5
+ globals: 15.8.0
ignore: 5.3.1
import-fresh: 3.3.0
is-language-code: 3.1.0
@@ -3285,9 +3162,9 @@ snapshots:
jsonc-eslint-parser: 2.4.0
lodash: 4.17.21
parse5: 7.1.2
- semver: 7.6.2
- synckit: 0.9.0
- vue-eslint-parser: 9.4.3(eslint@9.5.0)
+ semver: 7.6.3
+ synckit: 0.9.1
+ vue-eslint-parser: 9.4.3(eslint@9.9.0(jiti@1.21.6))
yaml-eslint-parser: 1.2.3
transitivePeerDependencies:
- supports-color
@@ -3299,22 +3176,22 @@ snapshots:
'@intlify/shared@9.13.1': {}
- '@intlify/unplugin-vue-i18n@4.0.0(rollup@4.18.0)(vue-i18n@9.13.1(vue@3.4.29(typescript@5.4.5)))':
+ '@intlify/unplugin-vue-i18n@4.0.0(rollup@4.20.0)(vue-i18n@9.13.1(vue@3.4.38(typescript@5.5.4)))':
dependencies:
- '@intlify/bundle-utils': 8.0.0(vue-i18n@9.13.1(vue@3.4.29(typescript@5.4.5)))
+ '@intlify/bundle-utils': 8.0.0(vue-i18n@9.13.1(vue@3.4.38(typescript@5.5.4)))
'@intlify/shared': 9.13.1
- '@rollup/pluginutils': 5.1.0(rollup@4.18.0)
- '@vue/compiler-sfc': 3.4.29
- debug: 4.3.5
+ '@rollup/pluginutils': 5.1.0(rollup@4.20.0)
+ '@vue/compiler-sfc': 3.4.38
+ debug: 4.3.6
fast-glob: 3.3.2
js-yaml: 4.1.0
json5: 2.2.3
pathe: 1.1.2
picocolors: 1.0.1
source-map-js: 1.2.0
- unplugin: 1.10.1
+ unplugin: 1.12.0
optionalDependencies:
- vue-i18n: 9.13.1(vue@3.4.29(typescript@5.4.5))
+ vue-i18n: 9.13.1(vue@3.4.38(typescript@5.5.4))
transitivePeerDependencies:
- rollup
- supports-color
@@ -3328,37 +3205,28 @@ snapshots:
wrap-ansi: 8.1.0
wrap-ansi-cjs: wrap-ansi@7.0.0
- '@jest/schemas@29.6.3':
- dependencies:
- '@sinclair/typebox': 0.27.8
-
'@jridgewell/gen-mapping@0.3.5':
dependencies:
'@jridgewell/set-array': 1.2.1
- '@jridgewell/sourcemap-codec': 1.4.15
+ '@jridgewell/sourcemap-codec': 1.5.0
'@jridgewell/trace-mapping': 0.3.25
'@jridgewell/resolve-uri@3.1.2': {}
'@jridgewell/set-array@1.2.1': {}
- '@jridgewell/sourcemap-codec@1.4.15': {}
+ '@jridgewell/sourcemap-codec@1.5.0': {}
'@jridgewell/trace-mapping@0.3.25':
dependencies:
'@jridgewell/resolve-uri': 3.1.2
- '@jridgewell/sourcemap-codec': 1.4.15
+ '@jridgewell/sourcemap-codec': 1.5.0
- '@jsdevtools/ez-spawn@3.0.4':
+ '@kyvg/vue3-notification@3.2.1(vue@3.4.38(typescript@5.5.4))':
dependencies:
- call-me-maybe: 1.0.2
- cross-spawn: 7.0.3
- string-argv: 0.3.2
- type-detect: 4.0.8
+ vue: 3.4.38(typescript@5.5.4)
- '@kyvg/vue3-notification@3.2.1(vue@3.4.29(typescript@5.4.5))':
- dependencies:
- vue: 3.4.29(typescript@5.4.5)
+ '@mdi/js@7.4.47': {}
'@nodelib/fs.scandir@2.1.5':
dependencies:
@@ -3379,139 +3247,109 @@ snapshots:
'@pkgr/core@0.1.1': {}
- '@rollup/pluginutils@5.1.0(rollup@4.18.0)':
+ '@rollup/pluginutils@5.1.0(rollup@4.20.0)':
dependencies:
'@types/estree': 1.0.5
estree-walker: 2.0.2
picomatch: 2.3.1
optionalDependencies:
- rollup: 4.18.0
+ rollup: 4.20.0
- '@rollup/rollup-android-arm-eabi@4.18.0':
+ '@rollup/rollup-android-arm-eabi@4.20.0':
optional: true
- '@rollup/rollup-android-arm64@4.18.0':
+ '@rollup/rollup-android-arm64@4.20.0':
optional: true
- '@rollup/rollup-darwin-arm64@4.18.0':
+ '@rollup/rollup-darwin-arm64@4.20.0':
optional: true
- '@rollup/rollup-darwin-x64@4.18.0':
+ '@rollup/rollup-darwin-x64@4.20.0':
optional: true
- '@rollup/rollup-linux-arm-gnueabihf@4.18.0':
+ '@rollup/rollup-linux-arm-gnueabihf@4.20.0':
optional: true
- '@rollup/rollup-linux-arm-musleabihf@4.18.0':
+ '@rollup/rollup-linux-arm-musleabihf@4.20.0':
optional: true
- '@rollup/rollup-linux-arm64-gnu@4.18.0':
+ '@rollup/rollup-linux-arm64-gnu@4.20.0':
optional: true
- '@rollup/rollup-linux-arm64-musl@4.18.0':
+ '@rollup/rollup-linux-arm64-musl@4.20.0':
optional: true
- '@rollup/rollup-linux-powerpc64le-gnu@4.18.0':
+ '@rollup/rollup-linux-powerpc64le-gnu@4.20.0':
optional: true
- '@rollup/rollup-linux-riscv64-gnu@4.18.0':
+ '@rollup/rollup-linux-riscv64-gnu@4.20.0':
optional: true
- '@rollup/rollup-linux-s390x-gnu@4.18.0':
+ '@rollup/rollup-linux-s390x-gnu@4.20.0':
optional: true
- '@rollup/rollup-linux-x64-gnu@4.18.0':
+ '@rollup/rollup-linux-x64-gnu@4.20.0':
optional: true
- '@rollup/rollup-linux-x64-musl@4.18.0':
+ '@rollup/rollup-linux-x64-musl@4.20.0':
optional: true
- '@rollup/rollup-win32-arm64-msvc@4.18.0':
+ '@rollup/rollup-win32-arm64-msvc@4.20.0':
optional: true
- '@rollup/rollup-win32-ia32-msvc@4.18.0':
+ '@rollup/rollup-win32-ia32-msvc@4.20.0':
optional: true
- '@rollup/rollup-win32-x64-msvc@4.18.0':
+ '@rollup/rollup-win32-x64-msvc@4.20.0':
optional: true
- '@sinclair/typebox@0.27.8': {}
-
'@sindresorhus/is@4.6.0': {}
- '@stylistic/eslint-plugin-js@2.2.1(eslint@9.5.0)':
+ '@stylistic/eslint-plugin@2.7.2(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)':
dependencies:
- '@types/eslint': 8.56.10
- acorn: 8.12.0
- eslint: 9.5.0
+ '@types/eslint': 9.6.1
+ '@typescript-eslint/utils': 8.4.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)
+ eslint: 9.9.0(jiti@1.21.6)
eslint-visitor-keys: 4.0.0
espree: 10.1.0
-
- '@stylistic/eslint-plugin-jsx@2.2.1(eslint@9.5.0)':
- dependencies:
- '@stylistic/eslint-plugin-js': 2.2.1(eslint@9.5.0)
- '@types/eslint': 8.56.10
- eslint: 9.5.0
estraverse: 5.3.0
picomatch: 4.0.2
-
- '@stylistic/eslint-plugin-plus@2.2.1(eslint@9.5.0)(typescript@5.4.5)':
- dependencies:
- '@types/eslint': 8.56.10
- '@typescript-eslint/utils': 7.13.1(eslint@9.5.0)(typescript@5.4.5)
- eslint: 9.5.0
- transitivePeerDependencies:
- - supports-color
- - typescript
-
- '@stylistic/eslint-plugin-ts@2.2.1(eslint@9.5.0)(typescript@5.4.5)':
- dependencies:
- '@stylistic/eslint-plugin-js': 2.2.1(eslint@9.5.0)
- '@types/eslint': 8.56.10
- '@typescript-eslint/utils': 7.13.1(eslint@9.5.0)(typescript@5.4.5)
- eslint: 9.5.0
- transitivePeerDependencies:
- - supports-color
- - typescript
-
- '@stylistic/eslint-plugin@2.2.1(eslint@9.5.0)(typescript@5.4.5)':
- dependencies:
- '@stylistic/eslint-plugin-js': 2.2.1(eslint@9.5.0)
- '@stylistic/eslint-plugin-jsx': 2.2.1(eslint@9.5.0)
- '@stylistic/eslint-plugin-plus': 2.2.1(eslint@9.5.0)(typescript@5.4.5)
- '@stylistic/eslint-plugin-ts': 2.2.1(eslint@9.5.0)(typescript@5.4.5)
- '@types/eslint': 8.56.10
- eslint: 9.5.0
transitivePeerDependencies:
- supports-color
- typescript
'@trysound/sax@0.2.0': {}
- '@types/eslint@8.56.10':
+ '@types/eslint@8.56.11':
+ dependencies:
+ '@types/estree': 1.0.5
+ '@types/json-schema': 7.0.15
+
+ '@types/eslint@9.6.0':
+ dependencies:
+ '@types/estree': 1.0.5
+ '@types/json-schema': 7.0.15
+
+ '@types/eslint@9.6.1':
dependencies:
'@types/estree': 1.0.5
'@types/json-schema': 7.0.15
'@types/eslint__js@8.42.3':
dependencies:
- '@types/eslint': 8.56.10
+ '@types/eslint': 9.6.0
'@types/estree@1.0.5': {}
'@types/json-schema@7.0.15': {}
- '@types/lodash@4.17.5': {}
+ '@types/lodash@4.17.7': {}
'@types/mdast@3.0.15':
dependencies:
- '@types/unist': 2.0.10
+ '@types/unist': 2.0.11
- '@types/node-emoji@2.1.0':
- dependencies:
- node-emoji: 2.1.3
-
- '@types/node@20.14.5':
+ '@types/node@20.14.15':
dependencies:
undici-types: 5.26.5
@@ -3523,234 +3361,290 @@ snapshots:
'@types/tinycolor2@1.4.6': {}
- '@types/unist@2.0.10': {}
+ '@types/unist@2.0.11': {}
'@types/web-bluetooth@0.0.20': {}
- '@typescript-eslint/eslint-plugin@7.13.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint@9.5.0)(typescript@5.4.5)':
+ '@typescript-eslint/eslint-plugin@8.4.0(@typescript-eslint/parser@8.4.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4))(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)':
dependencies:
- '@eslint-community/regexpp': 4.10.1
- '@typescript-eslint/parser': 7.13.1(eslint@9.5.0)(typescript@5.4.5)
- '@typescript-eslint/scope-manager': 7.13.1
- '@typescript-eslint/type-utils': 7.13.1(eslint@9.5.0)(typescript@5.4.5)
- '@typescript-eslint/utils': 7.13.1(eslint@9.5.0)(typescript@5.4.5)
- '@typescript-eslint/visitor-keys': 7.13.1
- eslint: 9.5.0
+ '@eslint-community/regexpp': 4.11.0
+ '@typescript-eslint/parser': 8.4.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)
+ '@typescript-eslint/scope-manager': 8.4.0
+ '@typescript-eslint/type-utils': 8.4.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)
+ '@typescript-eslint/utils': 8.4.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)
+ '@typescript-eslint/visitor-keys': 8.4.0
+ eslint: 9.9.0(jiti@1.21.6)
graphemer: 1.4.0
- ignore: 5.3.1
+ ignore: 5.3.2
natural-compare: 1.4.0
- ts-api-utils: 1.3.0(typescript@5.4.5)
+ ts-api-utils: 1.3.0(typescript@5.5.4)
optionalDependencies:
- typescript: 5.4.5
+ typescript: 5.5.4
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5)':
+ '@typescript-eslint/parser@8.4.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)':
dependencies:
- '@typescript-eslint/scope-manager': 7.13.1
- '@typescript-eslint/types': 7.13.1
- '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.4.5)
- '@typescript-eslint/visitor-keys': 7.13.1
- debug: 4.3.5
- eslint: 9.5.0
+ '@typescript-eslint/scope-manager': 8.4.0
+ '@typescript-eslint/types': 8.4.0
+ '@typescript-eslint/typescript-estree': 8.4.0(typescript@5.5.4)
+ '@typescript-eslint/visitor-keys': 8.4.0
+ debug: 4.3.6
+ eslint: 9.9.0(jiti@1.21.6)
optionalDependencies:
- typescript: 5.4.5
+ typescript: 5.5.4
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/scope-manager@7.13.1':
+ '@typescript-eslint/scope-manager@8.1.0':
dependencies:
- '@typescript-eslint/types': 7.13.1
- '@typescript-eslint/visitor-keys': 7.13.1
+ '@typescript-eslint/types': 8.1.0
+ '@typescript-eslint/visitor-keys': 8.1.0
- '@typescript-eslint/type-utils@7.13.1(eslint@9.5.0)(typescript@5.4.5)':
+ '@typescript-eslint/scope-manager@8.4.0':
dependencies:
- '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.4.5)
- '@typescript-eslint/utils': 7.13.1(eslint@9.5.0)(typescript@5.4.5)
- debug: 4.3.5
- eslint: 9.5.0
- ts-api-utils: 1.3.0(typescript@5.4.5)
+ '@typescript-eslint/types': 8.4.0
+ '@typescript-eslint/visitor-keys': 8.4.0
+
+ '@typescript-eslint/type-utils@8.4.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)':
+ dependencies:
+ '@typescript-eslint/typescript-estree': 8.4.0(typescript@5.5.4)
+ '@typescript-eslint/utils': 8.4.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)
+ debug: 4.3.6
+ ts-api-utils: 1.3.0(typescript@5.5.4)
optionalDependencies:
- typescript: 5.4.5
+ typescript: 5.5.4
transitivePeerDependencies:
+ - eslint
- supports-color
- '@typescript-eslint/types@7.13.1': {}
+ '@typescript-eslint/types@7.18.0': {}
- '@typescript-eslint/typescript-estree@7.13.1(typescript@5.4.5)':
+ '@typescript-eslint/types@8.1.0': {}
+
+ '@typescript-eslint/types@8.4.0': {}
+
+ '@typescript-eslint/typescript-estree@8.1.0(typescript@5.5.4)':
dependencies:
- '@typescript-eslint/types': 7.13.1
- '@typescript-eslint/visitor-keys': 7.13.1
- debug: 4.3.5
+ '@typescript-eslint/types': 8.1.0
+ '@typescript-eslint/visitor-keys': 8.1.0
+ debug: 4.3.6
globby: 11.1.0
is-glob: 4.0.3
- minimatch: 9.0.4
- semver: 7.6.2
- ts-api-utils: 1.3.0(typescript@5.4.5)
+ minimatch: 9.0.5
+ semver: 7.6.3
+ ts-api-utils: 1.3.0(typescript@5.5.4)
optionalDependencies:
- typescript: 5.4.5
+ typescript: 5.5.4
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/utils@7.13.1(eslint@9.5.0)(typescript@5.4.5)':
+ '@typescript-eslint/typescript-estree@8.4.0(typescript@5.5.4)':
dependencies:
- '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0)
- '@typescript-eslint/scope-manager': 7.13.1
- '@typescript-eslint/types': 7.13.1
- '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.4.5)
- eslint: 9.5.0
+ '@typescript-eslint/types': 8.4.0
+ '@typescript-eslint/visitor-keys': 8.4.0
+ debug: 4.3.6
+ fast-glob: 3.3.2
+ is-glob: 4.0.3
+ minimatch: 9.0.5
+ semver: 7.6.3
+ ts-api-utils: 1.3.0(typescript@5.5.4)
+ optionalDependencies:
+ typescript: 5.5.4
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/utils@8.1.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)':
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.0(jiti@1.21.6))
+ '@typescript-eslint/scope-manager': 8.1.0
+ '@typescript-eslint/types': 8.1.0
+ '@typescript-eslint/typescript-estree': 8.1.0(typescript@5.5.4)
+ eslint: 9.9.0(jiti@1.21.6)
transitivePeerDependencies:
- supports-color
- typescript
- '@typescript-eslint/visitor-keys@7.13.1':
+ '@typescript-eslint/utils@8.4.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)':
dependencies:
- '@typescript-eslint/types': 7.13.1
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.0(jiti@1.21.6))
+ '@typescript-eslint/scope-manager': 8.4.0
+ '@typescript-eslint/types': 8.4.0
+ '@typescript-eslint/typescript-estree': 8.4.0(typescript@5.5.4)
+ eslint: 9.9.0(jiti@1.21.6)
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+
+ '@typescript-eslint/visitor-keys@8.1.0':
+ dependencies:
+ '@typescript-eslint/types': 8.1.0
eslint-visitor-keys: 3.4.3
- '@vitejs/plugin-vue@5.0.5(vite@5.3.1(@types/node@20.14.5)(stylus@0.57.0))(vue@3.4.29(typescript@5.4.5))':
+ '@typescript-eslint/visitor-keys@8.4.0':
dependencies:
- vite: 5.3.1(@types/node@20.14.5)(stylus@0.57.0)
- vue: 3.4.29(typescript@5.4.5)
+ '@typescript-eslint/types': 8.4.0
+ eslint-visitor-keys: 3.4.3
- '@vitest/expect@1.6.0':
+ '@vitejs/plugin-vue@5.1.2(vite@5.4.1(@types/node@20.14.15)(stylus@0.57.0))(vue@3.4.38(typescript@5.5.4))':
dependencies:
- '@vitest/spy': 1.6.0
- '@vitest/utils': 1.6.0
- chai: 4.4.1
+ vite: 5.4.1(@types/node@20.14.15)(stylus@0.57.0)
+ vue: 3.4.38(typescript@5.5.4)
- '@vitest/runner@1.6.0':
+ '@vitest/eslint-plugin@1.1.0(@typescript-eslint/utils@8.4.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4))(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)(vitest@2.0.5(@types/node@20.14.15)(jsdom@25.0.0)(stylus@0.57.0))':
dependencies:
- '@vitest/utils': 1.6.0
- p-limit: 5.0.0
+ eslint: 9.9.0(jiti@1.21.6)
+ optionalDependencies:
+ '@typescript-eslint/utils': 8.4.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)
+ typescript: 5.5.4
+ vitest: 2.0.5(@types/node@20.14.15)(jsdom@25.0.0)(stylus@0.57.0)
+
+ '@vitest/expect@2.0.5':
+ dependencies:
+ '@vitest/spy': 2.0.5
+ '@vitest/utils': 2.0.5
+ chai: 5.1.1
+ tinyrainbow: 1.2.0
+
+ '@vitest/pretty-format@2.0.5':
+ dependencies:
+ tinyrainbow: 1.2.0
+
+ '@vitest/runner@2.0.5':
+ dependencies:
+ '@vitest/utils': 2.0.5
pathe: 1.1.2
- '@vitest/snapshot@1.6.0':
+ '@vitest/snapshot@2.0.5':
dependencies:
- magic-string: 0.30.10
+ '@vitest/pretty-format': 2.0.5
+ magic-string: 0.30.11
pathe: 1.1.2
- pretty-format: 29.7.0
- '@vitest/spy@1.6.0':
+ '@vitest/spy@2.0.5':
dependencies:
- tinyspy: 2.2.1
+ tinyspy: 3.0.0
- '@vitest/utils@1.6.0':
+ '@vitest/utils@2.0.5':
dependencies:
- diff-sequences: 29.6.3
+ '@vitest/pretty-format': 2.0.5
estree-walker: 3.0.3
- loupe: 2.3.7
- pretty-format: 29.7.0
+ loupe: 3.1.1
+ tinyrainbow: 1.2.0
- '@volar/language-core@2.3.0':
+ '@volar/language-core@2.4.0-alpha.18':
dependencies:
- '@volar/source-map': 2.3.0
+ '@volar/source-map': 2.4.0-alpha.18
- '@volar/source-map@2.3.0':
- dependencies:
- muggle-string: 0.4.1
+ '@volar/source-map@2.4.0-alpha.18': {}
- '@volar/typescript@2.3.0':
+ '@volar/typescript@2.4.0-alpha.18':
dependencies:
- '@volar/language-core': 2.3.0
+ '@volar/language-core': 2.4.0-alpha.18
path-browserify: 1.0.1
vscode-uri: 3.0.8
- '@vue/compiler-core@3.4.29':
+ '@vue/compiler-core@3.4.38':
dependencies:
- '@babel/parser': 7.24.7
- '@vue/shared': 3.4.29
+ '@babel/parser': 7.25.3
+ '@vue/shared': 3.4.38
entities: 4.5.0
estree-walker: 2.0.2
source-map-js: 1.2.0
- '@vue/compiler-dom@3.4.29':
+ '@vue/compiler-dom@3.4.38':
dependencies:
- '@vue/compiler-core': 3.4.29
- '@vue/shared': 3.4.29
+ '@vue/compiler-core': 3.4.38
+ '@vue/shared': 3.4.38
- '@vue/compiler-sfc@3.4.29':
+ '@vue/compiler-sfc@3.4.38':
dependencies:
- '@babel/parser': 7.24.7
- '@vue/compiler-core': 3.4.29
- '@vue/compiler-dom': 3.4.29
- '@vue/compiler-ssr': 3.4.29
- '@vue/shared': 3.4.29
+ '@babel/parser': 7.25.3
+ '@vue/compiler-core': 3.4.38
+ '@vue/compiler-dom': 3.4.38
+ '@vue/compiler-ssr': 3.4.38
+ '@vue/shared': 3.4.38
estree-walker: 2.0.2
- magic-string: 0.30.10
- postcss: 8.4.38
+ magic-string: 0.30.11
+ postcss: 8.4.41
source-map-js: 1.2.0
- '@vue/compiler-ssr@3.4.29':
+ '@vue/compiler-ssr@3.4.38':
dependencies:
- '@vue/compiler-dom': 3.4.29
- '@vue/shared': 3.4.29
+ '@vue/compiler-dom': 3.4.38
+ '@vue/shared': 3.4.38
+
+ '@vue/compiler-vue2@2.7.16':
+ dependencies:
+ de-indent: 1.0.2
+ he: 1.2.0
'@vue/devtools-api@6.6.3': {}
- '@vue/language-core@2.0.21(typescript@5.4.5)':
+ '@vue/language-core@2.0.29(typescript@5.5.4)':
dependencies:
- '@volar/language-core': 2.3.0
- '@vue/compiler-dom': 3.4.29
- '@vue/shared': 3.4.29
+ '@volar/language-core': 2.4.0-alpha.18
+ '@vue/compiler-dom': 3.4.38
+ '@vue/compiler-vue2': 2.7.16
+ '@vue/shared': 3.4.38
computeds: 0.0.1
- minimatch: 9.0.4
+ minimatch: 9.0.5
+ muggle-string: 0.4.1
path-browserify: 1.0.1
- vue-template-compiler: 2.7.16
optionalDependencies:
- typescript: 5.4.5
+ typescript: 5.5.4
- '@vue/reactivity@3.4.29':
+ '@vue/reactivity@3.4.38':
dependencies:
- '@vue/shared': 3.4.29
+ '@vue/shared': 3.4.38
- '@vue/runtime-core@3.4.29':
+ '@vue/runtime-core@3.4.38':
dependencies:
- '@vue/reactivity': 3.4.29
- '@vue/shared': 3.4.29
+ '@vue/reactivity': 3.4.38
+ '@vue/shared': 3.4.38
- '@vue/runtime-dom@3.4.29':
+ '@vue/runtime-dom@3.4.38':
dependencies:
- '@vue/reactivity': 3.4.29
- '@vue/runtime-core': 3.4.29
- '@vue/shared': 3.4.29
+ '@vue/reactivity': 3.4.38
+ '@vue/runtime-core': 3.4.38
+ '@vue/shared': 3.4.38
csstype: 3.1.3
- '@vue/server-renderer@3.4.29(vue@3.4.29(typescript@5.4.5))':
+ '@vue/server-renderer@3.4.38(vue@3.4.38(typescript@5.5.4))':
dependencies:
- '@vue/compiler-ssr': 3.4.29
- '@vue/shared': 3.4.29
- vue: 3.4.29(typescript@5.4.5)
+ '@vue/compiler-ssr': 3.4.38
+ '@vue/shared': 3.4.38
+ vue: 3.4.38(typescript@5.5.4)
- '@vue/shared@3.4.29': {}
+ '@vue/shared@3.4.38': {}
'@vue/test-utils@2.4.6':
dependencies:
js-beautify: 1.15.1
- vue-component-type-helpers: 2.0.21
+ vue-component-type-helpers: 2.0.29
- '@vueuse/core@10.11.0(vue@3.4.29(typescript@5.4.5))':
+ '@vueuse/core@10.11.1(vue@3.4.38(typescript@5.5.4))':
dependencies:
'@types/web-bluetooth': 0.0.20
- '@vueuse/metadata': 10.11.0
- '@vueuse/shared': 10.11.0(vue@3.4.29(typescript@5.4.5))
- vue-demi: 0.14.8(vue@3.4.29(typescript@5.4.5))
+ '@vueuse/metadata': 10.11.1
+ '@vueuse/shared': 10.11.1(vue@3.4.38(typescript@5.5.4))
+ vue-demi: 0.14.10(vue@3.4.38(typescript@5.5.4))
transitivePeerDependencies:
- '@vue/composition-api'
- vue
- '@vueuse/metadata@10.11.0': {}
+ '@vueuse/metadata@10.11.1': {}
- '@vueuse/shared@10.11.0(vue@3.4.29(typescript@5.4.5))':
+ '@vueuse/shared@10.11.1(vue@3.4.38(typescript@5.5.4))':
dependencies:
- vue-demi: 0.14.8(vue@3.4.29(typescript@5.4.5))
+ vue-demi: 0.14.10(vue@3.4.38(typescript@5.5.4))
transitivePeerDependencies:
- '@vue/composition-api'
- vue
'@windicss/config@1.9.3':
dependencies:
- debug: 4.3.5
+ debug: 4.3.6
jiti: 1.21.6
windicss: 3.5.6
transitivePeerDependencies:
@@ -3758,11 +3652,11 @@ snapshots:
'@windicss/plugin-utils@1.9.3':
dependencies:
- '@antfu/utils': 0.7.8
+ '@antfu/utils': 0.7.10
'@windicss/config': 1.9.3
- debug: 4.3.5
+ debug: 4.3.6
fast-glob: 3.3.2
- magic-string: 0.30.10
+ magic-string: 0.30.11
micromatch: 4.0.7
windicss: 3.5.6
transitivePeerDependencies:
@@ -3770,19 +3664,15 @@ snapshots:
abbrev@2.0.0: {}
- acorn-jsx@5.3.2(acorn@8.12.0):
+ acorn-jsx@5.3.2(acorn@8.12.1):
dependencies:
- acorn: 8.12.0
+ acorn: 8.12.1
- acorn-walk@8.3.3:
- dependencies:
- acorn: 8.12.0
-
- acorn@8.12.0: {}
+ acorn@8.12.1: {}
agent-base@7.1.1:
dependencies:
- debug: 4.3.5
+ debug: 4.3.6
transitivePeerDependencies:
- supports-color
@@ -3805,8 +3695,6 @@ snapshots:
dependencies:
color-convert: 2.0.1
- ansi-styles@5.2.0: {}
-
ansi-styles@6.2.1: {}
ansi_up@6.0.2: {}
@@ -3822,7 +3710,7 @@ snapshots:
array-union@2.1.0: {}
- assertion-error@1.1.0: {}
+ assertion-error@2.0.1: {}
asynckit@0.4.0: {}
@@ -3851,32 +3739,37 @@ snapshots:
dependencies:
fill-range: 7.1.1
- browserslist@4.23.1:
+ browserslist@4.23.2:
dependencies:
- caniuse-lite: 1.0.30001636
- electron-to-chromium: 1.4.805
- node-releases: 2.0.14
- update-browserslist-db: 1.0.16(browserslist@4.23.1)
+ caniuse-lite: 1.0.30001644
+ electron-to-chromium: 1.5.3
+ node-releases: 2.0.18
+ update-browserslist-db: 1.1.0(browserslist@4.23.2)
+
+ browserslist@4.23.3:
+ dependencies:
+ caniuse-lite: 1.0.30001651
+ electron-to-chromium: 1.5.8
+ node-releases: 2.0.18
+ update-browserslist-db: 1.1.0(browserslist@4.23.3)
builtin-modules@3.3.0: {}
cac@6.7.14: {}
- call-me-maybe@1.0.2: {}
-
callsites@3.1.0: {}
- caniuse-lite@1.0.30001636: {}
+ caniuse-lite@1.0.30001644: {}
- chai@4.4.1:
+ caniuse-lite@1.0.30001651: {}
+
+ chai@5.1.1:
dependencies:
- assertion-error: 1.1.0
- check-error: 1.0.3
- deep-eql: 4.1.4
- get-func-name: 2.0.2
- loupe: 2.3.7
- pathval: 1.1.1
- type-detect: 4.0.8
+ assertion-error: 2.0.1
+ check-error: 2.1.1
+ deep-eql: 5.0.2
+ loupe: 3.1.1
+ pathval: 2.0.0
chalk@2.4.2:
dependencies:
@@ -3889,6 +3782,8 @@ snapshots:
ansi-styles: 4.3.0
supports-color: 7.2.0
+ chalk@5.3.0: {}
+
char-regex@1.0.2: {}
character-entities-legacy@1.1.4: {}
@@ -3897,9 +3792,7 @@ snapshots:
character-reference-invalid@1.1.4: {}
- check-error@1.0.3:
- dependencies:
- get-func-name: 2.0.2
+ check-error@2.1.1: {}
chokidar@3.6.0:
dependencies:
@@ -3960,9 +3853,9 @@ snapshots:
convert-source-map@2.0.0: {}
- core-js-compat@3.37.1:
+ core-js-compat@3.38.0:
dependencies:
- browserslist: 4.23.1
+ browserslist: 4.23.3
cross-spawn@7.0.3:
dependencies:
@@ -4013,7 +3906,7 @@ snapshots:
whatwg-mimetype: 4.0.0
whatwg-url: 14.0.0
- dayjs@1.11.11: {}
+ dayjs@1.11.12: {}
de-indent@1.0.2: {}
@@ -4021,7 +3914,7 @@ snapshots:
dependencies:
ms: 2.1.3
- debug@4.3.5:
+ debug@4.3.6:
dependencies:
ms: 2.1.2
@@ -4029,16 +3922,12 @@ snapshots:
decode-uri-component@0.2.2: {}
- deep-eql@4.1.4:
- dependencies:
- type-detect: 4.0.8
+ deep-eql@5.0.2: {}
deep-is@0.1.4: {}
delayed-stream@1.0.0: {}
- diff-sequences@29.6.3: {}
-
dir-glob@3.0.1:
dependencies:
path-type: 4.0.0
@@ -4072,9 +3961,11 @@ snapshots:
'@one-ini/wasm': 0.1.1
commander: 10.0.1
minimatch: 9.0.1
- semver: 7.6.2
+ semver: 7.6.3
- electron-to-chromium@1.4.805: {}
+ electron-to-chromium@1.5.3: {}
+
+ electron-to-chromium@1.5.8: {}
emoji-regex@8.0.0: {}
@@ -4082,7 +3973,7 @@ snapshots:
emojilib@2.4.0: {}
- enhanced-resolve@5.17.0:
+ enhanced-resolve@5.17.1:
dependencies:
graceful-fs: 4.2.11
tapable: 2.2.1
@@ -4093,6 +3984,8 @@ snapshots:
dependencies:
is-arrayish: 0.2.1
+ es-module-lexer@1.5.4: {}
+
esbuild@0.21.5:
optionalDependencies:
'@esbuild/aix-ppc64': 0.21.5
@@ -4133,165 +4026,165 @@ snapshots:
optionalDependencies:
source-map: 0.6.1
- eslint-compat-utils@0.5.1(eslint@9.5.0):
+ eslint-compat-utils@0.5.1(eslint@9.9.0(jiti@1.21.6)):
dependencies:
- eslint: 9.5.0
- semver: 7.6.2
+ eslint: 9.9.0(jiti@1.21.6)
+ semver: 7.6.3
- eslint-config-flat-gitignore@0.1.5:
+ eslint-config-flat-gitignore@0.3.0(eslint@9.9.0(jiti@1.21.6)):
dependencies:
- find-up: 7.0.0
- parse-gitignore: 2.0.0
+ '@eslint/compat': 1.1.1
+ eslint: 9.9.0(jiti@1.21.6)
+ find-up-simple: 1.0.0
- eslint-flat-config-utils@0.2.5:
+ eslint-flat-config-utils@0.3.1:
dependencies:
- '@types/eslint': 8.56.10
+ '@types/eslint': 9.6.0
pathe: 1.1.2
eslint-import-resolver-node@0.3.9:
dependencies:
debug: 3.2.7
- is-core-module: 2.13.1
+ is-core-module: 2.15.0
resolve: 1.22.8
transitivePeerDependencies:
- supports-color
- eslint-merge-processors@0.1.0(eslint@9.5.0):
+ eslint-merge-processors@0.1.0(eslint@9.9.0(jiti@1.21.6)):
dependencies:
- eslint: 9.5.0
+ eslint: 9.9.0(jiti@1.21.6)
- eslint-plugin-antfu@2.3.3(eslint@9.5.0):
+ eslint-plugin-antfu@2.5.0(eslint@9.9.0(jiti@1.21.6)):
dependencies:
- '@antfu/utils': 0.7.8
- eslint: 9.5.0
+ '@antfu/utils': 0.7.10
+ eslint: 9.9.0(jiti@1.21.6)
- eslint-plugin-command@0.2.3(eslint@9.5.0):
+ eslint-plugin-command@0.2.3(eslint@9.9.0(jiti@1.21.6)):
dependencies:
'@es-joy/jsdoccomment': 0.43.1
- eslint: 9.5.0
+ eslint: 9.9.0(jiti@1.21.6)
- eslint-plugin-es-x@7.7.0(eslint@9.5.0):
+ eslint-plugin-es-x@7.8.0(eslint@9.9.0(jiti@1.21.6)):
dependencies:
- '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0)
- '@eslint-community/regexpp': 4.10.1
- eslint: 9.5.0
- eslint-compat-utils: 0.5.1(eslint@9.5.0)
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.0(jiti@1.21.6))
+ '@eslint-community/regexpp': 4.11.0
+ eslint: 9.9.0(jiti@1.21.6)
+ eslint-compat-utils: 0.5.1(eslint@9.9.0(jiti@1.21.6))
- eslint-plugin-eslint-comments@3.2.0(eslint@9.5.0):
+ eslint-plugin-import-x@4.2.1(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4):
dependencies:
- escape-string-regexp: 1.0.5
- eslint: 9.5.0
- ignore: 5.3.1
-
- eslint-plugin-import-x@0.5.1(eslint@9.5.0)(typescript@5.4.5):
- dependencies:
- '@typescript-eslint/utils': 7.13.1(eslint@9.5.0)(typescript@5.4.5)
- debug: 4.3.5
+ '@typescript-eslint/utils': 8.1.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)
+ debug: 4.3.6
doctrine: 3.0.0
- eslint: 9.5.0
+ eslint: 9.9.0(jiti@1.21.6)
eslint-import-resolver-node: 0.3.9
- get-tsconfig: 4.7.5
+ get-tsconfig: 4.7.6
is-glob: 4.0.3
- minimatch: 9.0.4
- semver: 7.6.2
+ minimatch: 9.0.5
+ semver: 7.6.3
+ stable-hash: 0.0.4
tslib: 2.6.3
transitivePeerDependencies:
- supports-color
- typescript
- eslint-plugin-jsdoc@48.2.12(eslint@9.5.0):
+ eslint-plugin-jsdoc@50.2.2(eslint@9.9.0(jiti@1.21.6)):
dependencies:
- '@es-joy/jsdoccomment': 0.43.1
+ '@es-joy/jsdoccomment': 0.48.0
are-docs-informative: 0.0.2
comment-parser: 1.4.1
- debug: 4.3.5
+ debug: 4.3.6
escape-string-regexp: 4.0.0
- eslint: 9.5.0
- esquery: 1.5.0
- semver: 7.6.2
+ eslint: 9.9.0(jiti@1.21.6)
+ espree: 10.1.0
+ esquery: 1.6.0
+ parse-imports: 2.1.1
+ semver: 7.6.3
spdx-expression-parse: 4.0.0
+ synckit: 0.9.1
transitivePeerDependencies:
- supports-color
- eslint-plugin-jsonc@2.16.0(eslint@9.5.0):
+ eslint-plugin-jsonc@2.16.0(eslint@9.9.0(jiti@1.21.6)):
dependencies:
- '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0)
- eslint: 9.5.0
- eslint-compat-utils: 0.5.1(eslint@9.5.0)
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.0(jiti@1.21.6))
+ eslint: 9.9.0(jiti@1.21.6)
+ eslint-compat-utils: 0.5.1(eslint@9.9.0(jiti@1.21.6))
espree: 9.6.1
graphemer: 1.4.0
jsonc-eslint-parser: 2.4.0
natural-compare: 1.4.0
synckit: 0.6.2
- eslint-plugin-markdown@5.0.0(eslint@9.5.0):
+ eslint-plugin-markdown@5.1.0(eslint@9.9.0(jiti@1.21.6)):
dependencies:
- eslint: 9.5.0
+ eslint: 9.9.0(jiti@1.21.6)
mdast-util-from-markdown: 0.8.5
transitivePeerDependencies:
- supports-color
- eslint-plugin-n@17.9.0(eslint@9.5.0):
+ eslint-plugin-n@17.10.2(eslint@9.9.0(jiti@1.21.6)):
dependencies:
- '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0)
- enhanced-resolve: 5.17.0
- eslint: 9.5.0
- eslint-plugin-es-x: 7.7.0(eslint@9.5.0)
- get-tsconfig: 4.7.5
- globals: 15.6.0
- ignore: 5.3.1
- minimatch: 9.0.4
- semver: 7.6.2
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.0(jiti@1.21.6))
+ enhanced-resolve: 5.17.1
+ eslint: 9.9.0(jiti@1.21.6)
+ eslint-plugin-es-x: 7.8.0(eslint@9.9.0(jiti@1.21.6))
+ get-tsconfig: 4.7.6
+ globals: 15.9.0
+ ignore: 5.3.2
+ minimatch: 9.0.5
+ semver: 7.6.3
- eslint-plugin-no-only-tests@3.1.0: {}
+ eslint-plugin-no-only-tests@3.3.0: {}
- eslint-plugin-perfectionist@2.11.0(eslint@9.5.0)(typescript@5.4.5)(vue-eslint-parser@9.4.3(eslint@9.5.0)):
+ eslint-plugin-perfectionist@3.4.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)(vue-eslint-parser@9.4.3(eslint@9.9.0(jiti@1.21.6))):
dependencies:
- '@typescript-eslint/utils': 7.13.1(eslint@9.5.0)(typescript@5.4.5)
- eslint: 9.5.0
- minimatch: 9.0.4
+ '@typescript-eslint/types': 8.4.0
+ '@typescript-eslint/utils': 8.4.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)
+ eslint: 9.9.0(jiti@1.21.6)
+ minimatch: 9.0.5
natural-compare-lite: 1.4.0
optionalDependencies:
- vue-eslint-parser: 9.4.3(eslint@9.5.0)
+ vue-eslint-parser: 9.4.3(eslint@9.9.0(jiti@1.21.6))
transitivePeerDependencies:
- supports-color
- typescript
- eslint-plugin-promise@6.2.0(eslint@9.5.0):
+ eslint-plugin-promise@7.1.0(eslint@9.9.0(jiti@1.21.6)):
dependencies:
- eslint: 9.5.0
+ eslint: 9.9.0(jiti@1.21.6)
- eslint-plugin-regexp@2.6.0(eslint@9.5.0):
+ eslint-plugin-regexp@2.6.0(eslint@9.9.0(jiti@1.21.6)):
dependencies:
- '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0)
- '@eslint-community/regexpp': 4.10.1
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.0(jiti@1.21.6))
+ '@eslint-community/regexpp': 4.11.0
comment-parser: 1.4.1
- eslint: 9.5.0
- jsdoc-type-pratt-parser: 4.0.0
+ eslint: 9.9.0(jiti@1.21.6)
+ jsdoc-type-pratt-parser: 4.1.0
refa: 0.12.1
regexp-ast-analysis: 0.7.1
scslre: 0.3.0
- eslint-plugin-toml@0.11.0(eslint@9.5.0):
+ eslint-plugin-toml@0.11.1(eslint@9.9.0(jiti@1.21.6)):
dependencies:
- debug: 4.3.5
- eslint: 9.5.0
- eslint-compat-utils: 0.5.1(eslint@9.5.0)
+ debug: 4.3.6
+ eslint: 9.9.0(jiti@1.21.6)
+ eslint-compat-utils: 0.5.1(eslint@9.9.0(jiti@1.21.6))
lodash: 4.17.21
- toml-eslint-parser: 0.9.3
+ toml-eslint-parser: 0.10.0
transitivePeerDependencies:
- supports-color
- eslint-plugin-unicorn@53.0.0(eslint@9.5.0):
+ eslint-plugin-unicorn@55.0.0(eslint@9.9.0(jiti@1.21.6)):
dependencies:
'@babel/helper-validator-identifier': 7.24.7
- '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0)
- '@eslint/eslintrc': 3.1.0
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.0(jiti@1.21.6))
ci-info: 4.0.0
clean-regexp: 1.0.0
- core-js-compat: 3.37.1
- eslint: 9.5.0
- esquery: 1.5.0
+ core-js-compat: 3.38.0
+ eslint: 9.9.0(jiti@1.21.6)
+ esquery: 1.6.0
+ globals: 15.9.0
indent-string: 4.0.0
is-builtin-module: 3.2.1
jsesc: 3.0.2
@@ -4299,82 +4192,66 @@ snapshots:
read-pkg-up: 7.0.1
regexp-tree: 0.1.27
regjsparser: 0.10.0
- semver: 7.6.2
+ semver: 7.6.3
strip-indent: 3.0.0
- transitivePeerDependencies:
- - supports-color
- eslint-plugin-unused-imports@3.2.0(@typescript-eslint/eslint-plugin@7.13.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint@9.5.0)(typescript@5.4.5))(eslint@9.5.0):
+ eslint-plugin-unused-imports@4.1.3(@typescript-eslint/eslint-plugin@8.4.0(@typescript-eslint/parser@8.4.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4))(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4))(eslint@9.9.0(jiti@1.21.6)):
dependencies:
- eslint: 9.5.0
- eslint-rule-composer: 0.3.0
+ eslint: 9.9.0(jiti@1.21.6)
optionalDependencies:
- '@typescript-eslint/eslint-plugin': 7.13.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint@9.5.0)(typescript@5.4.5)
+ '@typescript-eslint/eslint-plugin': 8.4.0(@typescript-eslint/parser@8.4.0(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4))(eslint@9.9.0(jiti@1.21.6))(typescript@5.5.4)
- eslint-plugin-vitest@0.5.4(@typescript-eslint/eslint-plugin@7.13.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint@9.5.0)(typescript@5.4.5))(eslint@9.5.0)(typescript@5.4.5)(vitest@1.6.0(@types/node@20.14.5)(jsdom@24.1.0)(stylus@0.57.0)):
+ eslint-plugin-vue-scoped-css@2.8.1(eslint@9.9.0(jiti@1.21.6))(vue-eslint-parser@9.4.3(eslint@9.9.0(jiti@1.21.6))):
dependencies:
- '@typescript-eslint/utils': 7.13.1(eslint@9.5.0)(typescript@5.4.5)
- eslint: 9.5.0
- optionalDependencies:
- '@typescript-eslint/eslint-plugin': 7.13.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint@9.5.0)(typescript@5.4.5)
- vitest: 1.6.0(@types/node@20.14.5)(jsdom@24.1.0)(stylus@0.57.0)
- transitivePeerDependencies:
- - supports-color
- - typescript
-
- eslint-plugin-vue-scoped-css@2.8.0(eslint@9.5.0)(vue-eslint-parser@9.4.3(eslint@9.5.0)):
- dependencies:
- '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0)
- eslint: 9.5.0
- eslint-compat-utils: 0.5.1(eslint@9.5.0)
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.0(jiti@1.21.6))
+ eslint: 9.9.0(jiti@1.21.6)
+ eslint-compat-utils: 0.5.1(eslint@9.9.0(jiti@1.21.6))
lodash: 4.17.21
- postcss: 8.4.38
- postcss-safe-parser: 6.0.0(postcss@8.4.38)
- postcss-scss: 4.0.9(postcss@8.4.38)
- postcss-selector-parser: 6.1.0
+ postcss: 8.4.40
+ postcss-safe-parser: 6.0.0(postcss@8.4.40)
+ postcss-scss: 4.0.9(postcss@8.4.40)
+ postcss-selector-parser: 6.1.1
postcss-styl: 0.12.3
- vue-eslint-parser: 9.4.3(eslint@9.5.0)
+ vue-eslint-parser: 9.4.3(eslint@9.9.0(jiti@1.21.6))
transitivePeerDependencies:
- supports-color
- eslint-plugin-vue@9.26.0(eslint@9.5.0):
+ eslint-plugin-vue@9.28.0(eslint@9.9.0(jiti@1.21.6)):
dependencies:
- '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0)
- eslint: 9.5.0
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.0(jiti@1.21.6))
+ eslint: 9.9.0(jiti@1.21.6)
globals: 13.24.0
natural-compare: 1.4.0
nth-check: 2.1.1
- postcss-selector-parser: 6.1.0
- semver: 7.6.2
- vue-eslint-parser: 9.4.3(eslint@9.5.0)
+ postcss-selector-parser: 6.1.2
+ semver: 7.6.3
+ vue-eslint-parser: 9.4.3(eslint@9.9.0(jiti@1.21.6))
xml-name-validator: 4.0.0
transitivePeerDependencies:
- supports-color
- eslint-plugin-yml@1.14.0(eslint@9.5.0):
+ eslint-plugin-yml@1.14.0(eslint@9.9.0(jiti@1.21.6)):
dependencies:
- debug: 4.3.5
- eslint: 9.5.0
- eslint-compat-utils: 0.5.1(eslint@9.5.0)
+ debug: 4.3.6
+ eslint: 9.9.0(jiti@1.21.6)
+ eslint-compat-utils: 0.5.1(eslint@9.9.0(jiti@1.21.6))
lodash: 4.17.21
natural-compare: 1.4.0
yaml-eslint-parser: 1.2.3
transitivePeerDependencies:
- supports-color
- eslint-processor-vue-blocks@0.1.2(@vue/compiler-sfc@3.4.29)(eslint@9.5.0):
+ eslint-processor-vue-blocks@0.1.2(@vue/compiler-sfc@3.4.38)(eslint@9.9.0(jiti@1.21.6)):
dependencies:
- '@vue/compiler-sfc': 3.4.29
- eslint: 9.5.0
-
- eslint-rule-composer@0.3.0: {}
+ '@vue/compiler-sfc': 3.4.38
+ eslint: 9.9.0(jiti@1.21.6)
eslint-scope@7.2.2:
dependencies:
esrecurse: 4.3.0
estraverse: 5.3.0
- eslint-scope@8.0.1:
+ eslint-scope@8.0.2:
dependencies:
esrecurse: 4.3.0
estraverse: 5.3.0
@@ -4383,31 +4260,31 @@ snapshots:
eslint-visitor-keys@4.0.0: {}
- eslint@9.5.0:
+ eslint@9.9.0(jiti@1.21.6):
dependencies:
- '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0)
- '@eslint-community/regexpp': 4.10.1
- '@eslint/config-array': 0.16.0
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.0(jiti@1.21.6))
+ '@eslint-community/regexpp': 4.11.0
+ '@eslint/config-array': 0.17.1
'@eslint/eslintrc': 3.1.0
- '@eslint/js': 9.5.0
+ '@eslint/js': 9.9.0
'@humanwhocodes/module-importer': 1.0.1
'@humanwhocodes/retry': 0.3.0
'@nodelib/fs.walk': 1.2.8
ajv: 6.12.6
chalk: 4.1.2
cross-spawn: 7.0.3
- debug: 4.3.5
+ debug: 4.3.6
escape-string-regexp: 4.0.0
- eslint-scope: 8.0.1
+ eslint-scope: 8.0.2
eslint-visitor-keys: 4.0.0
espree: 10.1.0
- esquery: 1.5.0
+ esquery: 1.6.0
esutils: 2.0.3
fast-deep-equal: 3.1.3
file-entry-cache: 8.0.0
find-up: 5.0.0
glob-parent: 6.0.2
- ignore: 5.3.1
+ ignore: 5.3.2
imurmurhash: 0.1.4
is-glob: 4.0.3
is-path-inside: 3.0.3
@@ -4419,24 +4296,26 @@ snapshots:
optionator: 0.9.4
strip-ansi: 6.0.1
text-table: 0.2.0
+ optionalDependencies:
+ jiti: 1.21.6
transitivePeerDependencies:
- supports-color
espree@10.1.0:
dependencies:
- acorn: 8.12.0
- acorn-jsx: 5.3.2(acorn@8.12.0)
+ acorn: 8.12.1
+ acorn-jsx: 5.3.2(acorn@8.12.1)
eslint-visitor-keys: 4.0.0
espree@9.6.1:
dependencies:
- acorn: 8.12.0
- acorn-jsx: 5.3.2(acorn@8.12.0)
+ acorn: 8.12.1
+ acorn-jsx: 5.3.2(acorn@8.12.1)
eslint-visitor-keys: 3.4.3
esprima@4.0.1: {}
- esquery@1.5.0:
+ esquery@1.6.0:
dependencies:
estraverse: 5.3.0
@@ -4454,18 +4333,6 @@ snapshots:
esutils@2.0.3: {}
- execa@5.1.1:
- dependencies:
- cross-spawn: 7.0.3
- get-stream: 6.0.1
- human-signals: 2.1.0
- is-stream: 2.0.1
- merge-stream: 2.0.0
- npm-run-path: 4.0.1
- onetime: 5.1.2
- signal-exit: 3.0.7
- strip-final-newline: 2.0.0
-
execa@8.0.1:
dependencies:
cross-spawn: 7.0.3
@@ -4506,6 +4373,8 @@ snapshots:
dependencies:
to-regex-range: 5.0.1
+ find-up-simple@1.0.0: {}
+
find-up@4.1.0:
dependencies:
locate-path: 5.0.0
@@ -4516,12 +4385,6 @@ snapshots:
locate-path: 6.0.0
path-exists: 4.0.0
- find-up@7.0.0:
- dependencies:
- locate-path: 7.2.0
- path-exists: 5.0.0
- unicorn-magic: 0.1.0
-
flat-cache@4.0.1:
dependencies:
flatted: 3.3.1
@@ -4555,11 +4418,9 @@ snapshots:
get-func-name@2.0.2: {}
- get-stream@6.0.1: {}
-
get-stream@8.0.1: {}
- get-tsconfig@4.7.5:
+ get-tsconfig@4.7.6:
dependencies:
resolve-pkg-maps: 1.0.0
@@ -4571,12 +4432,13 @@ snapshots:
dependencies:
is-glob: 4.0.3
- glob@10.4.1:
+ glob@10.4.5:
dependencies:
foreground-child: 3.2.1
- jackspeak: 3.4.0
- minimatch: 9.0.4
+ jackspeak: 3.4.3
+ minimatch: 9.0.5
minipass: 7.1.2
+ package-json-from-dist: 1.0.0
path-scurry: 1.11.1
glob@7.2.3:
@@ -4588,14 +4450,6 @@ snapshots:
once: 1.4.0
path-is-absolute: 1.0.1
- glob@8.1.0:
- dependencies:
- fs.realpath: 1.0.0
- inflight: 1.0.6
- inherits: 2.0.4
- minimatch: 5.1.6
- once: 1.4.0
-
globals@11.12.0: {}
globals@13.24.0:
@@ -4604,14 +4458,16 @@ snapshots:
globals@14.0.0: {}
- globals@15.6.0: {}
+ globals@15.8.0: {}
+
+ globals@15.9.0: {}
globby@11.1.0:
dependencies:
array-union: 2.1.0
dir-glob: 3.0.1
fast-glob: 3.3.2
- ignore: 5.3.1
+ ignore: 5.3.2
merge2: 1.4.1
slash: 3.0.0
@@ -4638,19 +4494,17 @@ snapshots:
http-proxy-agent@7.0.2:
dependencies:
agent-base: 7.1.1
- debug: 4.3.5
+ debug: 4.3.6
transitivePeerDependencies:
- supports-color
- https-proxy-agent@7.0.4:
+ https-proxy-agent@7.0.5:
dependencies:
agent-base: 7.1.1
- debug: 4.3.5
+ debug: 4.3.6
transitivePeerDependencies:
- supports-color
- human-signals@2.1.0: {}
-
human-signals@5.0.0: {}
iconv-lite@0.6.3:
@@ -4659,6 +4513,8 @@ snapshots:
ignore@5.3.1: {}
+ ignore@5.3.2: {}
+
import-fresh@3.3.0:
dependencies:
parent-module: 1.0.1
@@ -4694,7 +4550,7 @@ snapshots:
dependencies:
builtin-modules: 3.3.0
- is-core-module@2.13.1:
+ is-core-module@2.15.0:
dependencies:
hasown: 2.0.2
@@ -4712,7 +4568,7 @@ snapshots:
is-language-code@3.1.0:
dependencies:
- '@babel/runtime': 7.24.7
+ '@babel/runtime': 7.25.0
is-number@7.0.0: {}
@@ -4720,13 +4576,11 @@ snapshots:
is-potential-custom-element-name@1.0.1: {}
- is-stream@2.0.1: {}
-
is-stream@3.0.0: {}
isexe@2.0.0: {}
- jackspeak@3.4.0:
+ jackspeak@3.4.3:
dependencies:
'@isaacs/cliui': 8.0.2
optionalDependencies:
@@ -4740,7 +4594,7 @@ snapshots:
dependencies:
config-chain: 1.1.13
editorconfig: 1.0.4
- glob: 10.4.1
+ glob: 10.4.5
js-cookie: 3.0.5
nopt: 7.2.1
@@ -4748,15 +4602,15 @@ snapshots:
js-tokens@4.0.0: {}
- js-tokens@9.0.0: {}
-
js-yaml@4.1.0:
dependencies:
argparse: 2.0.1
jsdoc-type-pratt-parser@4.0.0: {}
- jsdom@24.1.0:
+ jsdoc-type-pratt-parser@4.1.0: {}
+
+ jsdom@25.0.0:
dependencies:
cssstyle: 4.0.1
data-urls: 5.0.0
@@ -4764,9 +4618,9 @@ snapshots:
form-data: 4.0.0
html-encoding-sniffer: 4.0.0
http-proxy-agent: 7.0.2
- https-proxy-agent: 7.0.4
+ https-proxy-agent: 7.0.5
is-potential-custom-element-name: 1.0.1
- nwsapi: 2.2.10
+ nwsapi: 2.2.12
parse5: 7.1.2
rrweb-cssom: 0.7.1
saxes: 6.0.0
@@ -4777,7 +4631,7 @@ snapshots:
whatwg-encoding: 3.1.1
whatwg-mimetype: 4.0.0
whatwg-url: 14.0.0
- ws: 8.17.1
+ ws: 8.18.0
xml-name-validator: 5.0.0
transitivePeerDependencies:
- bufferutil
@@ -4802,10 +4656,10 @@ snapshots:
jsonc-eslint-parser@2.4.0:
dependencies:
- acorn: 8.12.0
+ acorn: 8.12.1
eslint-visitor-keys: 3.4.3
espree: 9.6.1
- semver: 7.6.2
+ semver: 7.6.3
keyv@4.5.4:
dependencies:
@@ -4820,12 +4674,10 @@ snapshots:
lines-and-columns@1.2.4: {}
- local-pkg@0.4.3: {}
-
local-pkg@0.5.0:
dependencies:
mlly: 1.7.1
- pkg-types: 1.1.1
+ pkg-types: 1.1.3
locate-path@5.0.0:
dependencies:
@@ -4835,29 +4687,25 @@ snapshots:
dependencies:
p-locate: 5.0.0
- locate-path@7.2.0:
- dependencies:
- p-locate: 6.0.0
-
lodash.merge@4.6.2: {}
lodash.sortedlastindex@4.1.0: {}
lodash@4.17.21: {}
- loupe@2.3.7:
+ loupe@3.1.1:
dependencies:
get-func-name: 2.0.2
- lru-cache@10.2.2: {}
+ lru-cache@10.4.3: {}
lru-cache@5.1.1:
dependencies:
yallist: 3.1.1
- magic-string@0.30.10:
+ magic-string@0.30.11:
dependencies:
- '@jridgewell/sourcemap-codec': 1.4.15
+ '@jridgewell/sourcemap-codec': 1.5.0
mdast-util-from-markdown@0.8.5:
dependencies:
@@ -4881,7 +4729,7 @@ snapshots:
micromark@2.11.4:
dependencies:
- debug: 4.3.5
+ debug: 4.3.6
parse-entities: 2.0.0
transitivePeerDependencies:
- supports-color
@@ -4897,8 +4745,6 @@ snapshots:
dependencies:
mime-db: 1.52.0
- mimic-fn@2.1.0: {}
-
mimic-fn@4.0.0: {}
min-indent@1.0.1: {}
@@ -4907,15 +4753,11 @@ snapshots:
dependencies:
brace-expansion: 1.1.11
- minimatch@5.1.6:
- dependencies:
- brace-expansion: 2.0.1
-
minimatch@9.0.1:
dependencies:
brace-expansion: 2.0.1
- minimatch@9.0.4:
+ minimatch@9.0.5:
dependencies:
brace-expansion: 2.0.1
@@ -4923,10 +4765,10 @@ snapshots:
mlly@1.7.1:
dependencies:
- acorn: 8.12.0
+ acorn: 8.12.1
pathe: 1.1.2
- pkg-types: 1.1.1
- ufo: 1.5.3
+ pkg-types: 1.1.3
+ ufo: 1.5.4
ms@2.1.2: {}
@@ -4947,7 +4789,7 @@ snapshots:
emojilib: 2.4.0
skin-tone: 2.0.0
- node-releases@2.0.14: {}
+ node-releases@2.0.18: {}
nopt@7.2.1:
dependencies:
@@ -4957,15 +4799,11 @@ snapshots:
dependencies:
hosted-git-info: 2.8.9
resolve: 1.22.8
- semver: 7.6.2
+ semver: 7.6.3
validate-npm-package-license: 3.0.4
normalize-path@3.0.0: {}
- npm-run-path@4.0.1:
- dependencies:
- path-key: 3.1.1
-
npm-run-path@5.3.0:
dependencies:
path-key: 4.0.0
@@ -4974,16 +4812,12 @@ snapshots:
dependencies:
boolbase: 1.0.0
- nwsapi@2.2.10: {}
+ nwsapi@2.2.12: {}
once@1.4.0:
dependencies:
wrappy: 1.0.2
- onetime@5.1.2:
- dependencies:
- mimic-fn: 2.1.0
-
onetime@6.0.0:
dependencies:
mimic-fn: 4.0.0
@@ -5005,14 +4839,6 @@ snapshots:
dependencies:
yocto-queue: 0.1.0
- p-limit@4.0.0:
- dependencies:
- yocto-queue: 1.0.0
-
- p-limit@5.0.0:
- dependencies:
- yocto-queue: 1.0.0
-
p-locate@4.1.0:
dependencies:
p-limit: 2.3.0
@@ -5021,12 +4847,12 @@ snapshots:
dependencies:
p-limit: 3.1.0
- p-locate@6.0.0:
- dependencies:
- p-limit: 4.0.0
-
p-try@2.2.0: {}
+ package-json-from-dist@1.0.0: {}
+
+ package-manager-detector@0.2.0: {}
+
parent-module@1.0.1:
dependencies:
callsites: 3.1.0
@@ -5042,6 +4868,11 @@ snapshots:
parse-gitignore@2.0.0: {}
+ parse-imports@2.1.1:
+ dependencies:
+ es-module-lexer: 1.5.4
+ slashes: 3.0.12
+
parse-json@5.2.0:
dependencies:
'@babel/code-frame': 7.24.7
@@ -5057,8 +4888,6 @@ snapshots:
path-exists@4.0.0: {}
- path-exists@5.0.0: {}
-
path-is-absolute@1.0.1: {}
path-key@3.1.1: {}
@@ -5069,30 +4898,32 @@ snapshots:
path-scurry@1.11.1:
dependencies:
- lru-cache: 10.2.2
+ lru-cache: 10.4.3
minipass: 7.1.2
path-type@4.0.0: {}
pathe@1.1.2: {}
- pathval@1.1.1: {}
+ pathval@2.0.0: {}
picocolors@1.0.1: {}
+ picocolors@1.1.0: {}
+
picomatch@2.3.1: {}
picomatch@4.0.2: {}
- pinia@2.1.7(typescript@5.4.5)(vue@3.4.29(typescript@5.4.5)):
+ pinia@2.2.1(typescript@5.5.4)(vue@3.4.38(typescript@5.5.4)):
dependencies:
'@vue/devtools-api': 6.6.3
- vue: 3.4.29(typescript@5.4.5)
- vue-demi: 0.14.8(vue@3.4.29(typescript@5.4.5))
+ vue: 3.4.38(typescript@5.5.4)
+ vue-demi: 0.14.10(vue@3.4.38(typescript@5.5.4))
optionalDependencies:
- typescript: 5.4.5
+ typescript: 5.5.4
- pkg-types@1.1.1:
+ pkg-types@1.1.3:
dependencies:
confbox: 0.1.7
mlly: 1.7.1
@@ -5100,30 +4931,41 @@ snapshots:
pluralize@8.0.0: {}
- postcss-safe-parser@6.0.0(postcss@8.4.38):
+ postcss-safe-parser@6.0.0(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
- postcss-scss@4.0.9(postcss@8.4.38):
+ postcss-scss@4.0.9(postcss@8.4.40):
dependencies:
- postcss: 8.4.38
+ postcss: 8.4.40
- postcss-selector-parser@6.1.0:
+ postcss-selector-parser@6.1.1:
+ dependencies:
+ cssesc: 3.0.0
+ util-deprecate: 1.0.2
+
+ postcss-selector-parser@6.1.2:
dependencies:
cssesc: 3.0.0
util-deprecate: 1.0.2
postcss-styl@0.12.3:
dependencies:
- debug: 4.3.5
+ debug: 4.3.6
fast-diff: 1.3.0
lodash.sortedlastindex: 4.1.0
- postcss: 8.4.38
+ postcss: 8.4.40
stylus: 0.57.0
transitivePeerDependencies:
- supports-color
- postcss@8.4.38:
+ postcss@8.4.40:
+ dependencies:
+ nanoid: 3.3.7
+ picocolors: 1.0.1
+ source-map-js: 1.2.0
+
+ postcss@8.4.41:
dependencies:
nanoid: 3.3.7
picocolors: 1.0.1
@@ -5131,13 +4973,7 @@ snapshots:
prelude-ls@1.2.1: {}
- prettier@3.3.2: {}
-
- pretty-format@29.7.0:
- dependencies:
- '@jest/schemas': 29.6.3
- ansi-styles: 5.2.0
- react-is: 18.3.1
+ prettier@3.3.3: {}
prismjs@1.29.0: {}
@@ -5151,8 +4987,6 @@ snapshots:
queue-microtask@1.2.3: {}
- react-is@18.3.1: {}
-
read-pkg-up@7.0.1:
dependencies:
find-up: 4.1.0
@@ -5172,13 +5006,13 @@ snapshots:
refa@0.12.1:
dependencies:
- '@eslint-community/regexpp': 4.10.1
+ '@eslint-community/regexpp': 4.11.0
regenerator-runtime@0.14.1: {}
regexp-ast-analysis@0.7.1:
dependencies:
- '@eslint-community/regexpp': 4.10.1
+ '@eslint-community/regexpp': 4.11.0
refa: 0.12.1
regexp-tree@0.1.27: {}
@@ -5187,10 +5021,10 @@ snapshots:
dependencies:
jsesc: 0.5.0
- replace-in-file@7.2.0:
+ replace-in-file@8.1.0:
dependencies:
- chalk: 4.1.2
- glob: 8.1.0
+ chalk: 5.3.0
+ glob: 10.4.5
yargs: 17.7.2
require-directory@2.1.1: {}
@@ -5203,32 +5037,32 @@ snapshots:
resolve@1.22.8:
dependencies:
- is-core-module: 2.13.1
+ is-core-module: 2.15.0
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
reusify@1.0.4: {}
- rollup@4.18.0:
+ rollup@4.20.0:
dependencies:
'@types/estree': 1.0.5
optionalDependencies:
- '@rollup/rollup-android-arm-eabi': 4.18.0
- '@rollup/rollup-android-arm64': 4.18.0
- '@rollup/rollup-darwin-arm64': 4.18.0
- '@rollup/rollup-darwin-x64': 4.18.0
- '@rollup/rollup-linux-arm-gnueabihf': 4.18.0
- '@rollup/rollup-linux-arm-musleabihf': 4.18.0
- '@rollup/rollup-linux-arm64-gnu': 4.18.0
- '@rollup/rollup-linux-arm64-musl': 4.18.0
- '@rollup/rollup-linux-powerpc64le-gnu': 4.18.0
- '@rollup/rollup-linux-riscv64-gnu': 4.18.0
- '@rollup/rollup-linux-s390x-gnu': 4.18.0
- '@rollup/rollup-linux-x64-gnu': 4.18.0
- '@rollup/rollup-linux-x64-musl': 4.18.0
- '@rollup/rollup-win32-arm64-msvc': 4.18.0
- '@rollup/rollup-win32-ia32-msvc': 4.18.0
- '@rollup/rollup-win32-x64-msvc': 4.18.0
+ '@rollup/rollup-android-arm-eabi': 4.20.0
+ '@rollup/rollup-android-arm64': 4.20.0
+ '@rollup/rollup-darwin-arm64': 4.20.0
+ '@rollup/rollup-darwin-x64': 4.20.0
+ '@rollup/rollup-linux-arm-gnueabihf': 4.20.0
+ '@rollup/rollup-linux-arm-musleabihf': 4.20.0
+ '@rollup/rollup-linux-arm64-gnu': 4.20.0
+ '@rollup/rollup-linux-arm64-musl': 4.20.0
+ '@rollup/rollup-linux-powerpc64le-gnu': 4.20.0
+ '@rollup/rollup-linux-riscv64-gnu': 4.20.0
+ '@rollup/rollup-linux-s390x-gnu': 4.20.0
+ '@rollup/rollup-linux-x64-gnu': 4.20.0
+ '@rollup/rollup-linux-x64-musl': 4.20.0
+ '@rollup/rollup-win32-arm64-msvc': 4.20.0
+ '@rollup/rollup-win32-ia32-msvc': 4.20.0
+ '@rollup/rollup-win32-x64-msvc': 4.20.0
fsevents: 2.3.3
rrweb-cssom@0.6.0: {}
@@ -5249,11 +5083,11 @@ snapshots:
scslre@0.3.0:
dependencies:
- '@eslint-community/regexpp': 4.10.1
+ '@eslint-community/regexpp': 4.11.0
refa: 0.12.1
regexp-ast-analysis: 0.7.1
- semver@7.6.2: {}
+ semver@7.6.3: {}
shebang-command@2.0.0:
dependencies:
@@ -5263,10 +5097,10 @@ snapshots:
siginfo@2.0.0: {}
- signal-exit@3.0.7: {}
-
signal-exit@4.1.0: {}
+ simple-icons@13.5.0: {}
+
sisteransi@1.0.5: {}
skin-tone@2.0.0:
@@ -5275,6 +5109,8 @@ snapshots:
slash@3.0.0: {}
+ slashes@3.0.12: {}
+
source-map-js@1.2.0: {}
source-map-resolve@0.6.0:
@@ -5305,12 +5141,12 @@ snapshots:
spdx-license-ids@3.0.18: {}
+ stable-hash@0.0.4: {}
+
stackback@0.0.2: {}
std-env@3.7.0: {}
- string-argv@0.3.2: {}
-
string-width@4.2.3:
dependencies:
emoji-regex: 8.0.0
@@ -5331,8 +5167,6 @@ snapshots:
dependencies:
ansi-regex: 6.0.1
- strip-final-newline@2.0.0: {}
-
strip-final-newline@3.0.0: {}
strip-indent@3.0.0:
@@ -5341,14 +5175,10 @@ snapshots:
strip-json-comments@3.1.1: {}
- strip-literal@2.1.0:
- dependencies:
- js-tokens: 9.0.0
-
stylus@0.57.0:
dependencies:
css: 3.0.0
- debug: 4.3.5
+ debug: 4.3.6
glob: 7.2.3
safer-buffer: 2.1.2
sax: 1.2.4
@@ -5382,7 +5212,7 @@ snapshots:
dependencies:
tslib: 2.6.3
- synckit@0.9.0:
+ synckit@0.9.1:
dependencies:
'@pkgr/core': 0.1.1
tslib: 2.6.3
@@ -5391,13 +5221,17 @@ snapshots:
text-table@0.2.0: {}
- tinybench@2.8.0: {}
+ tinybench@2.9.0: {}
tinycolor2@1.6.0: {}
- tinypool@0.8.4: {}
+ tinyexec@0.3.0: {}
- tinyspy@2.2.1: {}
+ tinypool@1.0.0: {}
+
+ tinyrainbow@1.2.0: {}
+
+ tinyspy@3.0.0: {}
to-fast-properties@2.0.0: {}
@@ -5405,7 +5239,7 @@ snapshots:
dependencies:
is-number: 7.0.0
- toml-eslint-parser@0.9.3:
+ toml-eslint-parser@0.10.0:
dependencies:
eslint-visitor-keys: 3.4.3
@@ -5420,9 +5254,9 @@ snapshots:
dependencies:
punycode: 2.3.1
- ts-api-utils@1.3.0(typescript@5.4.5):
+ ts-api-utils@1.3.0(typescript@5.5.4):
dependencies:
- typescript: 5.4.5
+ typescript: 5.5.4
tslib@2.6.3: {}
@@ -5430,85 +5264,42 @@ snapshots:
dependencies:
prelude-ls: 1.2.1
- type-detect@4.0.8: {}
-
type-fest@0.20.2: {}
type-fest@0.6.0: {}
type-fest@0.8.1: {}
- typescript-eslint@7.13.1(eslint@9.5.0)(typescript@5.4.5):
- dependencies:
- '@typescript-eslint/eslint-plugin': 7.13.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint@9.5.0)(typescript@5.4.5)
- '@typescript-eslint/parser': 7.13.1(eslint@9.5.0)(typescript@5.4.5)
- '@typescript-eslint/utils': 7.13.1(eslint@9.5.0)(typescript@5.4.5)
- eslint: 9.5.0
- optionalDependencies:
- typescript: 5.4.5
- transitivePeerDependencies:
- - supports-color
+ typescript@5.5.4: {}
- typescript@5.4.5: {}
-
- ufo@1.5.3: {}
+ ufo@1.5.4: {}
undici-types@5.26.5: {}
unicode-emoji-modifier-base@1.0.0: {}
- unicorn-magic@0.1.0: {}
-
unist-util-stringify-position@2.0.3:
dependencies:
- '@types/unist': 2.0.10
+ '@types/unist': 2.0.11
universalify@0.2.0: {}
- unplugin-icons@0.18.5(@vue/compiler-sfc@3.4.29)(vue-template-compiler@2.7.16):
+ unplugin@1.12.0:
dependencies:
- '@antfu/install-pkg': 0.3.3
- '@antfu/utils': 0.7.8
- '@iconify/utils': 2.1.24
- debug: 4.3.5
- kolorist: 1.8.0
- local-pkg: 0.5.0
- unplugin: 1.10.1
- optionalDependencies:
- '@vue/compiler-sfc': 3.4.29
- vue-template-compiler: 2.7.16
- transitivePeerDependencies:
- - supports-color
-
- unplugin-vue-components@0.26.0(@babel/parser@7.24.7)(rollup@4.18.0)(vue@3.4.29(typescript@5.4.5)):
- dependencies:
- '@antfu/utils': 0.7.8
- '@rollup/pluginutils': 5.1.0(rollup@4.18.0)
- chokidar: 3.6.0
- debug: 4.3.5
- fast-glob: 3.3.2
- local-pkg: 0.4.3
- magic-string: 0.30.10
- minimatch: 9.0.4
- resolve: 1.22.8
- unplugin: 1.10.1
- vue: 3.4.29(typescript@5.4.5)
- optionalDependencies:
- '@babel/parser': 7.24.7
- transitivePeerDependencies:
- - rollup
- - supports-color
-
- unplugin@1.10.1:
- dependencies:
- acorn: 8.12.0
+ acorn: 8.12.1
chokidar: 3.6.0
webpack-sources: 3.2.3
webpack-virtual-modules: 0.6.2
- update-browserslist-db@1.0.16(browserslist@4.23.1):
+ update-browserslist-db@1.1.0(browserslist@4.23.2):
dependencies:
- browserslist: 4.23.1
+ browserslist: 4.23.2
+ escalade: 3.1.2
+ picocolors: 1.0.1
+
+ update-browserslist-db@1.1.0(browserslist@4.23.3):
+ dependencies:
+ browserslist: 4.23.3
escalade: 3.1.2
picocolors: 1.0.1
@@ -5528,18 +5319,19 @@ snapshots:
spdx-correct: 3.2.0
spdx-expression-parse: 3.0.1
- vite-node@1.6.0(@types/node@20.14.5)(stylus@0.57.0):
+ vite-node@2.0.5(@types/node@20.14.15)(stylus@0.57.0):
dependencies:
cac: 6.7.14
- debug: 4.3.5
+ debug: 4.3.6
pathe: 1.1.2
- picocolors: 1.0.1
- vite: 5.3.1(@types/node@20.14.5)(stylus@0.57.0)
+ tinyrainbow: 1.2.0
+ vite: 5.4.1(@types/node@20.14.15)(stylus@0.57.0)
transitivePeerDependencies:
- '@types/node'
- less
- lightningcss
- sass
+ - sass-embedded
- stylus
- sugarss
- supports-color
@@ -5547,66 +5339,66 @@ snapshots:
vite-plugin-prismjs@0.0.11(prismjs@1.29.0):
dependencies:
- '@babel/core': 7.24.7
+ '@babel/core': 7.25.2
babel-plugin-prismjs: 2.1.0(prismjs@1.29.0)
transitivePeerDependencies:
- prismjs
- supports-color
- vite-plugin-windicss@1.9.3(vite@5.3.1(@types/node@20.14.5)(stylus@0.57.0)):
+ vite-plugin-windicss@1.9.3(vite@5.4.1(@types/node@20.14.15)(stylus@0.57.0)):
dependencies:
'@windicss/plugin-utils': 1.9.3
- debug: 4.3.5
+ debug: 4.3.6
kolorist: 1.8.0
- vite: 5.3.1(@types/node@20.14.5)(stylus@0.57.0)
+ vite: 5.4.1(@types/node@20.14.15)(stylus@0.57.0)
windicss: 3.5.6
transitivePeerDependencies:
- supports-color
- vite-svg-loader@5.1.0(vue@3.4.29(typescript@5.4.5)):
+ vite-svg-loader@5.1.0(vue@3.4.38(typescript@5.5.4)):
dependencies:
svgo: 3.3.2
- vue: 3.4.29(typescript@5.4.5)
+ vue: 3.4.38(typescript@5.5.4)
- vite@5.3.1(@types/node@20.14.5)(stylus@0.57.0):
+ vite@5.4.1(@types/node@20.14.15)(stylus@0.57.0):
dependencies:
esbuild: 0.21.5
- postcss: 8.4.38
- rollup: 4.18.0
+ postcss: 8.4.41
+ rollup: 4.20.0
optionalDependencies:
- '@types/node': 20.14.5
+ '@types/node': 20.14.15
fsevents: 2.3.3
stylus: 0.57.0
- vitest@1.6.0(@types/node@20.14.5)(jsdom@24.1.0)(stylus@0.57.0):
+ vitest@2.0.5(@types/node@20.14.15)(jsdom@25.0.0)(stylus@0.57.0):
dependencies:
- '@vitest/expect': 1.6.0
- '@vitest/runner': 1.6.0
- '@vitest/snapshot': 1.6.0
- '@vitest/spy': 1.6.0
- '@vitest/utils': 1.6.0
- acorn-walk: 8.3.3
- chai: 4.4.1
- debug: 4.3.5
+ '@ampproject/remapping': 2.3.0
+ '@vitest/expect': 2.0.5
+ '@vitest/pretty-format': 2.0.5
+ '@vitest/runner': 2.0.5
+ '@vitest/snapshot': 2.0.5
+ '@vitest/spy': 2.0.5
+ '@vitest/utils': 2.0.5
+ chai: 5.1.1
+ debug: 4.3.6
execa: 8.0.1
- local-pkg: 0.5.0
- magic-string: 0.30.10
+ magic-string: 0.30.11
pathe: 1.1.2
- picocolors: 1.0.1
std-env: 3.7.0
- strip-literal: 2.1.0
- tinybench: 2.8.0
- tinypool: 0.8.4
- vite: 5.3.1(@types/node@20.14.5)(stylus@0.57.0)
- vite-node: 1.6.0(@types/node@20.14.5)(stylus@0.57.0)
- why-is-node-running: 2.2.2
+ tinybench: 2.9.0
+ tinypool: 1.0.0
+ tinyrainbow: 1.2.0
+ vite: 5.4.1(@types/node@20.14.15)(stylus@0.57.0)
+ vite-node: 2.0.5(@types/node@20.14.15)(stylus@0.57.0)
+ why-is-node-running: 2.3.0
optionalDependencies:
- '@types/node': 20.14.5
- jsdom: 24.1.0
+ '@types/node': 20.14.15
+ jsdom: 25.0.0
transitivePeerDependencies:
- less
- lightningcss
- sass
+ - sass-embedded
- stylus
- sugarss
- supports-color
@@ -5614,58 +5406,53 @@ snapshots:
vscode-uri@3.0.8: {}
- vue-component-type-helpers@2.0.21: {}
+ vue-component-type-helpers@2.0.29: {}
- vue-demi@0.14.8(vue@3.4.29(typescript@5.4.5)):
+ vue-demi@0.14.10(vue@3.4.38(typescript@5.5.4)):
dependencies:
- vue: 3.4.29(typescript@5.4.5)
+ vue: 3.4.38(typescript@5.5.4)
- vue-eslint-parser@9.4.3(eslint@9.5.0):
+ vue-eslint-parser@9.4.3(eslint@9.9.0(jiti@1.21.6)):
dependencies:
- debug: 4.3.5
- eslint: 9.5.0
+ debug: 4.3.6
+ eslint: 9.9.0(jiti@1.21.6)
eslint-scope: 7.2.2
eslint-visitor-keys: 3.4.3
espree: 9.6.1
- esquery: 1.5.0
+ esquery: 1.6.0
lodash: 4.17.21
- semver: 7.6.2
+ semver: 7.6.3
transitivePeerDependencies:
- supports-color
- vue-i18n@9.13.1(vue@3.4.29(typescript@5.4.5)):
+ vue-i18n@9.13.1(vue@3.4.38(typescript@5.5.4)):
dependencies:
'@intlify/core-base': 9.13.1
'@intlify/shared': 9.13.1
'@vue/devtools-api': 6.6.3
- vue: 3.4.29(typescript@5.4.5)
+ vue: 3.4.38(typescript@5.5.4)
- vue-router@4.3.3(vue@3.4.29(typescript@5.4.5)):
+ vue-router@4.4.3(vue@3.4.38(typescript@5.5.4)):
dependencies:
'@vue/devtools-api': 6.6.3
- vue: 3.4.29(typescript@5.4.5)
+ vue: 3.4.38(typescript@5.5.4)
- vue-template-compiler@2.7.16:
+ vue-tsc@2.0.29(typescript@5.5.4):
dependencies:
- de-indent: 1.0.2
- he: 1.2.0
+ '@volar/typescript': 2.4.0-alpha.18
+ '@vue/language-core': 2.0.29(typescript@5.5.4)
+ semver: 7.6.3
+ typescript: 5.5.4
- vue-tsc@2.0.21(typescript@5.4.5):
+ vue@3.4.38(typescript@5.5.4):
dependencies:
- '@volar/typescript': 2.3.0
- '@vue/language-core': 2.0.21(typescript@5.4.5)
- semver: 7.6.2
- typescript: 5.4.5
-
- vue@3.4.29(typescript@5.4.5):
- dependencies:
- '@vue/compiler-dom': 3.4.29
- '@vue/compiler-sfc': 3.4.29
- '@vue/runtime-dom': 3.4.29
- '@vue/server-renderer': 3.4.29(vue@3.4.29(typescript@5.4.5))
- '@vue/shared': 3.4.29
+ '@vue/compiler-dom': 3.4.38
+ '@vue/compiler-sfc': 3.4.38
+ '@vue/runtime-dom': 3.4.38
+ '@vue/server-renderer': 3.4.38(vue@3.4.38(typescript@5.5.4))
+ '@vue/shared': 3.4.38
optionalDependencies:
- typescript: 5.4.5
+ typescript: 5.5.4
w3c-xmlserializer@5.0.0:
dependencies:
@@ -5692,7 +5479,7 @@ snapshots:
dependencies:
isexe: 2.0.0
- why-is-node-running@2.2.2:
+ why-is-node-running@2.3.0:
dependencies:
siginfo: 2.0.0
stackback: 0.0.2
@@ -5715,7 +5502,7 @@ snapshots:
wrappy@1.0.2: {}
- ws@8.17.1: {}
+ ws@8.18.0: {}
xml-name-validator@4.0.0: {}
@@ -5731,9 +5518,9 @@ snapshots:
dependencies:
eslint-visitor-keys: 3.4.3
lodash: 4.17.21
- yaml: 2.4.5
+ yaml: 2.5.0
- yaml@2.4.5: {}
+ yaml@2.5.0: {}
yargs-parser@21.1.1: {}
@@ -5748,5 +5535,3 @@ snapshots:
yargs-parser: 21.1.1
yocto-queue@0.1.0: {}
-
- yocto-queue@1.0.0: {}
diff --git a/web/src/App.vue b/web/src/App.vue
index 90a04d174..98e0ffb41 100644
--- a/web/src/App.vue
+++ b/web/src/App.vue
@@ -31,7 +31,7 @@ const apiClient = useApiClient();
const { notify } = useNotifications();
const i18n = useI18n();
-// TODO reenable with eslint-plugin-promise eslint-disable-next-line promise/prefer-await-to-callbacks
+// eslint-disable-next-line promise/prefer-await-to-callbacks
apiClient.setErrorHandler((err) => {
if (err.status === 404) {
notify({ title: i18n.t('errors.not_found'), type: 'error' });
diff --git a/web/src/assets/locales/de.json b/web/src/assets/locales/de.json
index 2dc204168..e12719419 100644
--- a/web/src/assets/locales/de.json
+++ b/web/src/assets/locales/de.json
@@ -3,7 +3,7 @@
"settings": {
"agents": {
"add": "Agent hinzufügen",
- "agents": "Agents",
+ "agents": "Agenten",
"backend": {
"backend": "Backend",
"badge": "Backend"
@@ -17,36 +17,36 @@
"delete_agent": "Agent löschen",
"delete_confirm": "Wollen Sie diesen Agent wirklich löschen? Dieser kann sich dann nicht mehr mit dem Server verbinden.",
"deleted": "Agent gelöscht",
- "desc": "Für diesen Server registrierte Agents",
+ "desc": "Für diesen Server registrierte Agenten.",
"edit_agent": "Agent bearbeiten",
"id": "ID",
"last_contact": "Letzter Kontakt",
"name": {
"name": "Name",
- "placeholder": "Name des Agents"
+ "placeholder": "Name des Agenten"
},
"never": "Nie",
"no_schedule": {
"name": "Agent deaktivieren",
"placeholder": "Agent daran hindern, neue Aufgaben zu nehmen"
},
- "none": "Es gibt noch keine Agents.",
+ "none": "Es gibt noch keine Agenten.",
"platform": {
"badge": "Plattform",
"platform": "Plattform"
},
"save": "Agent speichern",
"saved": "Agent gespeichert",
- "show": "Agents anzeigen",
+ "show": "Agenten anzeigen",
"token": "Schlüssel",
"version": "Version"
},
- "not_allowed": "Du darfst nicht auf die Server-Einstellungen zugreifen",
+ "not_allowed": "Du darfst nicht auf die Server-Einstellungen zugreifen.",
"orgs": {
"delete_confirm": "Möchtest du diese Organisation wirklich löschen? Das wird auch alle Repositorys löschen, die dieser Organisation gehören.",
"delete_org": "Organisation löschen",
"deleted": "Organisation gelöscht",
- "desc": "Organisationen mit Repositorys auf diesem Server",
+ "desc": "Organisationen, die Repositorys auf diesem Server besitzen.",
"none": "Es gibt noch keine Organisationen.",
"org_settings": "Organisations-Einstellungen",
"orgs": "Organisationen",
@@ -54,7 +54,7 @@
},
"queue": {
"agent": "Agent",
- "desc": "Aufgaben, die darauf warten, von Agents ausgeführt zu werden",
+ "desc": "Aufgaben, die darauf warten, von Agenten ausgeführt zu werden",
"pause": "Pausieren",
"paused": "Warteschlange wurde pausiert",
"queue": "Warteschlange",
@@ -74,7 +74,7 @@
"waiting_for": "wartet auf"
},
"repos": {
- "desc": "Repositorys, die auf dem Server aktiviert sind oder waren",
+ "desc": "Repositorys, die auf dem Server aktiviert sind oder waren.",
"disabled": "Deaktiviert",
"none": "Es gibt noch keine Repositorys.",
"repair": {
@@ -89,7 +89,7 @@
"add": "Geheimnis hinzufügen",
"created": "Globales Geheimnis erstellt",
"deleted": "Globales Geheimnis gelöscht",
- "desc": "Globale Geheimnisse können an alle Repositorys als Umgebungsvariablen übergeben werden.",
+ "desc": "Globale Geheimnisse können an Pipelineschritte aller Repositorys als Umgebungsvariablen übergeben werden.",
"events": {
"events": "Verfügbar für folgende Ereignisse",
"pr_warning": "Bitte sei vorsichtig mit dieser Option, da eine böswillige Person über einen Pull-Request deine Geheimnisse erhalten könnte."
@@ -106,7 +106,7 @@
"secrets": "Geheimnisse",
"show": "Geheimnisse anzeigen",
"value": "Wert",
- "warning": "Diese Geheimnisse können von allen Nutzern des Server eingesehen werden."
+ "warning": "Diese Geheimnisse können von allen Nutzern eingesehen werden."
},
"settings": "Einstellungen",
"users": {
@@ -130,6 +130,10 @@
"saved": "Benutzer gespeichert",
"show": "Benutzer anzeigen",
"users": "Benutzer"
+ },
+ "registries": {
+ "desc": "Globale Register-Zugangsdaten können für private Images aller Pipelines verwendet werden.",
+ "warning": "Diese Register-Zugangsdaten sind für alle Benutzer verfügbar."
}
}
},
@@ -158,7 +162,7 @@
"add": "Geheimnis hinzufügen",
"created": "Organisations-Geheimnis erstellt",
"deleted": "Organisations-Geheimnis gelöscht",
- "desc": "Organisation-Geheimnisse können an alle Repositorys der Organisation als Umgebungsvariablen übergeben werden.",
+ "desc": "Organisation-Geheimnisse können an alle Pipelineschritte in Repositorys der Organisation als Umgebungsvariablen übergeben werden.",
"events": {
"events": "Verfügbar für folgende Ereignisse",
"pr_warning": "Bitte sei vorsichtig mit dieser Option, da eine böswillige Person über einen Pull-Request deine Geheimnisse erhalten könnte."
@@ -176,7 +180,10 @@
"show": "Geheimnisse anzeigen",
"value": "Wert"
},
- "settings": "Einstellungen"
+ "settings": "Einstellungen",
+ "registries": {
+ "desc": "Register-Zugangsdaten der Organisation können für private Images aller Organisations-Pipelines verwendet werden."
+ }
}
},
"org_level_secret": "Organisationsgeheimnis",
@@ -219,7 +226,8 @@
"title": "Zusätzliche Pipeline-Variablen",
"value": "Variablenwert",
"delete": "Variable löschen"
- }
+ },
+ "show_pipelines": "Pipelines anzeigen"
},
"not_allowed": "Zugriff auf dieses Repository nicht erlaubt",
"open_in_forge": "Repository in der Forge öffnen",
@@ -245,7 +253,8 @@
"pr": "Pull-Request",
"push": "Push",
"tag": "Tag",
- "release": "Release"
+ "release": "Release",
+ "pr_closed": "Pull-Request zusammengeführt/geschlossen"
},
"exit_code": "Exit-Code {exitCode}",
"files": "Geänderte Dateien ({files})",
@@ -286,7 +295,10 @@
"warnings": "Warnungen ({count})",
"we_got_some_errors": "Oh nein, es gab einige Fehler!",
"log_delete_confirm": "Möchtest du die Logs diesen Schrittes wirklich löschen?",
- "log_delete_error": "Es gab einen Fehler beim Löschen der Logs des Schrittes"
+ "log_delete_error": "Es gab einen Fehler beim Löschen der Logs des Schrittes",
+ "duration": "Pipeline-Dauer",
+ "created": "Erstellt: {created}",
+ "no_logs": "Keine Logs"
},
"pull_requests": "Pull-Requests",
"settings": {
@@ -335,7 +347,7 @@
"placeholder": "Name des Cron"
},
"next_exec": "Nächste Ausführung",
- "none": "Derzeit existieren keine Crons.",
+ "none": "Es gibt noch keine Crons.",
"not_executed_yet": "Noch nicht ausgeführt",
"run": "Jetzt ausführen",
"save": "Cron speichern",
@@ -378,7 +390,7 @@
"timeout": "Zeitlimit"
},
"trusted": {
- "desc": "Die zugrundeliegenden Pipeline-Container erhalten Zugriff auf ausgeweitete Funktionen wie z. B. das Einhängen von Volumes.",
+ "desc": "Die zugrundeliegenden Pipeline-Container erhalten Zugriff auf ausgeweitete Funktionen (z. B. das Einhängen von Laufwerken).",
"trusted": "Vertrauenswürdig"
},
"visibility": {
@@ -496,7 +508,7 @@
"add": "Geheimnis hinzufügen",
"created": "Benutzer-Geheimnis erstellt",
"deleted": "Benutzer-Geheimnis gelöscht",
- "desc": "Benutzer-Geheimnisse können an alle Repositorys des Benutzers als Umgebungsvariablen übergeben werden.",
+ "desc": "Benutzer-Geheimnisse können an alle persönlichen Pipelineschritte als Umgebungsvariablen übergeben werden.",
"events": {
"events": "Verfügbar für folgende Ereignisse",
"pr_warning": "Bitte sei vorsichtig mit dieser Option, da eine böswillige Person über einen Pull-Request deine Geheimnisse erhalten könnte."
@@ -524,13 +536,16 @@
"swagger_ui": "Swagger-UI",
"cli_and_api": "CLI/API",
"cli_usage": "Beispiel zur Nutzung des CLI"
+ },
+ "registries": {
+ "desc": "Register-Zugangsdaten des Benutzers können für private Images aller persönlichen Pipelines verwendet werden."
}
}
},
"username": "Benutzername",
"welcome": "Willkommen bei Woodpecker",
"login_to_cli": "In CLI anmelden",
- "login_to_cli_description": "Wenn du fortfährst, wirst bei im CLI angemeldet.",
+ "login_to_cli_description": "Wenn du fortfährst, wirst du im CLI angemeldet.",
"abort": "Abbrechen",
"cli_login_success": "Anmelden im CLI erfolgreich",
"cli_login_failed": "Anmelden im CLI fehlgeschlagen",
@@ -538,7 +553,7 @@
"return_to_cli": "Du kannst diesen Tab jetzt schließen und zur CLI zurückkehren.",
"secrets": {
"secrets": "Geheimnisse",
- "desc": "Geheimnisse können zur Laufzeit als Umgebungsvariablen an einzelne Pipelineschritte übergeben werden.",
+ "desc": "Geheimnisse können als Umgebungsvariablen an einzelne Pipelineschritte übergeben werden.",
"none": "Es gibt noch keine Geheimnisse.",
"add": "Geheimnis hinzufügen",
"save": "Geheimnis speichern",
@@ -550,16 +565,56 @@
"created": "Geheimnis erstellt",
"saved": "Geheimnis gespeichert",
"images": {
- "images": "Verfügbar für folgende Images",
- "desc": "Liste der Images, für die dieses Geheimnis verfügbar ist; leer lassen, um alle Images zuzulassen"
+ "images": "Verfügbar für die folgenden Images",
+ "desc": "Liste der Images, für die dieses Geheimnis verfügbar ist; leer lassen, um für alle Images zuzulassen."
},
"events": {
- "events": "Verfügbar bei folgenden Ereignissen",
- "pr_warning": "Bitte sei vorsichtig mit dieser Option, da eine böswillige Person über einen Pull-Request deine Geheimnisse erhalten könnte."
+ "events": "Verfügbar bei den folgenden Ereignissen",
+ "pr_warning": "Bitte sei vorsichtig mit dieser Option: Eine böswillige Person könnte über einen Pull-Request deine Geheimnisse erhalten."
},
"plugins_only": "Nur für Plugins verfügbar",
"edit": "Geheimnis bearbeiten",
- "delete": "Geheimnis löschen"
+ "delete": "Geheimnis löschen",
+ "plugins": {
+ "images": "Nur für die folgenden Plugins verfügbar",
+ "desc": "Liste aller Plugin-Images, für die dieses Geheimnis verwendet werden kann. Freilassen, um alle Plugins und allgemeine Schritte zu erlauben."
+ }
},
- "settings": "Einstellungen"
+ "settings": "Einstellungen",
+ "oauth_error": "Fehler bei der Authentifizierung mit OAuth-Anbieter",
+ "internal_error": "Ein interner Fehler ist aufgetreten",
+ "registration_closed": "Die Registrierung ist geschlossen",
+ "access_denied": "Du darfst nicht auf diese Instanz zugreifen",
+ "registries": {
+ "delete_confirm": "Möchtest du dieses Register wirklich löschen?",
+ "address": {
+ "desc": "Register-Adresse (z. B. docker.io)",
+ "address": "Adresse"
+ },
+ "credentials": "Register-Zugangsdaten",
+ "none": "Es gibt noch keine Register-Zugangsdaten.",
+ "registries": "Register",
+ "desc": "Register-Zugangsdaten können für private Images in Pipelines verwendet werden.",
+ "deleted": "Register-Zugangsdaten gelöscht",
+ "save": "Register speichern",
+ "add": "Register hinzufügen",
+ "view": "Register anzeigen",
+ "edit": "Register bearbeiten",
+ "delete": "Register löschen",
+ "created": "Register-Zugangsdaten erstellt",
+ "saved": "Register-Zugangsdaten gespeichert",
+ "show": "Register anzeigen"
+ },
+ "invalid_state": "Der OAuth-Status ist ungültig.",
+ "by_user": "von {user}",
+ "pushed_to": "gepusht auf",
+ "closed": "geschlossen",
+ "deployed_to": "Deployment ausgeführt auf",
+ "created": "erstellt",
+ "triggered": "ausgelöst",
+ "pipeline_duration": "Pipeline-Dauer",
+ "pipeline_since": "Die Pipeline wurde vor {created} Minuten erstellt",
+ "pipeline_has_warnings": "Die Pipeline hat Warnungen",
+ "pipeline_has_errors": "Die Pipeline hat Fehler",
+ "login_with": "Mit {forge} anmelden"
}
diff --git a/web/src/assets/locales/en.json b/web/src/assets/locales/en.json
index 41ba7dd17..d5d586f41 100644
--- a/web/src/assets/locales/en.json
+++ b/web/src/assets/locales/en.json
@@ -1,5 +1,6 @@
{
"cancel": "Cancel",
+ "login_with": "Login with {forge}",
"login": "Login",
"welcome": "Welcome to Woodpecker",
"repos": "Repos",
@@ -37,7 +38,8 @@
"desc": "Specify additional variables to use in your pipeline. Variables with the same name will be overwritten.",
"name": "Variable name",
"value": "Variable value"
- }
+ },
+ "show_pipelines": "Show pipelines"
},
"deploy_pipeline": {
"title": "Trigger deployment event for current pipeline #{pipelineId}",
@@ -96,7 +98,7 @@
},
"trusted": {
"trusted": "Trusted",
- "desc": "Underlying pipeline containers get access to escalated capabilities like mounting volumes."
+ "desc": "Underlying pipeline containers get access to escalated capabilities (like mounting volumes)."
},
"visibility": {
"visibility": "Project visibility",
@@ -122,24 +124,6 @@
"desc": "Enable to cancel pending and running pipelines of the same event and context before starting the newly triggered one."
}
},
- "registries": {
- "registries": "Registries",
- "credentials": "Registry credentials",
- "desc": "Registries credentials can be added to use private images for your pipeline.",
- "show": "Show registries",
- "add": "Add registry",
- "none": "There are no registry credentials yet.",
- "save": "Save registry",
- "created": "Registry credentials created",
- "saved": "Registry credentials saved",
- "deleted": "Registry credentials deleted",
- "address": {
- "address": "Address",
- "placeholder": "Registry Address (e.g. docker.io)"
- },
- "edit": "Edit registry",
- "delete": "Delete registry"
- },
"crons": {
"crons": "Crons",
"desc": "Cron jobs can be used to trigger pipelines on a regular basis.",
@@ -208,6 +192,7 @@
"pipelines_for_pr": "Pipelines for pull request #{index}",
"exit_code": "Exit Code {exitCode}",
"loading": "Loading…",
+ "no_logs": "No logs",
"pipeline": "Pipeline #{pipelineId}",
"log_title": "Step Logs",
"log_download_error": "There was an error while downloading the log file",
@@ -237,6 +222,7 @@
"push": "Push",
"tag": "Tag",
"pr": "Pull Request",
+ "pr_closed": "Pull Request merged / closed",
"deploy": "Deploy",
"cron": "Cron",
"manual": "Manual",
@@ -258,27 +244,36 @@
"errors": "Errors ({count})",
"warnings": "Warnings ({count})",
"show_errors": "Show errors",
- "we_got_some_errors": "Oh no, we got some errors!"
+ "we_got_some_errors": "Oh no, we got some errors!",
+ "duration": "Pipeline duration",
+ "created": "Created: {created}"
}
},
"org": {
"settings": {
"not_allowed": "You are not allowed to access this organization's settings",
"secrets": {
- "desc": "Organization secrets can be passed to all organization's repository individual pipeline steps at runtime as environmental variables."
+ "desc": "Organization secrets can be passed to all organization's repository's pipeline steps as environmental variables."
+ },
+ "registries": {
+ "desc": "Organization registry credentials can be added to use private images for all pipelines of an organization."
}
}
},
"admin": {
"settings": {
- "not_allowed": "You are not allowed to access server settings",
+ "not_allowed": "You are not allowed to access server settings.",
"secrets": {
- "desc": "Global secrets can be passed to all repositories individual pipeline steps at runtime as environmental variables.",
- "warning": "These secrets will be available for all server users."
+ "desc": "Global secrets can be passed to all repository's pipeline steps as environmental variables.",
+ "warning": "These secrets will be available for all users."
+ },
+ "registries": {
+ "desc": "Global registry credentials can be added to use private images for all pipelines.",
+ "warning": "These registry credentials will be available for all users."
},
"agents": {
"agents": "Agents",
- "desc": "Agents registered for this server",
+ "desc": "Agents registered on this server.",
"none": "There are no agents yet.",
"id": "ID",
"add": "Add agent",
@@ -312,7 +307,7 @@
"version": "Version",
"last_contact": "Last contact",
"never": "Never",
- "delete_confirm": "Do you really want to delete this agent? It wont be able to connected to the server anymore.",
+ "delete_confirm": "Do you really want to delete this agent? It will not be able to connect to the server anymore.",
"edit_agent": "Edit agent",
"delete_agent": "Delete agent"
},
@@ -361,7 +356,7 @@
},
"orgs": {
"orgs": "Organizations",
- "desc": "Organizations owning repositories on this server",
+ "desc": "Organizations owning repositories on this server.",
"none": "There are no organizations yet.",
"org_settings": "Organization settings",
"delete_org": "Delete organization",
@@ -371,7 +366,7 @@
},
"repos": {
"repos": "Repositories",
- "desc": "Repositories that are or were enabled on this server",
+ "desc": "Repositories that are or have been enabled on this server.",
"none": "There are no repositories yet.",
"view": "View repository",
"settings": "Repository settings",
@@ -397,7 +392,10 @@
}
},
"secrets": {
- "desc": "User secrets can be passed to all user's repository individual pipeline steps at runtime as environmental variables."
+ "desc": "User secrets can be passed to personal pipeline steps as environmental variables."
+ },
+ "registries": {
+ "desc": "User registry credentials can be added to use private images for all personal pipelines."
},
"cli_and_api": {
"cli_and_api": "CLI & API",
@@ -413,7 +411,7 @@
},
"secrets": {
"secrets": "Secrets",
- "desc": "Secrets can be passed to individual pipeline steps at runtime as environmental variables.",
+ "desc": "Secrets can be passed to individual pipeline steps as environmental variables.",
"none": "There are no secrets yet.",
"add": "Add secret",
"save": "Save secret",
@@ -424,17 +422,37 @@
"deleted": "Secret deleted",
"created": "Secret created",
"saved": "Secret saved",
- "images": {
- "images": "Available for following images",
- "desc": "List of images where this secret is available, leave empty to allow all images"
+ "plugins": {
+ "images": "Available only for the following plugins",
+ "desc": "List of plugins images where this secret is available, leave empty to allow for all plugins and general steps."
},
"events": {
- "events": "Available at following events",
- "pr_warning": "Please be careful with this option as a bad actor can submit a malicious pull request that exposes your secrets."
+ "events": "Available at the following events",
+ "pr_warning": "Please be careful with this option: a bad actor can submit a malicious pull request that exposes your secrets."
},
"edit": "Edit secret",
"delete": "Delete secret"
},
+ "registries": {
+ "registries": "Registries",
+ "credentials": "Registry credentials",
+ "desc": "Registry credentials can be added to use private images for pipelines.",
+ "none": "There are no registry credentials yet.",
+ "address": {
+ "address": "Address",
+ "desc": "Registry Address (e.g. docker.io)"
+ },
+ "show": "Show registries",
+ "save": "Save registry",
+ "add": "Add registry",
+ "view": "View registry",
+ "edit": "Edit registry",
+ "delete": "Delete registry",
+ "delete_confirm": "Do you really want to delete this registry?",
+ "created": "Registry credentials created",
+ "saved": "Registry credentials saved",
+ "deleted": "Registry credentials deleted"
+ },
"default": "default",
"info": "Info",
"running_version": "You are running Woodpecker {0}",
@@ -442,7 +460,7 @@
"global_level_secret": "global secret",
"org_level_secret": "organization secret",
"login_to_cli": "Login to CLI",
- "login_to_cli_description": "By continuing you will be logged in to the CLI.",
+ "login_to_cli_description": "By continuing you will be logged into the CLI.",
"abort": "Abort",
"cli_login_success": "Login to CLI successful",
"cli_login_failed": "Login to CLI failed",
@@ -452,5 +470,6 @@
"oauth_error": "Error while authenticating against OAuth provider",
"internal_error": "Some internal error occurred",
"registration_closed": "The registration is closed",
- "access_denied": "You are not allowed to access this instance"
+ "access_denied": "You are not allowed to access this instance",
+ "invalid_state": "The OAuth state is invalid"
}
diff --git a/web/src/assets/locales/eo.json b/web/src/assets/locales/eo.json
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/web/src/assets/locales/eo.json
@@ -0,0 +1 @@
+{}
diff --git a/web/src/assets/locales/fr.json b/web/src/assets/locales/fr.json
index 3265bf7f8..b4967efce 100644
--- a/web/src/assets/locales/fr.json
+++ b/web/src/assets/locales/fr.json
@@ -17,7 +17,7 @@
"delete_agent": "Supprimer l'agent",
"delete_confirm": "Voulez vous vraiment supprimer cet agent ? Il ne pourra plus se connecter sur le serveur.",
"deleted": "Agent supprimé",
- "desc": "Agents enregistrés sur ce serveur",
+ "desc": "Agents enregistrés sur ce serveur.",
"edit_agent": "Éditer l'agent",
"id": "ID",
"last_contact": "Dernier contact",
@@ -41,12 +41,12 @@
"token": "Jeton",
"version": "Version"
},
- "not_allowed": "Vous n'êtes pas autorisé à accéder aux réglages du serveur",
+ "not_allowed": "Vous n'êtes pas autorisé à accéder aux réglages du serveur.",
"orgs": {
"delete_confirm": "Voulez-vous vraiment supprimer cette organisation ? Cela supprimera tous les dépôts que possède cette organisation.",
"delete_org": "Supprimer l'organisation",
"deleted": "Organisation supprimée",
- "desc": "Organisations possédant des dépôts sur ce serveur",
+ "desc": "Organisations possédant des dépôts sur ce serveur.",
"none": "Il n'y a pas encore d'organisation.",
"org_settings": "Réglages de l'organisation",
"orgs": "Organisations",
@@ -74,7 +74,7 @@
"waiting_for": "en attente de"
},
"repos": {
- "desc": "Dépôts actifs ou anciennement actifs sur ce serveur",
+ "desc": "Dépôts actifs ou anciennement actifs sur ce serveur.",
"disabled": "Désactivé",
"none": "Il n'y a pas encore de dépôts.",
"repair": {
@@ -106,7 +106,7 @@
"secrets": "Secrets",
"show": "Afficher les secrets",
"value": "Valeur",
- "warning": "Ces secrets seront disponibles pour tout les comptes du serveur."
+ "warning": "Ces secrets seront disponibles pour tout les comptes."
},
"settings": "Réglages",
"users": {
@@ -130,6 +130,10 @@
"saved": "Compte utilisateur enregistré",
"show": "Afficher les comptes utilisateurs",
"users": "Utilisateurs"
+ },
+ "registries": {
+ "warning": "Ces codes d’accès au registre seront disponibles pour tout les utilisateurs.",
+ "desc": "Les codes d'accès aux registres globaux peuvent être ajouter pour utiliser les images privées sur tout les pipelines."
}
}
},
@@ -157,7 +161,7 @@
"add": "Ajouter un secret",
"created": "Secret d'organisation crée",
"deleted": "Secret d'organisation supprimé",
- "desc": "Les secrets d'organisation sont transmis sous forme de variable d’environnement lors de l’exécution de chaque étape d'un pipeline de tout les dépôts de l'organisation.",
+ "desc": "Les secrets d'organisation sont transmis sous forme de variable d’environnement à chaque étape d'un pipeline de tout les dépôts de l'organisation.",
"events": {
"events": "Disponible pour les événements suivants",
"pr_warning": "Faites attention avec cette option car un acteur malicieux pourrait soumettre une pull request qui va afficher vos secrets."
@@ -175,7 +179,10 @@
"show": "Afficher les secrets",
"value": "Valeur"
},
- "settings": "Réglages"
+ "settings": "Réglages",
+ "registries": {
+ "desc": "Les codes d'accès aux registres de l'organisation peuvent être ajouté pour utiliser les images privées sur tout les pipelines de l'organisation."
+ }
}
},
"org_level_secret": "Secret d'organisation",
@@ -196,7 +203,8 @@
"title": "Variables additionnelles du pipeline",
"value": "Valeur de la variable",
"delete": "Supprimer la variable"
- }
+ },
+ "enter_task": "Tâche de déploiement"
},
"enable": {
"disabled": "Désactivé",
@@ -217,10 +225,11 @@
"title": "Variables de pipeline supplémentaire",
"value": "Valeur de la variable",
"delete": "Supprimer la variable"
- }
+ },
+ "show_pipelines": "Afficher les pieplines"
},
"not_allowed": "Vous n'êtes pas autorisé à accéder à ce dépôt",
- "open_in_forge": "Ouvrir le dépôt dans un système de contrôle de version",
+ "open_in_forge": "Ouvrir le dépôt dans la forge",
"pipeline": {
"actions": {
"cancel": "Annuler",
@@ -243,7 +252,8 @@
"pr": "Pull Request",
"push": "Push",
"tag": "Tag",
- "release": "Release"
+ "release": "Release",
+ "pr_closed": "Pull Request fusionnée / fermée"
},
"exit_code": "Code de retour {exitCode}",
"files": "Fichiers changés ({files})",
@@ -284,7 +294,10 @@
"warnings": "Avertissements ({count})",
"we_got_some_errors": "Oh non, il y a des erreurs !",
"log_delete_error": "Il y a eu une erreur lors de la suppression des logs",
- "log_delete_confirm": "Voulez vous vraiment supprimer les logs de cette étape ?"
+ "log_delete_confirm": "Voulez vous vraiment supprimer les logs de cette étape ?",
+ "no_logs": "Aucun logs",
+ "duration": "Durée du pipeline",
+ "created": "Crée : {created}"
},
"pull_requests": "Pull requests",
"settings": {
@@ -376,7 +389,7 @@
"timeout": "Délai d’inactivité"
},
"trusted": {
- "desc": "Les conteneurs du pipeline ont accès à des capacités privilégiées comme le montage de volumes.",
+ "desc": "Les conteneurs du pipeline ont accès à des capacités privilégiées (comme le montage de volumes).",
"trusted": "Vérifié"
},
"visibility": {
@@ -494,7 +507,7 @@
"add": "Ajouter un secret",
"created": "Secret d'utilisateur crée",
"deleted": "Secret d'utilisateur supprimé",
- "desc": "Les secrets d'utilisateur peuvent être passés à toutes les étapes du pipeline des dépôts de l'utilisateur sous forme de variables d'environnement.",
+ "desc": "Les secrets d'utilisateur peuvent être passés à toutes les étapes d'un pipeline personnel sous forme de variables d'environnement.",
"events": {
"events": "Disponible pour les événements suivants",
"pr_warning": "Attention, si cette option est activée, un acteur malveillant peut proposer une pull request qui affiche vos secrets."
@@ -537,7 +550,7 @@
"login_to_cli_description": "En continuant, vous serez connecté via la ligne de commande.",
"secrets": {
"secrets": "Secrets",
- "desc": "Les secrets peuvent être transmis aux différentes étapes de la pipeline au moment de l'exécution en tant que variables d'environnement.",
+ "desc": "Les secrets peuvent être transmis aux différentes étapes de la pipeline en tant que variables d'environnement.",
"images": {
"desc": "Liste des images pour lesquelles ce secret est disponible, laisser vide pour autoriser toutes les images",
"images": "Disponible pour les images suivantes"
@@ -553,8 +566,51 @@
"saved": "Secret sauvegardé",
"events": {
"events": "Disponible lors des événements suivants",
- "pr_warning": "Soyez prudent avec cette option car un acteur malveillant peut soumettre une pull request qui expose vos secrets."
+ "pr_warning": "Soyez prudent avec cette option : un acteur malveillant peut soumettre une pull request qui expose vos secrets."
},
- "plugins_only": "Uniquement disponible pour les plugins"
- }
+ "plugins_only": "Uniquement disponible pour les plugins",
+ "edit": "Modifier le secret",
+ "delete": "Supprimer le secret",
+ "delete_confirm": "Voulez vous vraiment supprimer ce secret ?",
+ "plugins": {
+ "images": "Disponible pour les plugins suivants"
+ }
+ },
+ "internal_error": "Une erreur interne est survenue",
+ "access_denied": "Vous n'êtes pas autorisé à accéder à cette instance",
+ "oauth_error": "Erreur lors de l'authentification auprès du fournisseur OAuth",
+ "registration_closed": "Les inscriptions sont fermés",
+ "settings": "Réglages",
+ "registries": {
+ "registries": "Registres",
+ "delete_confirm": "Voulez vous vraiment supprimer ce registre ?",
+ "deleted": "Codes d'accès aux registres supprimés",
+ "desc": "Les codes d'accès aux registres peuvent être ajouté pour utiliser des images privées sur les pipelines.",
+ "credentials": "Codes d’accès aux registres",
+ "edit": "Éditer le registre",
+ "delete": "Supprimer le registre",
+ "add": "Ajouter un registre",
+ "view": "Voir le registre",
+ "save": "Enregistrer le registre",
+ "show": "Afficher les registres",
+ "address": {
+ "address": "Adresse",
+ "desc": "Adresse du registre (e.g. docker.io)"
+ },
+ "saved": "Codes d'accès aux registres enregistrés",
+ "created": "Codes d’accès aux registres crées",
+ "none": "Il n'y a pas de code d’accès aux registres."
+ },
+ "invalid_state": "L'état OAuth est invalide",
+ "by_user": "par {user}",
+ "pushed_to": "poussé vers",
+ "closed": "fermé",
+ "deployed_to": "déployé vers",
+ "created": "crée",
+ "triggered": "déclenché",
+ "pipeline_duration": "Durée du pipeline",
+ "pipeline_since": "Pipeline crée {created} minutes ago",
+ "pipeline_has_warnings": "Le pipeline a des alertes",
+ "pipeline_has_errors": "Le pipeline a des erreurs",
+ "login_with": "Se connecter avec {forge}"
}
diff --git a/web/src/assets/locales/it.json b/web/src/assets/locales/it.json
index 20b99f7cb..675789451 100644
--- a/web/src/assets/locales/it.json
+++ b/web/src/assets/locales/it.json
@@ -1,152 +1,510 @@
{
- "admin": {
- "settings": {
- "queue": {
- "agent": "agente",
- "stats": {
- "completed_count": "Task completo",
- "worker_count": "Liberi"
- },
- "waiting_for": "in attesa"
- },
- "users": {
- "add": "Aggiungi utente",
- "admin": {
- "admin": "Amministatore",
- "placeholder": "L'utente è un amministratore"
- },
- "created": "Utente creato",
- "delete_confirm": "Vuoi davvero cancellare questo utente?",
- "delete_user": "Cancella utente",
- "deleted": "Utente cancellato",
- "edit_user": "Modifica utente",
- "none": "Non ci sono ancora utenti.",
- "saved": "Utente salvato",
- "show": "Mostra utenti"
- }
- }
- },
- "back": "Indietro",
- "cancel": "Annulla",
- "docs": "Documentazione",
- "documentation_for": "Documentazione per \"{topic}\"",
- "errors": {
- "not_found": "Il server non riesce a trovare l'oggetto richiesto"
- },
- "login": "Accedi",
- "logout": "Esci",
- "not_found": {
- "back_home": "Torna alla pagina principale",
- "not_found": "Ahia 404, o abbiamo rotto qualcosa o hai scritto male qualcosa :-/"
- },
- "password": "Password",
- "pipeline_feed": "Alimentazione pipeline",
- "repo": {
- "activity": "Attività",
- "add": "Aggiungi repository",
- "branches": "Branch",
- "deploy_pipeline": {
- "enter_target": "Ambiente di deploy destinazione",
- "title": "Azione l'evento di deploy per la pipeline corrente #{pipelineId}",
- "trigger": "Deploy",
- "variables": {
- "add": "Aggiungi variabile",
- "desc": "Specifica variabili addizionali da usare nella pipeline. Le variabili con lo stesso nome saranno sovrascritte.",
- "name": "Nome variabile",
- "title": "Variabili addizionali della pipeline",
- "value": "Valore variabile"
- }
- },
- "enable": {
- "enable": "Abilita",
- "enabled": "Già abilitato",
- "list_reloaded": "Elenco dei repository ricaricato",
- "reload": "Ricarica i repository",
- "success": "Repository abilitato"
- },
- "manual_pipeline": {
- "select_branch": "Seleziona branch",
- "title": "Avvia un'esecuzione manuale della pipeline",
- "trigger": "Esegui pipeline",
- "variables": {
- "add": "Aggiungi variabile",
- "desc": "Specifica variabili addizionali da usare nella pipeline. Le variabili con lo stesso nome saranno sovrascritte.",
- "name": "Nome variabile",
- "title": "Variabili aggiuntive per la pipeline",
- "value": "Valore variabile"
- }
- },
- "not_allowed": "Non è permesso accedere a questo repository",
- "open_in_forge": "Apri il repository nel Version Control System",
- "pipeline": {
- "actions": {
- "cancel": "Annulla"
- }
- },
- "pull_requests": "Pull request",
- "settings": {
- "actions": {
- "actions": "Azioni"
- },
- "crons": {
- "name": {
- "name": "Nome"
- },
- "next_exec": "Prossima esecuzione",
- "not_executed_yet": "Non ancora eseguito"
- },
- "general": {
- "general": "Generale",
- "pipeline_path": {
- "default": "Predefinito: .woodpecker/*.yml -> .woodpecker.yml",
- "path": "Percorso della pipeline"
- },
- "project": "Impostazioni del progetto",
- "protected": {
- "protected": "Protetto"
- },
- "save": "Salva le impostazioni",
- "success": "Le impostazioni del repository sono state aggiornate",
- "timeout": {
- "minutes": "minuti"
- },
- "visibility": {
- "internal": {
- "desc": "Solo gli utenti dell'istanza Woodpecker che hanno effettuato l'accesso possono vedere questo progetto.",
- "internal": "Interno"
- },
- "private": {
- "desc": "Soltanto tu e gli altri proprietari del repository possono vedere questo progetto.",
- "private": "Privato"
- },
- "public": {
- "desc": "Qualunque utente può vedere il tuo progetto senza la necessità di accedere.",
- "public": "Pubblico"
- }
+ "admin": {
+ "settings": {
+ "queue": {
+ "agent": "agente",
+ "stats": {
+ "completed_count": "Attività Completate",
+ "worker_count": "Liberi",
+ "running_count": "In esecuzione",
+ "waiting_on_deps_count": "In attesa delle dipendenze",
+ "pending_count": "In attesa"
+ },
+ "waiting_for": "in attesa di",
+ "pause": "Sospendi",
+ "resume": "Riprendi",
+ "resumed": "Coda ripresa",
+ "paused": "Coda sospesa",
+ "tasks": "Attività",
+ "task_running": "Attività in esecuzione",
+ "task_waiting_on_deps": "Attività in attesa delle dipendenze",
+ "desc": "Attività in attesa di essere eseguiti dagli agenti",
+ "queue": "Coda",
+ "task_pending": "Attività in attesa"
+ },
+ "users": {
+ "add": "Aggiungi utente",
+ "admin": {
+ "admin": "Amministatore",
+ "placeholder": "L'utente è un amministratore"
+ },
+ "created": "Utente creato",
+ "delete_confirm": "Vuoi davvero eliminare questo utente? Ciò eliminerà anche tutte le repository di proprietà di questo utente.",
+ "delete_user": "Elimina utente",
+ "deleted": "Utente eliminato",
+ "edit_user": "Modifica utente",
+ "none": "Ancora nessun utente.",
+ "saved": "Utente salvato",
+ "show": "Mostra utenti",
+ "users": "Utenti",
+ "desc": "Utenti registrati per questo server",
+ "login": "Accesso",
+ "email": "E-mail",
+ "avatar_url": "URL Avatar",
+ "cancel": "Annulla",
+ "save": "Salva utente"
+ },
+ "agents": {
+ "agents": "Agenti",
+ "desc": "Agenti registrati su questo server.",
+ "none": "Ancora nessun agente.",
+ "id": "ID",
+ "add": "Aggiungi agente",
+ "save": "Salva agente",
+ "show": "Mostra agenti",
+ "created": "Agente creato",
+ "saved": "Agente salvato",
+ "deleted": "Agente eliminato",
+ "name": {
+ "name": "Nome",
+ "placeholder": "Nome dell'agente"
+ },
+ "no_schedule": {
+ "name": "Disabilita agente",
+ "placeholder": "Impedisci all'agente di accettare nuove attività"
+ },
+ "token": "Token",
+ "platform": {
+ "platform": "Piattaforma",
+ "badge": "piattaforma"
+ },
+ "version": "Versione",
+ "backend": {
+ "backend": "Backend",
+ "badge": "backend"
+ },
+ "capacity": {
+ "capacity": "Capacità",
+ "desc": "Quantità massima di pipeline parallele eseguite da questo agente.",
+ "badge": "capacità"
+ },
+ "last_contact": "Ultimo contatto",
+ "never": "Mai",
+ "delete_confirm": "Vuoi davvero eliminare questo agente? Non sarà più in grado di connettersi al server.",
+ "edit_agent": "Modifica agente",
+ "delete_agent": "Elimina agente"
+ },
+ "orgs": {
+ "desc": "Organizzazioni che possiedono repository su questo server.",
+ "none": "Ancora nessuna organizzazione.",
+ "delete_org": "Elimina organizzazione",
+ "deleted": "Organizzazione eliminata",
+ "org_settings": "Impostazioni organizzazione",
+ "delete_confirm": "Vuoi davvero eliminare questa organizzazione? Ciò eliminerà anche tutte le repository di proprietà di questa organizzazione.",
+ "view": "Mostra organizzazione",
+ "orgs": "Organizzazioni"
+ },
+ "secrets": {
+ "warning": "Questi segreti saranno disponibili a tutti gli utenti.",
+ "desc": "I segreti globali possono essere passati ad ogni step della pipeline della repository, come variabili d'ambiente."
+ },
+ "repos": {
+ "settings": "Impostazioni repository",
+ "repos": "Repository",
+ "desc": "Repository che sono o sono state abilitate su questo server.",
+ "none": "Ancora nessuna repository.",
+ "view": "Mostra repository",
+ "disabled": "Disabilitato",
+ "repair": {
+ "repair": "Ripara tutti",
+ "success": "Repository riparate"
+ }
+ },
+ "not_allowed": "Non ti è consentito accedere alle impostazioni del server.",
+ "registries": {
+ "desc": "È possibile aggiungere credenziali di registro globale per utilizzare immagini private per tutte le pipeline.",
+ "warning": "Queste credenziali di registro saranno disponibili per tutti gli utenti."
+ }
}
- },
- "not_allowed": "Non è permesso accedere alle impostazioni di questo repository",
- "secrets": {
- "name": "Nome",
- "value": "Valore"
- },
- "settings": "Impostazioni"
},
- "user_none": "L'organizzazione/utente non ha ancora alcun progetto."
- },
- "repos": "Repository",
- "repositories": "Repository",
- "search": "Cerca…",
- "time": {
- "not_started": "non ancora avviato"
- },
- "unknown_error": "Si è verificato un errore sconosciuto",
- "url": "URL",
- "user": {
- "access_denied": "Non hai il permesso di entrare",
- "internal_error": "Errore interno",
- "oauth_error": "Errore durante l'autenticazione con il provider Oauth"
- },
- "username": "Nome utente",
- "welcome": "Benvenuti in Woodpecker"
+ "back": "Indietro",
+ "cancel": "Annulla",
+ "docs": "Documentazione",
+ "documentation_for": "Documentazione per \"{topic}\"",
+ "errors": {
+ "not_found": "Il server non è riuscito a trovare l'oggetto richiesto"
+ },
+ "login": "Accedi",
+ "logout": "Esci",
+ "not_found": {
+ "back_home": "Torna alla pagina principale",
+ "not_found": "Diamine 404, o qualcosa si è rotto o hai scritto male qualcosa :-/"
+ },
+ "password": "Password",
+ "pipeline_feed": "Dettagli pipeline",
+ "repo": {
+ "activity": "Attività",
+ "add": "Aggiungi repository",
+ "branches": "Rami",
+ "deploy_pipeline": {
+ "enter_target": "Ambiente di destinazione del deploy",
+ "title": "Avvia evento di deploy per la pipeline corrente #{pipelineId}",
+ "trigger": "Distribuzione",
+ "variables": {
+ "add": "Aggiungi variabile",
+ "desc": "Specifica variabili addizionali da usare nella pipeline. Le variabili con lo stesso nome saranno sovrascritte.",
+ "name": "Nome variabile",
+ "title": "Variabili addizionali della pipeline",
+ "value": "Valore variabile",
+ "delete": "Elimina variabile"
+ },
+ "enter_task": "Attività di distribuzione"
+ },
+ "enable": {
+ "enable": "Abilita",
+ "enabled": "Già abilitato",
+ "list_reloaded": "Elenco dei repository ricaricato",
+ "reload": "Ricarica i repository",
+ "success": "Repository abilitata",
+ "disabled": "Disabilitato"
+ },
+ "manual_pipeline": {
+ "select_branch": "Seleziona ramo",
+ "title": "Avvia un'esecuzione manuale della pipeline",
+ "trigger": "Esegui pipeline",
+ "variables": {
+ "add": "Aggiungi variabile",
+ "desc": "Specifica variabili addizionali da usare nella pipeline. Le variabili con lo stesso nome saranno sovrascritte.",
+ "name": "Nome variabile",
+ "title": "Variabili aggiuntive per la pipeline",
+ "value": "Valore variabile",
+ "delete": "Elimina variabile"
+ },
+ "show_pipelines": "Mostra pipeline"
+ },
+ "not_allowed": "Non ti è consentito accedere a questa repository",
+ "open_in_forge": "Apri pagina web della repository",
+ "pipeline": {
+ "actions": {
+ "cancel": "Annulla",
+ "log_delete": "Elimina",
+ "log_auto_scroll": "Scorrimento automatico",
+ "log_auto_scroll_off": "Disattiva scorrimento automatico",
+ "restart": "Riavvia",
+ "canceled": "Questo step è stato annullato.",
+ "cancel_success": "Pipeline annullata",
+ "restart_success": "Pipeline riavviata",
+ "log_download": "Scarica",
+ "deploy": "Distribuzione"
+ },
+ "no_pipelines": "Non è ancora stata attivata alcuna pipeline.",
+ "pipelines_for": "Pipeline per ramo \"{branch}\"",
+ "files": "File modificati ({files})",
+ "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})",
+ "protected": {
+ "awaits": "Questa pipeline è in attesa di approvazione da parte di un manutentore!",
+ "approve": "Approva",
+ "decline": "Rifiuta",
+ "declined": "Questa pipeline è stata rifiutata!",
+ "approve_success": "Pipeline approvata",
+ "decline_success": "Pipeline rifiutata"
+ },
+ "log_delete_error": "Si è verificato un errore durante l'eliminazione dei registri attività di step",
+ "status": {
+ "failure": "fallita",
+ "killed": "terminata",
+ "status": "Stato: {status}",
+ "pending": "in attesa",
+ "running": "in esecuzione",
+ "started": "avviata",
+ "blocked": "bloccata",
+ "skipped": "saltata",
+ "success": "completata",
+ "declined": "rifiutata",
+ "error": "errore"
+ },
+ "warnings": "Avvertenze ({count})",
+ "show_errors": "Mostra errori",
+ "we_got_some_errors": "Oh no, si sono verificati degli errori!",
+ "event": {
+ "tag": "Tag",
+ "cron": "Attività pianificata",
+ "manual": "Manuale",
+ "release": "Rilascio",
+ "push": "Invia",
+ "pr": "Richiesta di Modifica",
+ "deploy": "Distribuzione",
+ "pr_closed": "Richiesta di Modifica unita / chiusa"
+ },
+ "exit_code": "Codice di Uscita {exitCode}",
+ "loading": "Caricamento…",
+ "pipeline": "Pipeline #{pipelineId}",
+ "log_download_error": "Si è verificato un errore durante il download del registro attività",
+ "log_title": "Registro Attività di Step",
+ "pipelines_for_pr": "Pipeline per richiesta di modifica #{index}",
+ "duration": "Durata pipeline",
+ "created": "Creata: {created}",
+ "no_logs": "Nessun registro"
+ },
+ "pull_requests": "Richieste di modifica",
+ "settings": {
+ "actions": {
+ "actions": "Azioni",
+ "repair": {
+ "success": "Repository riparata",
+ "repair": "Ripara repository"
+ },
+ "delete": {
+ "delete": "Elimina repository",
+ "confirm": "Tutti i dati andranno persi dopo questa azione!!!\n\nVuoi davvero procedere?",
+ "success": "Repository eliminata"
+ },
+ "disable": {
+ "disable": "Disabilita repository",
+ "success": "Repository disabilitata"
+ },
+ "enable": {
+ "enable": "Abilita repository",
+ "success": "Repository abiltata"
+ }
+ },
+ "crons": {
+ "name": {
+ "name": "Nome",
+ "placeholder": "Nome attività pianificata"
+ },
+ "next_exec": "Prossima esecuzione",
+ "not_executed_yet": "Non ancora eseguita",
+ "none": "Ancora nessuna attività pianificata.",
+ "branch": {
+ "placeholder": "Ramo (utilizza ramo predefinito se vuoto)",
+ "title": "Ramo"
+ },
+ "add": "Aggiungi attività pianificata",
+ "save": "Salva attività pianificata",
+ "created": "Attività pianificata creata",
+ "saved": "Attività pianificata salvata",
+ "deleted": "Attività pianificata eliminata",
+ "run": "Esegui ora",
+ "schedule": {
+ "title": "Programma (basato su UTC)",
+ "placeholder": "Programma"
+ },
+ "edit": "Modifica attività pianificata",
+ "delete": "Elimina attività pianificata",
+ "desc": "Le attività pianificate possono attivare pipeline a intervalli regolari.",
+ "show": "Mostra attività pianificate",
+ "crons": "Attività pianificate"
+ },
+ "general": {
+ "general": "Generale",
+ "pipeline_path": {
+ "default": "Predefinito: .woodpecker/*.{'{yaml,yml}'} -> .woodpecker.yaml -> .woodpecker.yml",
+ "path": "Percorso della pipeline",
+ "desc": "Percorso per la configurazione della pipeline (ad esempio {0}). Le cartelle devono terminare con {1}.",
+ "desc_path_example": "mio/percorso/"
+ },
+ "project": "Impostazioni progetto",
+ "protected": {
+ "protected": "Protetto",
+ "desc": "Ogni pipeline deve essere approvata prima di essere eseguita."
+ },
+ "save": "Salva impostazioni",
+ "success": "Impostazioni della repository aggiornate",
+ "timeout": {
+ "minutes": "minuti",
+ "timeout": "Scadenza"
+ },
+ "visibility": {
+ "internal": {
+ "desc": "Solo gli utenti autenticati dell'istanza Woodpecker possono vedere questo progetto.",
+ "internal": "Interno"
+ },
+ "private": {
+ "desc": "Solo tu e gli altri proprietari della repository potete vedere questo progetto.",
+ "private": "Privato"
+ },
+ "public": {
+ "desc": "Ogni utente può vedere il tuo progetto senza aver effettuato l'accesso.",
+ "public": "Pubblico"
+ },
+ "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.",
+ "cancel": "Annulla pipeline precedenti"
+ },
+ "trusted": {
+ "desc": "I container eseguiti dalle pipeline ottengono accesso a funzionalità avanzate (come il montaggio di volumi).",
+ "trusted": "Attendibile"
+ },
+ "allow_pr": {
+ "allow": "Consenti Richieste di Modifica",
+ "desc": "Le pipeline possono essere eseguite su 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."
+ },
+ "netrc_only_trusted": {
+ "netrc_only_trusted": "Inietta le credenziali netrc solo nei container attendibili",
+ "desc": "Inietta le credenziali netrc solo nei contenitori attendibili (consigliato)."
+ }
+ },
+ "not_allowed": "Non ti è consentito accedere alle impostazioni di questa repository",
+ "secrets": {
+ "name": "Nome",
+ "value": "Valore"
+ },
+ "settings": "Impostazioni",
+ "registries": {
+ "registries": "Registri",
+ "desc": "È possibile aggiungere credenziali di registro per utilizzare immagini private nella pipeline.",
+ "address": {
+ "placeholder": "Indirizzo del Registro (es. docker.io)",
+ "address": "Indirizzo"
+ },
+ "credentials": "Credenziali di registro",
+ "show": "Mostra registri",
+ "add": "Aggiungi registro",
+ "none": "Ancora nessuna credenziale di registro.",
+ "save": "Salva registro",
+ "created": "Credenziali di registro create",
+ "saved": "Credenziali di registro salvate",
+ "deleted": "Credenziali di registro eliminate",
+ "edit": "Modifica registro",
+ "delete": "Elimina registro"
+ },
+ "badge": {
+ "type": "Sintassi",
+ "type_url": "URL",
+ "type_markdown": "Markdown",
+ "type_html": "HTML",
+ "badge": "Badge",
+ "branch": "Ramo"
+ }
+ },
+ "user_none": "L'organizzazione / utente non ha ancora alcun progetto."
+ },
+ "repos": "Repository",
+ "repositories": "Repository",
+ "search": "Cerca…",
+ "time": {
+ "not_started": "non ancora iniziato",
+ "template": "MMM D, YYYY, HH:mm z"
+ },
+ "unknown_error": "Si è verificato un errore sconosciuto",
+ "url": "URL",
+ "user": {
+ "access_denied": "Non hai il permesso di entrare",
+ "internal_error": "Errore interno",
+ "oauth_error": "Errore durante l'autenticazione con il provider Oauth",
+ "settings": {
+ "secrets": {
+ "desc": "I segreti utente possono essere passati ad ogni step della pipeline, come variabili d'ambiente."
+ },
+ "cli_and_api": {
+ "desc": "Utilizzo del Token di Accesso Personale, CLI e API",
+ "token": "Token di Accesso Personale",
+ "api_usage": "Esempio di utilizzo dell'API",
+ "cli_usage": "Esempio di utilizzo della CLI",
+ "download_cli": "Scarica CLI",
+ "reset_token": "Ripristina token",
+ "swagger_ui": "Interfaccia Swagger",
+ "cli_and_api": "CLI & API"
+ },
+ "settings": "Impostazioni Utente",
+ "general": {
+ "general": "Generale",
+ "language": "Lingua",
+ "theme": {
+ "theme": "Tema",
+ "light": "Chiaro",
+ "dark": "Scuro",
+ "auto": "Auto"
+ }
+ },
+ "registries": {
+ "desc": "È possibile aggiungere le credenziali di registro per utilizzare immagini private in tutte le pipeline personali."
+ }
+ }
+ },
+ "username": "Nome utente",
+ "welcome": "Benvenuti in Woodpecker",
+ "secrets": {
+ "created": "Segreto creato",
+ "saved": "Segreto salvato",
+ "events": {
+ "events": "Disponibile ai seguenti eventi",
+ "pr_warning": "Si prega di fare attenzione con questa opzione: un malintenzionato potrebbe inviare una richiesta di modifica dannosa, che rivela i tuoi segreti."
+ },
+ "value": "Valore",
+ "delete_confirm": "Vuoi davvero eliminare questo segreto?",
+ "none": "Ancora nessun segreto.",
+ "add": "Aggiungi segreto",
+ "save": "Salva segreto",
+ "show": "Mostra segreti",
+ "name": "Nome",
+ "delete": "Elimina segreto",
+ "edit": "Modifica segreto",
+ "deleted": "Segreto eliminato",
+ "images": {
+ "images": "Disponibile per le seguenti immagini",
+ "desc": "Elenco di immagini in cui questo segreto è disponibile, lascia vuoto per consentire a tutte le immagini."
+ },
+ "secrets": "Segreti",
+ "desc": "I segreti possono essere passati ad ogni step della pipeline, come variabili d'ambiente.",
+ "plugins": {
+ "images": "Disponibile solo per le seguenti estensioni",
+ "desc": "Elenco delle estensioni in cui questo segreto è disponibile, lascia vuoto per consentire tutto."
+ }
+ },
+ "default": "predefinito",
+ "info": "Dettagli",
+ "update_woodpecker": "Aggiorna la tua istanza Woodpecker a {0}",
+ "global_level_secret": "segreto globale",
+ "org_level_secret": "segreto organizzazione",
+ "login_to_cli": "Accedi alla CLI",
+ "abort": "Interrompi",
+ "cli_login_success": "Accesso alla CLI riuscito",
+ "oauth_error": "Errore durante l'autenticazione con il provider OAuth",
+ "internal_error": "Si è verificato un errore interno",
+ "registration_closed": "La registrazione è chiusa",
+ "api": "API",
+ "empty_list": "Nessuna (entità) trovata!",
+ "cli_login_denied": "Accesso alla CLI negato",
+ "return_to_cli": "Ora puoi chiudere questa scheda e tornare alla CLI.",
+ "settings": "Impostazioni",
+ "cli_login_failed": "Accesso alla CLI fallito",
+ "login_to_cli_description": "Proseguendo si accederà alla CLI.",
+ "access_denied": "Non ti è consentito accedere a questa istanza",
+ "invalid_state": "Lo stato OAuth non è valido",
+ "org": {
+ "settings": {
+ "not_allowed": "Non ti è consentito accedere alle impostazioni di questa organizzazione",
+ "secrets": {
+ "desc": "I segreti dell'organizzazione possono essere passati ad ogni step della pipeline della repository dell'organizzazione, come variabili d'ambiente."
+ },
+ "registries": {
+ "desc": "È possibile aggiungere le credenziali di registro dell'organizzazione per utilizzare immagini private per tutte le pipeline di un'organizzazione."
+ }
+ }
+ },
+ "running_version": "Stai eseguendo Woodpecker {0}",
+ "registries": {
+ "delete_confirm": "Vuoi davvero eliminare questo registro?",
+ "registries": "Registri",
+ "credentials": "Credenziali di registro",
+ "desc": "È possibile aggiungere le credenziali di registro per utilizzare immagini private nelle pipeline.",
+ "none": "Ancora nessune credenziali di registro.",
+ "address": {
+ "address": "Indirizzo",
+ "desc": "Indirizzo di Registro (es. docker.io)"
+ },
+ "show": "Mostra registri",
+ "save": "Salva registro",
+ "add": "Aggiungi registro",
+ "view": "Mostra registro",
+ "edit": "Modifica registro",
+ "delete": "Elimina registro",
+ "created": "Credenziali di registro create",
+ "saved": "Credenziali di registro salvate",
+ "deleted": "Credenziali di registro eliminate"
+ },
+ "login_with": "Accedi con {forge}"
}
diff --git a/web/src/assets/locales/lv.json b/web/src/assets/locales/lv.json
index f21332615..33ebc777e 100644
--- a/web/src/assets/locales/lv.json
+++ b/web/src/assets/locales/lv.json
@@ -1,508 +1,605 @@
{
- "admin": {
- "settings": {
- "agents": {
- "add": "Pievienot aģentu",
- "agents": "Aģenti",
- "backend": {
- "backend": "Aizmugures sistēma",
- "badge": "aizmugures sistēma"
- },
- "capacity": {
- "badge": "paralēlie darbi",
- "capacity": "Paralēlie darbi",
- "desc": "Maksimālais aģenta paralēli izpildāmo konvejerdarbu skaits."
- },
- "created": "Aģents izveidots",
- "delete_agent": "Dzēst aģentu",
- "delete_confirm": "Vai patiešām dzēst šo aģentu? Tam vairs nebūs iespējas savienoties ar serveri.",
- "deleted": "Aģents izdzēsts",
- "desc": "Šajā serverī reģistrētie aģenti",
- "edit_agent": "Labot aģentu",
- "id": "ID",
- "last_contact": "Pēdējā sazināšanās",
- "name": {
- "name": "Nosaukums",
- "placeholder": "Aģenta nosaukums"
- },
- "never": "nekad",
- "no_schedule": {
- "name": "Atspējot aģentu",
- "placeholder": "Apturēt aģentu no jaunu darbu pieņemšanas"
- },
- "none": "Pagaidām nav neviena aģenta.",
- "platform": {
- "badge": "platforma",
- "platform": "Platforma"
- },
- "save": "Saglabāt aģentu",
- "saved": "Aģents saglabāts",
- "show": "Parādīt aģentus",
- "token": "Drošības talons",
- "version": "Versija"
- },
- "not_allowed": "Nav piekļuves servera iestatījumiem",
- "orgs": {
- "delete_confirm": "Vai patiešām vēlaties dzēst šo organizāciju? Tiks dzēsti arī visi organizācijai piederošie repozitoriji.",
- "delete_org": "Dzēst organizāciju",
- "deleted": "Organizācija tika izdzēsta",
- "desc": "Organizācijas, kurām pieder repozitoriji šajā serverī",
- "none": "Pagaidām nav nevienas organizācijas.",
- "org_settings": "Organizācijas iestatījumi",
- "orgs": "Organizācijas",
- "view": "Skatīt organizāciju"
- },
- "queue": {
- "agent": "aģents",
- "desc": "Uzdevumi, kuri gaida izpildi",
- "pause": "Apturēt",
- "paused": "Rinda ir apturēta",
- "queue": "Rinda",
- "resume": "Atsākt",
- "resumed": "Rindas apstrāde atsākta",
- "stats": {
- "completed_count": "Pabeigtie uzdevumi",
- "pending_count": "Gaida",
- "running_count": "Izpildās",
- "waiting_on_deps_count": "Gaida uz atkarībām",
- "worker_count": "Brīvi"
- },
- "task_pending": "Uzdevums gaida izpildi",
- "task_running": "Uzdevums tiek izpildīts",
- "task_waiting_on_deps": "Uzdevums gaida uz atkarībām",
- "tasks": "Uzdevumi",
- "waiting_for": "gaida uz"
- },
- "repos": {
- "desc": "Repozitoriji, kas ir vai ir bijuši iespējoti šajā serverī",
- "disabled": "Atspējots",
- "none": "Pagaidām nav neviena repozitorija.",
- "repair": {
- "repair": "Salabot visus",
- "success": "Repozitoriji salaboti"
- },
- "repos": "Repozitoriji",
- "settings": "Repozitorija iestatījumi",
- "view": "Skatīt repozitoriju"
- },
- "secrets": {
- "add": "Pievienot noslēpumu",
- "created": "Globālais noslēpums izveidots",
- "deleted": "Globālais noslēpums dzēsts",
- "desc": "Noslēpumus var padot visu repozitoriju individuāliem konvejerdarba soļiem izpildes laikā kā vides mainīgos.",
- "events": {
- "events": "Pieejams šādiem notikumiem",
- "pr_warning": "Uzmanieties, jo šādā veidā tas būs pieejams visiem cilvēkiem, kas var iesūtīt izmaiņu pieprasījumu."
- },
- "images": {
- "desc": "Ar komatiem atdalīts saraksts ar attēliem, kam šis noslēpums būs pieejams, atstājot tukšu, tas būs pieejams visiem attēliem",
- "images": "Pieejami šādiem attēliem"
- },
- "name": "Nosaukums",
- "none": "Pagaidām nav neviena globālā noslēpuma.",
- "plugins_only": "Pieejams tikai spraudņiem",
- "save": "Saglabāt noslēpumu",
- "saved": "Globālais noslēpums saglabāts",
- "secrets": "Noslēpumi",
- "show": "Noslēpumu saraksts",
- "value": "Vērtība",
- "warning": "Šie noslēpumi būs pieejami visiem servera lietotājiem."
- },
- "settings": "Iestatījumi",
- "users": {
- "add": "Pievienot lietotāju",
- "admin": {
- "admin": "Administrators",
- "placeholder": "Lietotājs ir administrators"
- },
- "avatar_url": "Avatāra URL",
- "cancel": "Atcelt",
- "created": "Lietotājs izveidots",
- "delete_confirm": "Vai patiešām vēlaties dzēst šo lietotāju? Tiks dzēsti arī visi lietotājam piederošie repozitoriji.",
- "delete_user": "Dzēst lietotāju",
- "deleted": "Lietotājs izdzēsts",
- "desc": "Lietotāji, kas ir reģistrēti šajā serverī",
- "edit_user": "Labot lietotāju",
- "email": "E-pasta adrese",
- "login": "Lietotāja vārds",
- "none": "Pašlaik vēl nav neviena lietotāja.",
- "save": "Saglabāt lietotāju",
- "saved": "Lietotāja dati saglabāti",
- "show": "Parādīt lietotājus",
- "users": "Lietotāji"
- }
- }
- },
- "api": "API",
- "back": "Atpakaļ",
- "cancel": "Atcelt",
- "default": "noklusētais",
- "docs": "Dokumentācija",
- "documentation_for": "Dokumentācija par \"{topic}\"",
- "errors": {
- "not_found": "Nevarēja atrast pieprasīto objektu"
- },
- "info": "Informācija",
- "login": "Autorizēties",
- "logout": "Iziet",
- "not_found": {
- "back_home": "Uz sākumu",
- "not_found": "Ak vai, 404, vai nu mēs salauzām kaut ko, vai arī tika atvērta lapa, kas neeksistē :-/"
- },
- "org": {
- "settings": {
- "not_allowed": "Nav piekļuves šīs organizācijas iestatījumiem",
- "secrets": {
- "add": "Pievienot noslēpumu",
- "created": "Organizācijas noslēpums izveidots",
- "deleted": "Organizācijas noslēpums dzēsts",
- "desc": "Noslēpumus var padot visu organizācijas repozitoriju individuāliem konvejerdarba soļiem izpildes laikā kā vides mainīgos.",
- "events": {
- "events": "Pieejams šādiem notikumiem",
- "pr_warning": "Uzmanieties, jo šādā veidā tas būs pieejams visiem cilvēkiem, kas var iesūtīt izmaiņu pieprasījumu."
- },
- "images": {
- "desc": "Ar komatiem atdalīts saraksts ar attēliem, kam šis noslēpums būs pieejams, atstājot tukšu, tas būs pieejams visiem attēliem",
- "images": "Pieejami šādiem attēliem"
- },
- "name": "Nosaukums",
- "none": "Pagaidām nav neviena organizācijas noslēpuma.",
- "plugins_only": "Pieejams tikai spraudņiem",
- "save": "Saglabāt noslēpumu",
- "saved": "Organizācijas noslēpums saglabāts",
- "secrets": "Noslēpumi",
- "show": "Noslēpumu saraksts",
- "value": "Vērtība"
- },
- "settings": "Iestatījumi"
- }
- },
- "password": "Parole",
- "pipeline_feed": "Konvejerdarba padeve",
- "repo": {
- "activity": "Aktivitāte",
- "add": "Pievienot repozitoriju",
- "branches": "Atzari",
- "deploy_pipeline": {
- "enter_target": "Mērķa uzstādīšanas vide",
- "title": "Iniciēt uzstādīšanas notikumu šim konvejerdarbam #{pipelineId}",
- "trigger": "Uzstādīt",
- "variables": {
- "add": "Pievienot mainīgo",
- "desc": "Norādiet papildus mainīgos, ko izmantot konvejerdarbā. Mainīgie ar šādu pašu nosaukumu tiks pārrakstīti.",
- "name": "Mainīgā nosaukums",
- "title": "Papildus konvejerdarba mainīgie",
- "value": "Mainīgā vērtība"
- }
+ "admin": {
+ "settings": {
+ "agents": {
+ "add": "Pievienot aģentu",
+ "agents": "Aģenti",
+ "backend": {
+ "backend": "Aizmugures sistēma",
+ "badge": "aizmugures sistēma"
+ },
+ "capacity": {
+ "badge": "paralēlie darbi",
+ "capacity": "Paralēlie darbi",
+ "desc": "Maksimālais aģenta paralēli izpildāmo konvejerdarbu skaits."
+ },
+ "created": "Aģents izveidots",
+ "delete_agent": "Dzēst aģentu",
+ "delete_confirm": "Vai tiešām vēlaties dzēst šo aģentu? Tam vairs nebūs iespējas savienoties ar serveri.",
+ "deleted": "Aģents izdzēsts",
+ "desc": "Šajā serverī reģistrētie aģenti.",
+ "edit_agent": "Labot aģentu",
+ "id": "ID",
+ "last_contact": "Pēdējā sazināšanās",
+ "name": {
+ "name": "Nosaukums",
+ "placeholder": "Aģenta nosaukums"
+ },
+ "never": "nekad",
+ "no_schedule": {
+ "name": "Atspējot aģentu",
+ "placeholder": "Apturēt aģentu no jaunu darbu pieņemšanas"
+ },
+ "none": "Pagaidām nav neviena aģenta.",
+ "platform": {
+ "badge": "platforma",
+ "platform": "Platforma"
+ },
+ "save": "Saglabāt aģentu",
+ "saved": "Aģents saglabāts",
+ "show": "Parādīt aģentus",
+ "token": "Drošības talons",
+ "version": "Versija"
+ },
+ "not_allowed": "Nav piekļuves servera iestatījumiem.",
+ "orgs": {
+ "delete_confirm": "Vai patiešām vēlaties dzēst šo organizāciju? Tiks dzēsti arī visi organizācijai piederošie repozitoriji.",
+ "delete_org": "Dzēst organizāciju",
+ "deleted": "Organizācija tika izdzēsta",
+ "desc": "Organizācijas, kurām pieder repozitoriji šajā serverī.",
+ "none": "Pagaidām nav nevienas organizācijas.",
+ "org_settings": "Organizācijas iestatījumi",
+ "orgs": "Organizācijas",
+ "view": "Skatīt organizāciju"
+ },
+ "queue": {
+ "agent": "aģents",
+ "desc": "Uzdevumi, kuri gaida izpildi",
+ "pause": "Apturēt",
+ "paused": "Rinda ir apturēta",
+ "queue": "Rinda",
+ "resume": "Atsākt",
+ "resumed": "Rindas apstrāde atsākta",
+ "stats": {
+ "completed_count": "Pabeigtie uzdevumi",
+ "pending_count": "Gaida",
+ "running_count": "Izpildās",
+ "waiting_on_deps_count": "Gaida uz atkarībām",
+ "worker_count": "Brīvi"
+ },
+ "task_pending": "Uzdevums gaida izpildi",
+ "task_running": "Uzdevums tiek izpildīts",
+ "task_waiting_on_deps": "Uzdevums gaida uz atkarībām",
+ "tasks": "Uzdevumi",
+ "waiting_for": "gaida uz"
+ },
+ "repos": {
+ "desc": "Repozitoriji, kas ir vai ir bijuši iespējoti šajā serverī.",
+ "disabled": "Atspējots",
+ "none": "Pagaidām nav neviena repozitorija.",
+ "repair": {
+ "repair": "Salabot visus",
+ "success": "Repozitoriji salaboti"
+ },
+ "repos": "Repozitoriji",
+ "settings": "Repozitorija iestatījumi",
+ "view": "Skatīt repozitoriju"
+ },
+ "secrets": {
+ "add": "Pievienot noslēpumu",
+ "created": "Globālais noslēpums izveidots",
+ "deleted": "Globālais noslēpums dzēsts",
+ "desc": "Noslēpumus var padot visu repozitoriju konvejerdarba soļiem izpildes laikā kā vides mainīgos.",
+ "events": {
+ "events": "Pieejams šādiem notikumiem",
+ "pr_warning": "Uzmanieties, jo šādā veidā tas būs pieejams visiem cilvēkiem, kas var iesūtīt izmaiņu pieprasījumu."
+ },
+ "images": {
+ "desc": "Ar komatiem atdalīts saraksts ar attēliem, kam šis noslēpums būs pieejams, atstājot tukšu, tas būs pieejams visiem attēliem",
+ "images": "Pieejami šādiem attēliem"
+ },
+ "name": "Nosaukums",
+ "none": "Pagaidām nav neviena globālā noslēpuma.",
+ "plugins_only": "Pieejams tikai spraudņiem",
+ "save": "Saglabāt noslēpumu",
+ "saved": "Globālais noslēpums saglabāts",
+ "secrets": "Noslēpumi",
+ "show": "Noslēpumu saraksts",
+ "value": "Vērtība",
+ "warning": "Šie noslēpumi būs pieejami visiem lietotājiem."
+ },
+ "settings": "Iestatījumi",
+ "users": {
+ "add": "Pievienot lietotāju",
+ "admin": {
+ "admin": "Administrators",
+ "placeholder": "Lietotājs ir administrators"
+ },
+ "avatar_url": "Avatāra URL",
+ "cancel": "Atcelt",
+ "created": "Lietotājs izveidots",
+ "delete_confirm": "Vai patiešām vēlaties dzēst šo lietotāju? Tiks dzēsti arī visi lietotājam piederošie repozitoriji.",
+ "delete_user": "Dzēst lietotāju",
+ "deleted": "Lietotājs izdzēsts",
+ "desc": "Lietotāji, kas ir reģistrēti šajā serverī",
+ "edit_user": "Labot lietotāju",
+ "email": "E-pasta adrese",
+ "login": "Lietotāja vārds",
+ "none": "Pašlaik vēl nav neviena lietotāja.",
+ "save": "Saglabāt lietotāju",
+ "saved": "Lietotāja dati saglabāti",
+ "show": "Parādīt lietotājus",
+ "users": "Lietotāji"
+ },
+ "registries": {
+ "warning": "Šie repozitorijas pilnvaras būs pieejamas visiem lietotājiem.",
+ "desc": "Globāli repozitoriju pilnvaras var tikt pievienoti pielietošanai privātos attēlos visiem konvejerdarbiem."
+ }
+ }
},
- "enable": {
- "disabled": "Atspējots",
- "enable": "Iespējot",
- "enabled": "Jau ir iespējots",
- "list_reloaded": "Repozitoriju sarakts tika pārlādēts",
- "reload": "Pārlādēt repozitorijus",
- "success": "Repozitorijs iespējots"
+ "api": "API",
+ "back": "Atpakaļ",
+ "cancel": "Atcelt",
+ "default": "noklusētais",
+ "docs": "Dokumentācija",
+ "documentation_for": "Dokumentācija par \"{topic}\"",
+ "errors": {
+ "not_found": "Nevarēja atrast pieprasīto objektu"
},
- "manual_pipeline": {
- "select_branch": "Norādiet atzaru",
- "title": "Iniciēt manuālu konvejerdarba izpildi",
- "trigger": "Izpildīt konvejerdarbu",
- "variables": {
- "add": "Pievienot",
- "desc": "Norādiet papildus mainīgos, ko izmantot konvejerdarbā. Mainīgie ar tādu pašu nosaukumu tiks pārrakstīti.",
- "name": "Mainīgā nosaukums",
- "title": "Papildus konvejerdarba mainīgie",
- "value": "Mainīgā vērtība"
- }
+ "info": "Informācija",
+ "login": "Autorizēties",
+ "logout": "Iziet",
+ "not_found": {
+ "back_home": "Uz sākumu",
+ "not_found": "Ak vai, 404, vai nu mēs salauzām kaut ko, vai arī tika atvērta lapa, kas neeksistē :-/"
},
- "not_allowed": "Nav piekļuves šim repozitorijam",
- "open_in_forge": "Atvērt repozitoriju versijas kontroles sistēmā",
- "pipeline": {
- "actions": {
- "cancel": "Atcelt",
- "cancel_success": "Konvejerdarbs atcelts",
- "canceled": "Šis solis tika atcelts.",
- "deploy": "Uzstādīt",
- "log_auto_scroll": "Automātiski ritināt",
- "log_auto_scroll_off": "Atslēgt automātisko ritināšanu",
- "log_download": "Lejupielādēt",
- "restart": "Pārstartēt",
- "restart_success": "Konvejerdarbs pārstartēts"
- },
- "config": "Konfigurācija",
- "errors": "Kļūdas ({count})",
- "event": {
- "cron": "Plānotais darbs",
- "deploy": "Uzstādīšana",
- "manual": "Manuāls",
- "pr": "Izmaiņu pieprasījums",
- "push": "Iesūtīšana",
- "tag": "Tags"
- },
- "exit_code": "Iziešanas kods {exitCode}",
- "files": "Izmainītie faili ({files})",
- "loading": "Notiek ielāde…",
- "log_download_error": "Veicot žurnālfaila lejupielādi notika kļūda",
- "log_title": "Soļa žurnāls",
- "no_files": "Neviens fails nav mainīts.",
- "no_pipeline_steps": "Konvejerdarbam nav neviena soļa!",
- "no_pipelines": "Neviens konvejerdarbs vēl nav uzsākts.",
- "pipeline": "Konvejerdarbs #{pipelineId}",
- "pipelines_for": "Konvejerdarbi atzaram \"{branch}\"",
- "pipelines_for_pr": "Konvejerdarbi izmaiņu pieprasījumam #{index}",
- "protected": {
- "approve": "Apstiprināt",
- "approve_success": "Konvejerdarbs apstiprināts",
- "awaits": "Šim konvejerdarbam ir nepieciešams apstiprinājums no atbildīgajām personām!",
- "decline": "Noraidīt",
- "decline_success": "Konvejerdarbs noraidīts",
- "declined": "Šis konvejerdarbs tika noraidīts!",
- "review": "Pārskatiet izmaiņas"
- },
- "show_errors": "Rādīt kļūdas",
- "status": {
- "blocked": "bloķēts",
- "declined": "noraidīts",
- "error": "kļūda",
- "failure": "neveiksmīgs",
- "killed": "apturēts",
- "pending": "gaida izpildi",
- "running": "izpildās",
- "skipped": "izlaists",
- "started": "uzsākts",
- "status": "Statuss: {status}",
- "success": "izpildīts"
- },
- "step_not_started": "Šis solis vēl nav uzsākts.",
- "tasks": "Uzdevumi",
- "warnings": "Brīdinājumi ({count})",
- "we_got_some_errors": "Ak nē, notika kļūda!"
+ "org": {
+ "settings": {
+ "not_allowed": "Nav piekļuves šīs organizācijas iestatījumiem",
+ "secrets": {
+ "add": "Pievienot noslēpumu",
+ "created": "Organizācijas noslēpums izveidots",
+ "deleted": "Organizācijas noslēpums dzēsts",
+ "desc": "Noslēpumus var padot visu organizācijas repozitoriju konvejerdarba soļiem kā vides mainīgos.",
+ "events": {
+ "events": "Pieejams šādiem notikumiem",
+ "pr_warning": "Uzmanieties, jo šādā veidā tas būs pieejams visiem cilvēkiem, kas var iesūtīt izmaiņu pieprasījumu."
+ },
+ "images": {
+ "desc": "Ar komatiem atdalīts saraksts ar attēliem, kam šis noslēpums būs pieejams, atstājot tukšu, tas būs pieejams visiem attēliem",
+ "images": "Pieejami šādiem attēliem"
+ },
+ "name": "Nosaukums",
+ "none": "Pagaidām nav neviena organizācijas noslēpuma.",
+ "plugins_only": "Pieejams tikai spraudņiem",
+ "save": "Saglabāt noslēpumu",
+ "saved": "Organizācijas noslēpums saglabāts",
+ "secrets": "Noslēpumi",
+ "show": "Noslēpumu saraksts",
+ "value": "Vērtība"
+ },
+ "settings": "Iestatījumi",
+ "registries": {
+ "desc": "Organizācijas reģistrijas pilnvaras var tikt pievienoti, lai izmantotu privātas attēlos priekš visiem konvejerdarbiem organizācijā."
+ }
+ }
},
- "pull_requests": "Izmaiņu pieprasījumi",
- "settings": {
- "actions": {
- "actions": "Darbības",
- "delete": {
- "confirm": "Visi repozitorija dati tiks neatgriezeniski dzēsti!\n\nVai vēlaties turpināt?",
- "delete": "Dzēst repozitoriju",
- "success": "Repozitorijs dzēsts"
- },
- "disable": {
- "disable": "Atspējot repozitoriju",
- "success": "Repozitorijs atspējots"
+ "password": "Parole",
+ "pipeline_feed": "Konvejerdarba padeve",
+ "repo": {
+ "activity": "Aktivitāte",
+ "add": "Pievienot repozitoriju",
+ "branches": "Atzari",
+ "deploy_pipeline": {
+ "enter_target": "Mērķa uzstādīšanas vide",
+ "title": "Iniciēt uzstādīšanas notikumu šim konvejerdarbam #{pipelineId}",
+ "trigger": "Uzstādīt",
+ "variables": {
+ "add": "Pievienot mainīgo",
+ "desc": "Norādiet papildus mainīgos, ko izmantot konvejerdarbā. Mainīgie ar šādu pašu nosaukumu tiks pārrakstīti.",
+ "name": "Mainīgā nosaukums",
+ "title": "Papildus konvejerdarba mainīgie",
+ "value": "Mainīgā vērtība",
+ "delete": "Dzēst mainīgo"
+ },
+ "enter_task": "Uzstādīšanas uzdevums"
},
"enable": {
- "enable": "Iespējot repozitoriju",
- "success": "Repozitorijs iespējots"
+ "disabled": "Atspējots",
+ "enable": "Iespējot",
+ "enabled": "Jau ir iespējots",
+ "list_reloaded": "Repozitoriju sarakts tika pārlādēts",
+ "reload": "Pārlādēt repozitorijus",
+ "success": "Repozitorijs iespējots"
},
- "repair": {
- "repair": "Salabot repozitoriju",
- "success": "Repozitorijs salabots"
- }
- },
- "badge": {
- "badge": "Nozīmīte",
- "branch": "Atzars",
- "type": "Pieraksta veids",
- "type_html": "HTML",
- "type_markdown": "Markdown",
- "type_url": "URL"
- },
- "crons": {
- "add": "Pievienot plānoto darbu",
- "branch": {
- "placeholder": "Atzars (atstājiet tukšu, lai izmantotu noklusēto atzaru)",
- "title": "Atzars"
+ "manual_pipeline": {
+ "select_branch": "Norādiet atzaru",
+ "title": "Iniciēt manuālu konvejerdarba izpildi",
+ "trigger": "Izpildīt konvejerdarbu",
+ "variables": {
+ "add": "Pievienot",
+ "desc": "Norādiet papildus mainīgos, ko izmantot konvejerdarbā. Mainīgie ar tādu pašu nosaukumu tiks pārrakstīti.",
+ "name": "Mainīgā nosaukums",
+ "title": "Papildus konvejerdarba mainīgie",
+ "value": "Mainīgā vērtība",
+ "delete": "Dzēst mainīgo"
+ },
+ "show_pipelines": "Rādīt konvejerdarbus"
},
- "created": "Izveidots plānotais darbs",
- "crons": "Darbu plānotājs",
- "delete": "Dzēst darbu plānotāju",
- "deleted": "Plānotais darbs izdzēsts",
- "desc": "Darbu plānotājs var tikt izmantots, lai izpildītu konvejerdarbus pēc noteikta grafika.",
- "edit": "Labot darbu plānotāju",
- "name": {
- "name": "Nosaukums",
- "placeholder": "Plānotā darba nosaukums"
+ "not_allowed": "Nav piekļuves šim repozitorijam",
+ "open_in_forge": "Atvērt repozitoriju iekš forge",
+ "pipeline": {
+ "actions": {
+ "cancel": "Atcelt",
+ "cancel_success": "Konvejerdarbs atcelts",
+ "canceled": "Šis solis tika atcelts.",
+ "deploy": "Uzstādīt",
+ "log_auto_scroll": "Automātiski ritināt",
+ "log_auto_scroll_off": "Atslēgt automātisko ritināšanu",
+ "log_download": "Lejupielādēt",
+ "restart": "Pārstartēt",
+ "restart_success": "Konvejerdarbs pārstartēts",
+ "log_delete": "Dzēst"
+ },
+ "config": "Konfigurācija",
+ "errors": "Kļūdas ({count})",
+ "event": {
+ "cron": "Plānotais darbs",
+ "deploy": "Uzstādīšana",
+ "manual": "Manuāls",
+ "pr": "Izmaiņu pieprasījums",
+ "push": "Iesūtīšana",
+ "tag": "Tags",
+ "pr_closed": "Izmaiņu pieprasījums apvienots / aizvērts",
+ "release": "Relīze"
+ },
+ "exit_code": "Iziešanas kods {exitCode}",
+ "files": "Izmainītie faili ({files})",
+ "loading": "Notiek ielāde…",
+ "log_download_error": "Veicot žurnālfaila lejupielādi notika kļūda",
+ "log_title": "Soļa žurnāls",
+ "no_files": "Neviens fails nav mainīts.",
+ "no_pipeline_steps": "Konvejerdarbam nav neviena soļa!",
+ "no_pipelines": "Neviens konvejerdarbs vēl nav uzsākts.",
+ "pipeline": "Konvejerdarbs #{pipelineId}",
+ "pipelines_for": "Konvejerdarbi atzaram \"{branch}\"",
+ "pipelines_for_pr": "Konvejerdarbi izmaiņu pieprasījumam #{index}",
+ "protected": {
+ "approve": "Apstiprināt",
+ "approve_success": "Konvejerdarbs apstiprināts",
+ "awaits": "Šim konvejerdarbam ir nepieciešams apstiprinājums no atbildīgajām personām!",
+ "decline": "Noraidīt",
+ "decline_success": "Konvejerdarbs noraidīts",
+ "declined": "Šis konvejerdarbs tika noraidīts!",
+ "review": "Pārskatiet izmaiņas"
+ },
+ "show_errors": "Rādīt kļūdas",
+ "status": {
+ "blocked": "bloķēts",
+ "declined": "noraidīts",
+ "error": "kļūda",
+ "failure": "neveiksmīgs",
+ "killed": "apturēts",
+ "pending": "gaida izpildi",
+ "running": "izpildās",
+ "skipped": "izlaists",
+ "started": "uzsākts",
+ "status": "Statuss: {status}",
+ "success": "izpildīts"
+ },
+ "step_not_started": "Šis solis vēl nav uzsākts.",
+ "tasks": "Uzdevumi",
+ "warnings": "Brīdinājumi ({count})",
+ "we_got_some_errors": "Ak nē, notika kļūda!",
+ "no_logs": "Nav darbību žurnālu",
+ "duration": "Konvejerdarba ilgums",
+ "created": "Izveidots: {created}",
+ "log_delete_confirm": "Vai tiešām vēlaties dzēst šī soļa darbību žurnālus?",
+ "log_delete_error": "Notika kļūda dzēšot šī soļa darbību žurnālus"
},
- "next_exec": "Nākošā izpilde",
- "none": "Nav pievienots neviens plānotais darbs.",
- "not_executed_yet": "Vēl ne reizi nav izpildīts",
- "run": "Izpildīt tagad",
- "save": "Saglabāt plānoto darbu",
- "saved": "Plānotā darba izmaiņas saglabātas",
- "schedule": {
- "placeholder": "Grafiks",
- "title": "Grafiks (balstīts uz UTC laika joslu)"
+ "pull_requests": "Izmaiņu pieprasījumi",
+ "settings": {
+ "actions": {
+ "actions": "Darbības",
+ "delete": {
+ "confirm": "Visi repozitorija dati tiks neatgriezeniski dzēsti!\n\nVai vēlaties turpināt?",
+ "delete": "Dzēst repozitoriju",
+ "success": "Repozitorijs dzēsts"
+ },
+ "disable": {
+ "disable": "Atspējot repozitoriju",
+ "success": "Repozitorijs atspējots"
+ },
+ "enable": {
+ "enable": "Iespējot repozitoriju",
+ "success": "Repozitorijs iespējots"
+ },
+ "repair": {
+ "repair": "Salabot repozitoriju",
+ "success": "Repozitorijs salabots"
+ }
+ },
+ "badge": {
+ "badge": "Nozīmīte",
+ "branch": "Atzars",
+ "type": "Pieraksta veids",
+ "type_html": "HTML",
+ "type_markdown": "Markdown",
+ "type_url": "URL"
+ },
+ "crons": {
+ "add": "Pievienot plānoto darbu",
+ "branch": {
+ "placeholder": "Atzars (atstājiet tukšu, lai izmantotu noklusēto atzaru)",
+ "title": "Atzars"
+ },
+ "created": "Izveidots plānotais darbs",
+ "crons": "Darbu plānotājs",
+ "delete": "Dzēst darbu plānotāju",
+ "deleted": "Plānotais darbs izdzēsts",
+ "desc": "Darbu plānotājs var tikt izmantots, lai izpildītu konvejerdarbus pēc noteikta grafika.",
+ "edit": "Labot darbu plānotāju",
+ "name": {
+ "name": "Nosaukums",
+ "placeholder": "Plānotā darba nosaukums"
+ },
+ "next_exec": "Nākošā izpilde",
+ "none": "Nav pievienots neviens plānotais darbs.",
+ "not_executed_yet": "Vēl ne reizi nav izpildīts",
+ "run": "Izpildīt tagad",
+ "save": "Saglabāt plānoto darbu",
+ "saved": "Plānotā darba izmaiņas saglabātas",
+ "schedule": {
+ "placeholder": "Grafiks",
+ "title": "Grafiks (balstīts uz UTC laika joslu)"
+ },
+ "show": "Parādīt plānotos darbus"
+ },
+ "general": {
+ "allow_pr": {
+ "allow": "Atļaut izmaiņu pieprasījumiem",
+ "desc": "Ļaut izpildīt konvejerdarbus izmaiņu pieprasījumiem."
+ },
+ "cancel_prev": {
+ "cancel": "Atcelt iepriekšējos konvejerdarbus",
+ "desc": "Iespējojot šo pazīmi, tiks atcelti visi iepriekšējie konvejerdarbi, kuriem sakrīt notikums un konteksts."
+ },
+ "general": "Pamata",
+ "netrc_only_trusted": {
+ "desc": "Atļaut izmantot Git autorizāciju tikai uzticamiem konteineriem (ieteicams).",
+ "netrc_only_trusted": "Atļaut izmantot Git autorizāciju tikai uzticamiem konteineriem"
+ },
+ "pipeline_path": {
+ "default": "Pēc noklusējuma: .woodpecker/*.{'{yaml,yml}'} -> .woodpecker.yaml -> .woodpecker.yml",
+ "desc": "Ceļš uz konvejerdarba konfigurāciju, piemēram, {0}. Mapēm jābeidzas ar {0}.",
+ "desc_path_example": "mans/ceļš/",
+ "path": "Konvejerdarba ceļš"
+ },
+ "project": "Projekta iestatījumi",
+ "protected": {
+ "desc": "Nepieciešams apstiprināt visus konvejerdarbus pirms tie tiek izpildīti.",
+ "protected": "Aizsargāts"
+ },
+ "save": "Saglabāt iestatījumus",
+ "success": "Repozitorija iestatījumi tika saglabāti",
+ "timeout": {
+ "minutes": "minūtes",
+ "timeout": "Noildze"
+ },
+ "trusted": {
+ "desc": "Konvejerdarba konteineri tiks izpildīti ar paaugstinātām tiesībām (piemēram, piesaistīt servera direktorijas).",
+ "trusted": "Uzticams"
+ },
+ "visibility": {
+ "internal": {
+ "desc": "Tikai autorizēti lietotāji var piekļūt šim projektam.",
+ "internal": "Iekšējs"
+ },
+ "private": {
+ "desc": "Tikai lietotāji, kam ir tiesības uz repozitoriju, var piekļūt šim projektam.",
+ "private": "Privāts"
+ },
+ "public": {
+ "desc": "Ikviens var piekļūt projektam, arī neautorizētie lietotāji.",
+ "public": "Publisks"
+ },
+ "visibility": "Projekta redzamība"
+ },
+ "allow_deploy": {
+ "desc": "Atļaut publicēšanu no veiksmīgiem konvejerdarbiem. Lietot tikai ja Jūs uzticaties visiem lietotājiem ar push permisijām.",
+ "allow": "Atļaut publicēšanu"
+ }
+ },
+ "not_allowed": "Nav piekļuves šī repozitorija iestatījumiem",
+ "registries": {
+ "add": "Pievienot reģistru",
+ "address": {
+ "address": "Adrese",
+ "placeholder": "Reģistra adrese, piemēram, docker.io"
+ },
+ "created": "Reģistra autorizācijas dati pievienoti",
+ "credentials": "Reģistru autorizācijas dati",
+ "delete": "Dzēst reģistra autorizācijas datus",
+ "deleted": "Reģistra autorizācijas dati dzēsti",
+ "desc": "Reģistru autorizācijas dati var tikt izmantoti, lai izmantotu attēlos no privātiem reģistriem, konvjerdarbu soļos.",
+ "edit": "Labot reģistra autorizācijas datus",
+ "none": "Pašlaik nav pievienots neviens reģistrs.",
+ "registries": "Reģistri",
+ "save": "Saglabāt reģistru",
+ "saved": "Reģistra autorizācijas dati saglabāti",
+ "show": "Reģistru saraksts"
+ },
+ "secrets": {
+ "add": "Pievienot noslēpumu",
+ "created": "Noslēpums izveidots",
+ "delete": "Dzēst noslēpumu",
+ "delete_confirm": "Vai patiešām vēlaties dzēst šo noslēpumu?",
+ "deleted": "Noslēpums dzēsts",
+ "desc": "Noslēpumus var padot individuāliem konvejerdarba soļiem izpildes laikā kā vides mainīgos.",
+ "edit": "Labot noslēpumu",
+ "events": {
+ "events": "Pieejams šādiem notikumiem",
+ "pr_warning": "Uzmanieties, jo šādā veidā tas būs pieejams visiem cilvēkiem, kas var iesūtīt izmaiņu pieprasījumu."
+ },
+ "images": {
+ "desc": "Ar komatiem atdalīts saraksts ar attēliem, kam šis noslēpums būs pieejams, atstājot tukšu, tas būs pieejams visiem attēliem",
+ "images": "Pieejams šādiem attēliem"
+ },
+ "name": "Nosaukums",
+ "none": "Pagaidām nav neviena noslēpuma.",
+ "plugins_only": "Pieejams tikai spraudņiem",
+ "save": "Saglabāt noslēpumu",
+ "saved": "Noslēpums saglabāts",
+ "secrets": "Noslēpumi",
+ "show": "Noslēpumu saraksts",
+ "value": "Vērtība"
+ },
+ "settings": "Iestatījumi"
},
- "show": "Parādīt plānotos darbus"
- },
- "general": {
- "allow_pr": {
- "allow": "Atļaut izmaiņu pieprasījumiem",
- "desc": "Ļaut izpildīt konvejerdarbus izmaiņu pieprasījumiem."
- },
- "cancel_prev": {
- "cancel": "Atcelt iepriekšējos konvejerdarbus",
- "desc": "Iespējojot šo pazīmi, tiks atcelti visi iepriekšējie konvejerdarbi, kuriem sakrīt notikums un konteksts."
- },
- "general": "Pamata",
- "netrc_only_trusted": {
- "desc": "Atļaut izmantot Git autorizāciju tikai uzticamiem konteineriem (ieteicams).",
- "netrc_only_trusted": "Atļaut izmantot Git autorizāciju tikai uzticamiem konteineriem"
- },
- "pipeline_path": {
- "default": "Pēc noklusējuma: .woodpecker/*.{'{yaml,yml}'} -> .woodpecker.yaml -> .woodpecker.yml",
- "desc": "Ceļš uz konvejerdarba konfigurāciju, piemēram, {0}. Mapēm jābeidzas ar {0}.",
- "desc_path_example": "mans/ceļš/",
- "path": "Konvejerdarba ceļš"
- },
- "project": "Projekta iestatījumi",
- "protected": {
- "desc": "Nepieciešams apstiprināt visus konvejerdarbus pirms tie tiek izpildīti.",
- "protected": "Aizsargāts"
- },
- "save": "Saglabāt iestatījumus",
- "success": "Repozitorija iestatījumi tika saglabāti",
- "timeout": {
- "minutes": "minūtes",
- "timeout": "Noildze"
- },
- "trusted": {
- "desc": "Konvejerdarba konteineri tiks izpildīti ar paaugstinātām tiesībām, piemēram, piesaistīt servera direktorijas.",
- "trusted": "Uzticams"
- },
- "visibility": {
- "internal": {
- "desc": "Tikai autorizēti lietotāji var piekļūt šim projektam.",
- "internal": "Iekšējs"
- },
- "private": {
- "desc": "Tikai lietotāji, kam ir tiesības uz repozitoriju, var piekļūt šim projektam.",
- "private": "Privāts"
- },
- "public": {
- "desc": "Ikviens var piekļūt projektam, arī neautorizētie lietotāji.",
- "public": "Publisks"
- },
- "visibility": "Projekta redzamība"
- }
- },
- "not_allowed": "Nav piekļuves šī repozitorija iestatījumiem",
- "registries": {
- "add": "Pievienot reģistru",
- "address": {
- "address": "Adrese",
- "placeholder": "Reģistra adrese, piemēram, docker.io"
- },
- "created": "Reģistra autorizācijas dati pievienoti",
- "credentials": "Reģistru autorizācijas dati",
- "delete": "Dzēst reģistra autorizācijas datus",
- "deleted": "Reģistra autorizācijas dati dzēsti",
- "desc": "Reģistru autorizācijas dati var tikt izmantoti, lai izmantotu attēlos no privātiem reģistriem, konvjerdarbu soļos.",
- "edit": "Labot reģistra autorizācijas datus",
- "none": "Pašlaik nav pievienots neviens reģistrs.",
- "registries": "Reģistri",
- "save": "Saglabāt reģistru",
- "saved": "Reģistra autorizācijas dati saglabāti",
- "show": "Reģistru saraksts"
- },
- "secrets": {
- "add": "Pievienot noslēpumu",
- "created": "Noslēpums izveidots",
- "delete": "Dzēst noslēpumu",
- "delete_confirm": "Vai patiešām vēlaties dzēst šo noslēpumu?",
- "deleted": "Noslēpums dzēsts",
- "desc": "Noslēpumus var padot individuāliem konvejerdarba soļiem izpildes laikā kā vides mainīgos.",
- "edit": "Labot noslēpumu",
- "events": {
- "events": "Pieejams šādiem notikumiem",
- "pr_warning": "Uzmanieties, jo šādā veidā tas būs pieejams visiem cilvēkiem, kas var iesūtīt izmaiņu pieprasījumu."
- },
- "images": {
- "desc": "Ar komatiem atdalīts saraksts ar attēliem, kam šis noslēpums būs pieejams, atstājot tukšu, tas būs pieejams visiem attēliem",
- "images": "Pieejams šādiem attēliem"
- },
- "name": "Nosaukums",
- "none": "Pagaidām nav neviena noslēpuma.",
- "plugins_only": "Pieejams tikai spraudņiem",
- "save": "Saglabāt noslēpumu",
- "saved": "Noslēpums saglabāts",
- "secrets": "Noslēpumi",
- "show": "Noslēpumu saraksts",
- "value": "Vērtība"
- },
- "settings": "Iestatījumi"
+ "user_none": "Šai organizācijai/lietotājam pagaidām nav neviena projekta."
},
- "user_none": "Šai organizācijai/lietotājam pagaidām nav neviena projekta."
- },
- "repos": "Repozitoriji",
- "repositories": "Repozitoriji",
- "running_version": "Tiek izmantota Woodpecker CI versija {0}",
- "search": "Meklēt…",
- "time": {
- "days_short": "dien.",
- "hours_short": "st.",
- "min_short": "min.",
- "not_started": "nav uzsākts",
- "sec_short": "sek.",
- "template": "YYYY. [gada] D. MMMM, HH:mm z",
- "weeks_short": "ned."
- },
- "unknown_error": "Notika neparedzēta kļūda",
- "update_woodpecker": "Pieejama jauna Woodpecker CI versija {0}",
- "url": "URL",
- "user": {
- "access_denied": "Jums nav tiesību autorizēties",
- "internal_error": "Notikusi sistēmas iekšējā kļūda",
- "oauth_error": "Neizdevās autorizēties, izmantojot, OAuth piegādātāju",
- "settings": {
- "api": {
- "api": "API",
- "api_usage": "Piemērs API lietošanai",
- "cli_usage": "Piemērs komandrindas lietošanai",
- "desc": "Personīgā piekļuves pilnvara un API lietošana",
- "dl_cli": "Lejupielādēt komandrindas rīku",
- "reset_token": "Atiestatīt pilnvaru",
- "shell_setup": "Komandrindas iestatīšana",
- "shell_setup_before": "nepieciešamie komandrindas iestatīšanas soļi",
- "swagger_ui": "API dokumentācija",
- "token": "Personīgā piekļuves pilnvara"
- },
- "general": {
- "general": "Vispārīgi",
- "language": "Valoda",
- "theme": {
- "auto": "Noteikt automātiski",
- "dark": "Tumšā",
- "light": "Gaišā",
- "theme": "Tēma"
+ "repos": "Repozitorijas",
+ "repositories": "Repozitoriji",
+ "running_version": "Tiek izmantota Woodpecker {0}",
+ "search": "Meklēt…",
+ "time": {
+ "days_short": "dien.",
+ "hours_short": "st.",
+ "min_short": "min.",
+ "not_started": "nav uzsākts",
+ "sec_short": "sek.",
+ "template": "YYYY. [gada] D. MMMM, HH:mm z",
+ "weeks_short": "ned."
+ },
+ "unknown_error": "Notika neparedzēta kļūda",
+ "update_woodpecker": "Lūdzu atjauniniet Woodpecker instanci uz {0}",
+ "url": "URL",
+ "user": {
+ "access_denied": "Jums nav tiesību autorizēties",
+ "internal_error": "Notikusi sistēmas iekšējā kļūda",
+ "oauth_error": "Neizdevās autorizēties, izmantojot, OAuth piegādātāju",
+ "settings": {
+ "api": {
+ "api": "API",
+ "api_usage": "Piemērs API lietošanai",
+ "cli_usage": "Piemērs komandrindas lietošanai",
+ "desc": "Personīgā piekļuves pilnvara un API lietošana",
+ "dl_cli": "Lejupielādēt komandrindas rīku",
+ "reset_token": "Atiestatīt pilnvaru",
+ "shell_setup": "Komandrindas iestatīšana",
+ "shell_setup_before": "nepieciešamie komandrindas iestatīšanas soļi",
+ "swagger_ui": "API dokumentācija",
+ "token": "Personīgā piekļuves pilnvara"
+ },
+ "general": {
+ "general": "Vispārīgi",
+ "language": "Valoda",
+ "theme": {
+ "auto": "Noteikt automātiski",
+ "dark": "Tumšā",
+ "light": "Gaišā",
+ "theme": "Tēma"
+ }
+ },
+ "secrets": {
+ "add": "Pievienot noslēpumu",
+ "created": "Lietotāja noslēpums tika izveidots",
+ "deleted": "Lietotāja noslēpums tika izdzēsts",
+ "desc": "Lietotāja noslēpumi var tikt padoti personīgajiem konvejerdarbu soļiem kā vides mainīgie.",
+ "events": {
+ "events": "Pieejams notikumiem",
+ "pr_warning": "Esiet uzmanīgi atzīmējot šo pazīmi, jo tas var tikt izmantots, lai izmaiņu pieprasījumā atklātu šī noslēpuma vērtību, nepiederošām personām."
+ },
+ "images": {
+ "desc": "Ar komatu attdalīts saraksts ar attēlu nosaukumiem, kam šis noslēpums būs pieejams, atstājiet tukšu, lai tas būtu pieejams visiem attēliem",
+ "images": "Pieejams šādiem soļu attēliem"
+ },
+ "name": "Nosaukums",
+ "none": "Pagaidām nav neviena lietotāja noslēpuma.",
+ "plugins_only": "Pieejams tikai spraudņiem",
+ "save": "Saglabāt noslēpumu",
+ "saved": "Lietotāja noslēpums tika saglabāts",
+ "secrets": "Noslēpumi",
+ "show": "Parādīt noslēpumus",
+ "value": "Vērtība"
+ },
+ "settings": "Lietotāja iestatījumi",
+ "registries": {
+ "desc": "Lietotāju reģistra pilnvaras var tikt pielietotas privātos attēlos priekš personīgiem konvejerdarbiem."
+ },
+ "cli_and_api": {
+ "token": "Personīgās Piekļuves Žetons",
+ "api_usage": "Piemēra API pielietošana",
+ "cli_usage": "Piemēra CLI lietošana",
+ "download_cli": "Lejupielādēt CLI",
+ "reset_token": "Atiestatīt žetonu",
+ "swagger_ui": "Swagger UI",
+ "cli_and_api": "CLI & API",
+ "desc": "Personīgās Piekļuves Žetons, CLI un API pielietošna"
+ }
}
- },
- "secrets": {
+ },
+ "username": "Lietotājvārds",
+ "welcome": "Woodpecker",
+ "secrets": {
+ "secrets": "Noslēpumi",
+ "none": "Pašlaik nav vides noslēpumu.",
"add": "Pievienot noslēpumu",
- "created": "Lietotāja noslēpums tika izveidots",
- "deleted": "Lietotāja noslēpums tika izdzēsts",
- "desc": "Lietotāja noslēpumi var tikt padoti uz visiem lietotāja repozitoriju konvejerdarbu soļiem kā vides mainīgie.",
+ "save": "Saglabāt noslēpumu",
+ "show": "Rādīt noslēpumus",
+ "name": "Nosaukums",
+ "value": "Vērtība",
+ "delete_confirm": "Vai tiešām vēlaties dzēst šo noslēpumu?",
+ "saved": "Noslēpums saglabāts",
"events": {
- "events": "Pieejams notikumiem",
- "pr_warning": "Esiet uzmanīgi atzīmējot šo pazīmi, jo tas var tikt izmantots, lai izmaiņu pieprasījumā atklātu šī noslēpuma vērtību, nepiederošām personām."
+ "events": "Pieejams sekojošajos notikumos",
+ "pr_warning": "Lūdzu esiet uzmanīgi ar šo iestatījumu: ļaunprātīgs aktieris var iesniegt ļaunprātīgu pull request, kas atklās noslēpumus."
},
"images": {
- "desc": "Ar komatu attdalīts saraksts ar attēlu nosaukumiem, kam šis noslēpums būs pieejams, atstājiet tukšu, lai tas būtu pieejams visiem attēliem",
- "images": "Pieejams šādiem soļu attēliem"
+ "desc": "Saraksts ar attēliem, kuriem šis noslēpums ir pieejams. Atstāt tukšu, lai atļautu visos attēlos.",
+ "images": "Pieejams sekojošiem attēliem"
},
- "name": "Nosaukums",
- "none": "Pagaidām nav neviena lietotāja noslēpuma.",
- "plugins_only": "Pieejams tikai spraudņiem",
- "save": "Saglabāt noslēpumu",
- "saved": "Lietotāja noslēpums tika saglabāts",
- "secrets": "Noslēpumi",
- "show": "Parādīt noslēpumus",
- "value": "Vērtība"
- },
- "settings": "Lietotāja iestatījumi"
- }
- },
- "username": "Lietotāja vārds",
- "welcome": "Woodpecker"
+ "edit": "Rediģēt noslēpumu",
+ "desc": "Noslēpumi var tikt padoti individuāliem konvejerdarbu soļiem kā vides mainīgie.",
+ "deleted": "Noslēpums dzēsts",
+ "created": "Noslēpums izveidots",
+ "delete": "Dzēst noslēpumu"
+ },
+ "registries": {
+ "delete_confirm": "Vai tiešām vēlaties dzēst šo reģistru?",
+ "created": "Reģistra pilnvaras izveidotas",
+ "view": "Skatīt reģistru",
+ "edit": "Rediģēt reģistru",
+ "delete": "Dzēst reģistru",
+ "saved": "Reģistra pilnvaras saglabātas",
+ "deleted": "Reģistra pilnvaras dzēstas",
+ "save": "Saglabāt reģistru",
+ "add": "Pievienot reģistru",
+ "registries": "Reģistrijas",
+ "credentials": "Reģistriju pilnvaras",
+ "desc": "Reģistriju pilnvaras var tikt pievienotas pielietošanai privātos attēlos priekš konvejerdarbiem.",
+ "none": "Pašlaik nav rēģistrijas pilnvaru.",
+ "address": {
+ "address": "Adreses",
+ "desc": "Reģistrijas adreses (piem. docker.io)"
+ },
+ "show": "Rādīt reģistrijas"
+ },
+ "oauth_error": "Kļūda autentificējoties pret OAuth nodrošinātāju",
+ "internal_error": "Notikušas dažas iekšējās kļūdas",
+ "registration_closed": "Reģistrācijas process ir aizvērts",
+ "access_denied": "Jums nav atļaujas piekļūt šai instancei",
+ "invalid_state": "OAuth stāvoklis nav valīds",
+ "org_level_secret": "organizācijas noslēpums",
+ "cli_login_success": "Autorizēšanās CLI veiksmīga",
+ "login_to_cli": "Autorizēties CLI",
+ "login_to_cli_description": "Turpinot, Jūs autorizēs iekš CLI.",
+ "abort": "Aborts",
+ "cli_login_failed": "Autorizešanās pie CLI neizdevās",
+ "return_to_cli": "Jūs varat aizvērt šo cilni un atgriezties pie CLI.",
+ "settings": "Iestatījumi",
+ "login_with": "Autorizēties ar {forge}",
+ "empty_list": "Nav {entity}!",
+ "global_level_secret": "globāls noslēpums",
+ "cli_login_denied": "Autorizešanās pie CLI liegta"
}
diff --git a/web/src/assets/locales/ru.json b/web/src/assets/locales/ru.json
index 3772c78f6..44ebe543c 100644
--- a/web/src/assets/locales/ru.json
+++ b/web/src/assets/locales/ru.json
@@ -1,510 +1,609 @@
{
- "admin": {
- "settings": {
- "agents": {
- "add": "Добавить обработчик",
- "agents": "Обработчики",
- "backend": {
- "backend": "Бэкенд",
- "badge": "бэкенд"
- },
- "capacity": {
- "badge": "мощность",
- "capacity": "Мощность",
- "desc": "Максимальное количество конвейеров, выполняемых параллельно этим агентом."
- },
- "created": "Обработчик успешно добавлен",
- "delete_agent": "Удалить агент",
- "delete_confirm": "Вы действительно хотите удалить этот обработчик? Он больше не сможет подключаться к серверу.",
- "deleted": "Обработчик успешно удалён",
- "desc": "Обработчики, зарегистрированные на этом сервере",
- "edit_agent": "Редактировать агент",
- "id": "ID",
- "last_contact": "Последние подключение",
- "name": {
- "name": "Название",
- "placeholder": "Название обработчика"
- },
- "never": "Никогда",
- "no_schedule": {
- "name": "Отключить обработчик",
- "placeholder": "Запретить обработчику получать новые задачи"
- },
- "none": "Пока обработчики отсутствуют.",
- "platform": {
- "badge": "платформа",
- "platform": "Платформа"
- },
- "save": "Сохранить обработчик",
- "saved": "Обработчик сохранён",
- "show": "Показать обработчики",
- "token": "Токен",
- "version": "Версия"
- },
- "not_allowed": "У вас нет прав для доступа к настройкам сервера",
- "orgs": {
- "delete_confirm": "Вы действительно хотите удалить эту организацию? При этом также будут удалены все репозитории, принадлежащие этой организации.",
- "delete_org": "Удалить организацию",
- "deleted": "Организация удалена",
- "desc": "Организации, владеющие репозиториями на этом сервере",
- "none": "Здесь еще нет организаций.",
- "org_settings": "Настройки организации",
- "orgs": "Организации",
- "view": "Просмотр организации"
- },
- "queue": {
- "agent": "агент",
- "desc": "Задачи, ожидающие выполнения агентами",
- "pause": "Пауза",
- "paused": "Очередь при остановлена",
- "queue": "Очередь",
- "resume": "Продолжить",
- "resumed": "Очередь возобновлена",
- "stats": {
- "completed_count": "Завершённые задачи",
- "pending_count": "Ожидает",
- "running_count": "Выполняется",
- "waiting_on_deps_count": "Ожидает зависимостей",
- "worker_count": "Свободно"
- },
- "task_pending": "Задача ожидает",
- "task_running": "Задача выполняется",
- "task_waiting_on_deps": "Задача ожидает завершения выполнения зависимостей",
- "tasks": "Задачи",
- "waiting_for": "в ожидании"
- },
- "repos": {
- "desc": "Репозитории, которые включены или были включены на этом сервере",
- "disabled": "Отключено",
- "none": "Здесь еще нет репозиториев.",
- "repair": {
- "repair": "Исправить все",
- "success": "Репозитории исправлены"
- },
- "repos": "Репозитории",
- "settings": "Настройки репозитория",
- "view": "Просмотр репозитория"
- },
- "secrets": {
- "add": "Создать секрет",
- "created": "Глобальный секрет создан",
- "deleted": "Глобальный секрет удалён",
- "desc": "Глобальные секреты могут быть переданы всем репозиториям и отдельным этапам конвейера во время выполнения в качестве переменных окружения.",
- "events": {
- "events": "Доступен для следующих событий",
- "pr_warning": "Пожалуйста, будьте осторожны с этой опцией, так как злоумышленник может отправить вредоносный запрос на слияние, который раскроет ваши секреты."
- },
- "images": {
- "desc": "Список образов, для которых доступен этот секрет. Оставьте поле пустым, чтобы разрешить все образы",
- "images": "Доступен только для этих образов"
- },
- "name": "Название",
- "none": "Тут пока нет глобальных секретов.",
- "plugins_only": "Доступен только для расширений",
- "save": "Сохранить секрет",
- "saved": "Глобальный секрет сохранён",
- "secrets": "Секреты",
- "show": "Показать секрет",
- "value": "Значение",
- "warning": "Эти секреты будут доступны всем пользователям сервера."
- },
- "settings": "Настройки",
- "users": {
- "add": "Добавить пользователя",
- "admin": {
- "admin": "Администратор",
- "placeholder": "Пользователь является администратором"
- },
- "avatar_url": "URL аватара",
- "cancel": "Отмена",
- "created": "Пользователь успешно создан",
- "delete_confirm": "Вы действительно хотите удалить этого пользователя? При этом также будут удалены все репозитории, принадлежащие этому пользователю.",
- "delete_user": "Удалить пользователя",
- "deleted": "Пользователь успешно удалён",
- "desc": "Пользователи, зарегистрированные на этом сервере",
- "edit_user": "Изменить пользователя",
- "email": "Почта",
- "login": "Вход в систему",
- "none": "Пока тут нет пользователей.",
- "save": "Сохранить пользователя",
- "saved": "Пользователь сохранён",
- "show": "Показать пользователей",
- "users": "Пользователи"
- }
- }
- },
- "api": "API",
- "back": "Назад",
- "cancel": "Отменить",
- "default": "по умолчанию",
- "docs": "Документация",
- "documentation_for": "Документация о \"{topic}\"",
- "errors": {
- "not_found": "Серверу не удалось найти запрошенный объект"
- },
- "global_level_secret": "глобальный секрет",
- "info": "Информация",
- "login": "Вход",
- "logout": "Выйти",
- "not_found": {
- "back_home": "Вернуться на главную",
- "not_found": "Ошибка 404. Проверьте что ввели адрес правильно :-/"
- },
- "org": {
- "settings": {
- "not_allowed": "У вас нет прав для доступа к настройкам этой организации",
- "secrets": {
- "add": "Создать секрет",
- "created": "Секрет организации успешно добавлен",
- "deleted": "Секрет организации был удалён",
- "desc": "Секреты этой организации передаются всем шагам любого конвейера, принадлежащего этой организации, во время выполнения в качестве переменных среды.",
- "events": {
- "events": "Доступен для следующих событий",
- "pr_warning": "Пожалуйста, будьте осторожны с этой опцией, так как злоумышленник может отправить вредоносный запрос на слияние, который раскроет ваши секреты."
- },
- "images": {
- "desc": "Список образов, для которых доступен этот секрет. Оставьте поле пустым, чтобы разрешить все образы",
- "images": "Доступен только для этих образов"
- },
- "name": "Название",
- "none": "Тут пока нет секретов организации.",
- "plugins_only": "Доступен только для расширений",
- "save": "Сохранить секрет",
- "saved": "Секрет организации успешно обновлён",
- "secrets": "Секреты",
- "show": "Показать секрет",
- "value": "Значение"
- },
- "settings": "Настройки"
- }
- },
- "org_level_secret": "секрет организации",
- "password": "Пароль",
- "pipeline_feed": "Состояние конвейеров",
- "repo": {
- "activity": "Активность",
- "add": "Подключить репозиторий",
- "branches": "Ветви",
- "deploy_pipeline": {
- "enter_target": "Целевая среда развертывания",
- "title": "Вызвать событие развертывания для текущего конвейера #{pipelineId}",
- "trigger": "Развернуть",
- "variables": {
- "add": "Добавить переменную",
- "desc": "Укажите дополнительные переменные для использования в конвейере. Переменные с одинаковыми именами будут перезаписаны.",
- "name": "Имя переменой",
- "title": "Дополнительные переменные для конвейера",
- "value": "Значение переменой"
- }
+ "admin": {
+ "settings": {
+ "agents": {
+ "add": "Добавить обработчик",
+ "agents": "Обработчики",
+ "backend": {
+ "backend": "Бэкенд",
+ "badge": "бэкенд"
+ },
+ "capacity": {
+ "badge": "мощность",
+ "capacity": "Мощность",
+ "desc": "Максимальное количество конвейеров, выполняемых параллельно этим обработчиком."
+ },
+ "created": "Обработчик успешно добавлен",
+ "delete_agent": "Удалить обработчик",
+ "delete_confirm": "Вы действительно хотите удалить этот обработчик? Он больше не сможет подключаться к серверу.",
+ "deleted": "Обработчик успешно удалён",
+ "desc": "Обработчики, зарегистрированные на этом сервере.",
+ "edit_agent": "Редактировать обработчик",
+ "id": "ID",
+ "last_contact": "Последняя активность",
+ "name": {
+ "name": "Название",
+ "placeholder": "Название обработчика"
+ },
+ "never": "Никогда",
+ "no_schedule": {
+ "name": "Отключить обработчик",
+ "placeholder": "Запретить обработчику получать новые задачи"
+ },
+ "none": "Обработчиков пока нет.",
+ "platform": {
+ "badge": "платформа",
+ "platform": "Платформа"
+ },
+ "save": "Сохранить обработчик",
+ "saved": "Обработчик сохранён",
+ "show": "Показать обработчики",
+ "token": "Токен",
+ "version": "Версия"
+ },
+ "not_allowed": "У вас нет прав доступа к настройкам сервера.",
+ "orgs": {
+ "delete_confirm": "Вы действительно хотите удалить эту организацию? При этом также будут удалены все репозитории, принадлежащие этой организации.",
+ "delete_org": "Удалить организацию",
+ "deleted": "Организация удалена",
+ "desc": "Организации, владеющие репозиториями на этом сервере.",
+ "none": "Организаций пока нет.",
+ "org_settings": "Настройки организации",
+ "orgs": "Организации",
+ "view": "Просмотр организации"
+ },
+ "queue": {
+ "agent": "обработчик",
+ "desc": "Задачи, ожидающие выполнения обработчиками",
+ "pause": "Приостановить",
+ "paused": "Очередь приостановлена",
+ "queue": "Очередь",
+ "resume": "Продолжить",
+ "resumed": "Очередь возобновлена",
+ "stats": {
+ "completed_count": "Завершённые задачи",
+ "pending_count": "Ожидает",
+ "running_count": "Выполняется",
+ "waiting_on_deps_count": "Ожидает зависимостей",
+ "worker_count": "Свободно"
+ },
+ "task_pending": "Задача ожидает",
+ "task_running": "Задача выполняется",
+ "task_waiting_on_deps": "Задача ожидает завершения выполнения зависимостей",
+ "tasks": "Задачи",
+ "waiting_for": "в ожидании"
+ },
+ "repos": {
+ "desc": "Репозитории, включенные в данный момент, или включавшиеся когда-либо ранее на этом сервере.",
+ "disabled": "Отключено",
+ "none": "Репозиториев пока нет.",
+ "repair": {
+ "repair": "Исправить все",
+ "success": "Репозитории исправлены"
+ },
+ "repos": "Репозитории",
+ "settings": "Настройки репозитория",
+ "view": "Просмотр репозитория"
+ },
+ "secrets": {
+ "add": "Создать секрет",
+ "created": "Глобальный секрет создан",
+ "deleted": "Глобальный секрет удалён",
+ "desc": "Глобальные секреты могут быть переданы в виде переменных окружения всем этапам конвейера во всех репозиториях.",
+ "events": {
+ "events": "Доступен для следующих событий",
+ "pr_warning": "Пожалуйста, будьте осторожны с этой опцией, так как злоумышленник может отправить вредоносный запрос на слияние, который раскроет ваши секреты."
+ },
+ "images": {
+ "desc": "Список образов, для которых доступен этот секрет. Оставьте поле пустым, чтобы разрешить все образы",
+ "images": "Доступен только для этих образов"
+ },
+ "name": "Название",
+ "none": "Тут пока нет глобальных секретов.",
+ "plugins_only": "Доступен только для расширений",
+ "save": "Сохранить секрет",
+ "saved": "Глобальный секрет сохранён",
+ "secrets": "Секреты",
+ "show": "Показать секрет",
+ "value": "Значение",
+ "warning": "Эти секреты будут доступны всем пользователям."
+ },
+ "settings": "Настройки",
+ "users": {
+ "add": "Добавить пользователя",
+ "admin": {
+ "admin": "Администратор",
+ "placeholder": "Пользователь является администратором"
+ },
+ "avatar_url": "URL аватара",
+ "cancel": "Отмена",
+ "created": "Пользователь успешно создан",
+ "delete_confirm": "Вы действительно хотите удалить этого пользователя? При этом также будут удалены все репозитории, принадлежащие этому пользователю.",
+ "delete_user": "Удалить пользователя",
+ "deleted": "Пользователь успешно удалён",
+ "desc": "Пользователи, зарегистрированные на этом сервере",
+ "edit_user": "Изменить пользователя",
+ "email": "Почта",
+ "login": "Вход в систему",
+ "none": "Пользователей пока нет.",
+ "save": "Сохранить пользователя",
+ "saved": "Пользователь сохранён",
+ "show": "Показать пользователей",
+ "users": "Пользователи"
+ },
+ "registries": {
+ "desc": "Можно добавить глобальные учётные данные реестра, чтобы иметь возможность использовать частные образы во всех конвейерах.",
+ "warning": "Эти учётные данные реестра будут доступны всем пользователям."
+ }
+ }
},
- "enable": {
- "disabled": "Отключено",
- "enable": "Подключить",
- "enabled": "Уже подключен",
- "list_reloaded": "Обновить список репозиториев",
- "reload": "Обновить репозитории",
- "success": "Репозиторий подключен"
+ "api": "API",
+ "back": "Назад",
+ "cancel": "Отменить",
+ "default": "по умолчанию",
+ "docs": "Документация",
+ "documentation_for": "Документация о «{topic}»",
+ "errors": {
+ "not_found": "Серверу не удалось найти запрошенный объект"
},
- "manual_pipeline": {
- "select_branch": "Выберите ветвь",
- "title": "Запустить конвейер вручную",
- "trigger": "Запустить конвейер",
- "variables": {
- "add": "Добавить переменную",
- "desc": "Укажите дополнительные переменные для использования в конвейере. Переменные с одинаковыми именами будут перезаписаны.",
- "name": "Имя переменой",
- "title": "Дополнительные переменные для конвейера",
- "value": "Значение переменой"
- }
+ "global_level_secret": "глобальный секрет",
+ "info": "Информация",
+ "login": "Вход",
+ "logout": "Выйти",
+ "not_found": {
+ "back_home": "Вернуться на главную",
+ "not_found": "Ошибка 404. Проверьте, что ввели адрес правильно :-/"
},
- "not_allowed": "У вас нет прав для доступа к этому репозиторию",
- "open_in_forge": "Открыть репозиторий в системе контроля версий",
- "pipeline": {
- "actions": {
- "cancel": "Отменить",
- "cancel_success": "Конвейер отменён",
- "canceled": "Этот шаг был пропущен.",
- "deploy": "Развертывание",
- "log_auto_scroll": "Автоматически пролистывать вниз",
- "log_auto_scroll_off": "Отключить автоматические пролистывание",
- "log_download": "Скачать",
- "restart": "Перезапустить",
- "restart_success": "Конвейер перезапущен"
- },
- "config": "Конфигурация",
- "errors": "Ошибки ({count})",
- "event": {
- "cron": "Задание Cron",
- "deploy": "Развёртывание (деплой)",
- "manual": "Ручной запуск",
- "pr": "Запросы на слияние",
- "push": "Новый коммит",
- "tag": "Тег"
- },
- "exit_code": "Код завершения {exitCode}",
- "files": "Изменённые файлы ({files})",
- "loading": "Загрузка…",
- "log_download_error": "Произошла ошибка при скачивании файла журнала",
- "log_title": "Журнал шагов",
- "no_files": "Никакие файлы не были изменены.",
- "no_pipeline_steps": "Нет доступных шагов конвеера!",
- "no_pipelines": "Ни один конвеер ещё не запущен.",
- "pipeline": "Конвейер №{pipelineId}",
- "pipelines_for": "Конвееры для ветви \"{branch}\"",
- "pipelines_for_pr": "Конвейер для запроса на слияние №{index}",
- "protected": {
- "approve": "Подтвердить",
- "approve_success": "Конвейер подтверждён",
- "awaits": "Конвейер ожидает подтверждения от разработчика!",
- "decline": "Отклонить",
- "decline_success": "Конвейер отклонён",
- "declined": "Этот конвейер был отклонён!",
- "review": "Обзор изменений"
- },
- "show_errors": "Показать ошибки",
- "status": {
- "blocked": "заблокирован",
- "declined": "отклонён",
- "error": "ошибка",
- "failure": "провален",
- "killed": "принудительно завершён",
- "pending": "ожидает",
- "running": "выполняется",
- "skipped": "пропущен",
- "started": "запускается",
- "status": "Состояние: {status}",
- "success": "успешно выполнен"
- },
- "step_not_started": "Этот шаг ещё не запущен.",
- "tasks": "Задачи",
- "warnings": "Предупреждения ({count})",
- "we_got_some_errors": "О нет, у нас возникли ошибки!"
+ "org": {
+ "settings": {
+ "not_allowed": "У вас нет прав для доступа к настройкам этой организации",
+ "secrets": {
+ "add": "Создать секрет",
+ "created": "Секрет организации успешно добавлен",
+ "deleted": "Секрет организации был удалён",
+ "desc": "Секреты этой организации могут быть переданы в виде переменных окружения всем шагам любого конвейера, принадлежащего этой организации.",
+ "events": {
+ "events": "Доступен для следующих событий",
+ "pr_warning": "Пожалуйста, будьте осторожны с этой опцией, так как злоумышленник может отправить вредоносный запрос на слияние, который раскроет ваши секреты."
+ },
+ "images": {
+ "desc": "Список образов, для которых доступен этот секрет. Оставьте поле пустым, чтобы разрешить все образы",
+ "images": "Доступен только для этих образов"
+ },
+ "name": "Название",
+ "none": "Тут пока нет секретов организации.",
+ "plugins_only": "Доступен только для расширений",
+ "save": "Сохранить секрет",
+ "saved": "Секрет организации успешно обновлён",
+ "secrets": "Секреты",
+ "show": "Показать секрет",
+ "value": "Значение"
+ },
+ "settings": "Настройки",
+ "registries": {
+ "desc": "Можно добавить учётные данные реестра для организации, чтобы иметь возможность использовать частные образы во всех конвейерах этой организации."
+ }
+ }
},
- "pull_requests": "Запросы на слияние",
- "settings": {
- "actions": {
- "actions": "Действия",
- "delete": {
- "confirm": "Все данные будут потеряны после этого действия!!!\n\nВы действительно хотите продолжить?",
- "delete": "Удалить репозиторий",
- "success": "Репозиторий удалён"
- },
- "disable": {
- "disable": "Отключить репозиторий",
- "success": "Репозиторий отключен"
+ "org_level_secret": "секрет организации",
+ "password": "Пароль",
+ "pipeline_feed": "Состояние конвейеров",
+ "repo": {
+ "activity": "Активность",
+ "add": "Подключить репозиторий",
+ "branches": "Ветви",
+ "deploy_pipeline": {
+ "enter_target": "Целевая среда развёртывания",
+ "title": "Вызвать событие развёртывания для текущего конвейера #{pipelineId}",
+ "trigger": "Развернуть",
+ "variables": {
+ "add": "Добавить переменную",
+ "desc": "Укажите дополнительные переменные для использования в конвейере. Переменные с одинаковыми именами будут перезаписаны.",
+ "name": "Имя переменной",
+ "title": "Дополнительные переменные для конвейера",
+ "value": "Значение переменной",
+ "delete": "Удалить переменную"
+ },
+ "enter_task": "Задача на развёртывание"
},
"enable": {
- "enable": "Включить репозиторий",
- "success": "Репозиторий включён"
+ "disabled": "Отключено",
+ "enable": "Подключить",
+ "enabled": "Уже подключен",
+ "list_reloaded": "Обновить список репозиториев",
+ "reload": "Обновить репозитории",
+ "success": "Репозиторий подключен"
},
- "repair": {
- "repair": "Восстановить репозиторий",
- "success": "Репозиторий восстановлен"
- }
- },
- "badge": {
- "badge": "Бейдж",
- "branch": "Ветвь",
- "type": "Синтаксис",
- "type_html": "HTML",
- "type_markdown": "Markdown",
- "type_url": "URL"
- },
- "crons": {
- "add": "Добавить задание Cron",
- "branch": {
- "placeholder": "Ветвь (если пусто, используется ветвь по умолчанию)",
- "title": "Ветвь"
+ "manual_pipeline": {
+ "select_branch": "Выберите ветвь",
+ "title": "Запустить конвейер вручную",
+ "trigger": "Запустить конвейер",
+ "variables": {
+ "add": "Добавить переменную",
+ "desc": "Укажите дополнительные переменные для использования в конвейере. Переменные с одинаковыми именами будут перезаписаны.",
+ "name": "Имя переменной",
+ "title": "Дополнительные переменные для конвейера",
+ "value": "Значение переменной",
+ "delete": "Удалить переменную"
+ },
+ "show_pipelines": "Показать конвейеры"
},
- "created": "Задача cron создана",
- "crons": "Задания Cron",
- "delete": "Удалить задачу cron",
- "deleted": "Задача cron удалена",
- "desc": "Задания Cron можно использовать для регулярного запуска конвейеров.",
- "edit": "Редактировать задачу cron",
- "name": {
- "name": "Название",
- "placeholder": "Имя задачи cron"
+ "not_allowed": "У вас нет прав для доступа к этому репозиторию",
+ "open_in_forge": "Открыть репозиторий в платформе разработки",
+ "pipeline": {
+ "actions": {
+ "cancel": "Отменить",
+ "cancel_success": "Конвейер отменён",
+ "canceled": "Этот шаг был отменён.",
+ "deploy": "Развёртывание",
+ "log_auto_scroll": "Автоматически пролистывать вниз",
+ "log_auto_scroll_off": "Отключить автоматические пролистывание",
+ "log_download": "Скачать",
+ "restart": "Перезапустить",
+ "restart_success": "Конвейер перезапущен",
+ "log_delete": "Удалить"
+ },
+ "config": "Конфигурация",
+ "errors": "Ошибки ({count})",
+ "event": {
+ "cron": "Задание cron",
+ "deploy": "Развёртывание (деплой)",
+ "manual": "Ручной запуск",
+ "pr": "Запросы на слияние",
+ "push": "Новый коммит",
+ "tag": "Тег",
+ "pr_closed": "Запрос на слияние удовлетворён / закрыт",
+ "release": "Релиз"
+ },
+ "exit_code": "Код завершения {exitCode}",
+ "files": "Изменённые файлы ({files})",
+ "loading": "Загрузка…",
+ "log_download_error": "Произошла ошибка при скачивании файла журнала",
+ "log_title": "Журнал шага",
+ "no_files": "Никакие файлы не были изменены.",
+ "no_pipeline_steps": "Нет доступных шагов конвеера!",
+ "no_pipelines": "Ни один конвеер ещё не запущен.",
+ "pipeline": "Конвейер №{pipelineId}",
+ "pipelines_for": "Конвееры для ветви «{branch}»",
+ "pipelines_for_pr": "Конвейер для запроса на слияние №{index}",
+ "protected": {
+ "approve": "Подтвердить",
+ "approve_success": "Конвейер подтверждён",
+ "awaits": "Конвейер ожидает подтверждения от разработчика!",
+ "decline": "Отклонить",
+ "decline_success": "Конвейер отклонён",
+ "declined": "Этот конвейер был отклонён!",
+ "review": "Обзор изменений"
+ },
+ "show_errors": "Показать ошибки",
+ "status": {
+ "blocked": "заблокирован",
+ "declined": "отклонён",
+ "error": "ошибка",
+ "failure": "провален",
+ "killed": "принудительно завершён",
+ "pending": "ожидает",
+ "running": "выполняется",
+ "skipped": "пропущен",
+ "started": "запущен",
+ "status": "Состояние: {status}",
+ "success": "успешно выполнен"
+ },
+ "step_not_started": "Этот шаг ещё не запущен.",
+ "tasks": "Задачи",
+ "warnings": "Предупреждения ({count})",
+ "we_got_some_errors": "О нет, у нас возникли ошибки!",
+ "no_logs": "Нет записей журнала",
+ "created": "Создано: {created}",
+ "duration": "Время работы конвейера",
+ "log_delete_confirm": "Вы действительно хотите удалить журналы этого шага?",
+ "log_delete_error": "При удалении журналов шага произошла ошибка"
},
- "next_exec": "Следующий запуск",
- "none": "Пока нет ни одной задачи cron.",
- "not_executed_yet": "Ещё не запущено",
- "run": "Запустить сейчас",
- "save": "Сохранить задачу cron",
- "saved": "Задача cron сохранена",
- "schedule": {
- "placeholder": "Расписание",
- "title": "Расписание (по UTC)"
+ "pull_requests": "Запросы на слияние",
+ "settings": {
+ "actions": {
+ "actions": "Действия",
+ "delete": {
+ "confirm": "Все данные будут потеряны после этого действия!!!\n\nВы действительно хотите продолжить?",
+ "delete": "Удалить репозиторий",
+ "success": "Репозиторий удалён"
+ },
+ "disable": {
+ "disable": "Отключить репозиторий",
+ "success": "Репозиторий отключен"
+ },
+ "enable": {
+ "enable": "Включить репозиторий",
+ "success": "Репозиторий включён"
+ },
+ "repair": {
+ "repair": "Восстановить репозиторий",
+ "success": "Репозиторий восстановлен"
+ }
+ },
+ "badge": {
+ "badge": "Бейдж",
+ "branch": "Ветвь",
+ "type": "Синтаксис",
+ "type_html": "HTML",
+ "type_markdown": "Markdown",
+ "type_url": "URL"
+ },
+ "crons": {
+ "add": "Добавить задачу cron",
+ "branch": {
+ "placeholder": "Ветвь (если пусто, используется ветвь по умолчанию)",
+ "title": "Ветвь"
+ },
+ "created": "Задача cron создана",
+ "crons": "Задачи cron",
+ "delete": "Удалить задачу cron",
+ "deleted": "Задача cron удалена",
+ "desc": "Задачи cron можно использовать для регулярного запуска конвейеров.",
+ "edit": "Редактировать задачу cron",
+ "name": {
+ "name": "Название",
+ "placeholder": "Имя задачи cron"
+ },
+ "next_exec": "Следующий запуск",
+ "none": "Пока нет ни одной задачи cron.",
+ "not_executed_yet": "Ещё не запущено",
+ "run": "Запустить сейчас",
+ "save": "Сохранить задачу cron",
+ "saved": "Задача cron сохранена",
+ "schedule": {
+ "placeholder": "Расписание",
+ "title": "Расписание (по UTC)"
+ },
+ "show": "Показать задачи cron"
+ },
+ "general": {
+ "allow_pr": {
+ "allow": "Разрешить запросы на слияние",
+ "desc": "Конвейеры смогут запускаться для запросов на слияние."
+ },
+ "cancel_prev": {
+ "cancel": "Принудительно завершить все предыдущие конвейеры",
+ "desc": "Позволяет отменить уже отложенные и запущенные конвейеры того же события и контекста перед запуском нового конвейера."
+ },
+ "general": "Главное",
+ "netrc_only_trusted": {
+ "desc": "Вводите учетные данные netrc только внутри контейнеров, которым вы доверяете (рекомендуется).",
+ "netrc_only_trusted": "Вводите учетные данные netrc только внутри контейнеров, которым вы доверяете"
+ },
+ "pipeline_path": {
+ "default": "По умолчанию: .woodpecker/*.{'{yaml,yml}'} -> .woodpecker.yaml -> .woodpecker.yml",
+ "desc": "Путь к конфигурации вашего конвейера (например: {0}). При указании директории путь должен заканчиваться символом {1}.",
+ "desc_path_example": "мой/путь/",
+ "path": "Конфигурация конвейера"
+ },
+ "project": "Настройки проекта",
+ "protected": {
+ "desc": "Каждый конвейер должен быть проверен до начала выполнения.",
+ "protected": "Защищён"
+ },
+ "save": "Сохранить настройки",
+ "success": "Настройки репозитория обновлены",
+ "timeout": {
+ "minutes": "минуты",
+ "timeout": "Время ожидания"
+ },
+ "trusted": {
+ "desc": "Доверенные конвейеры получат доступ к дополнительным возможностям (например, монтированию томов).",
+ "trusted": "Доверенный"
+ },
+ "visibility": {
+ "internal": {
+ "desc": "Только пользователи, вошедшие в систему, смогут видеть этот проект.",
+ "internal": "Внутренний"
+ },
+ "private": {
+ "desc": "Только вы и другие владельцы этого репозитория смогут видеть его.",
+ "private": "Приватный"
+ },
+ "public": {
+ "desc": "Любой незарегистрированный пользователь сможет увидеть этот проект.",
+ "public": "Публичный"
+ },
+ "visibility": "Видимость проекта"
+ },
+ "allow_deploy": {
+ "allow": "Разрешить развёртывание",
+ "desc": "Разрешить развёртывание из успешных конвейеров. Используйте только в том случае, если вы доверяете всем пользователям с push-доступом."
+ }
+ },
+ "not_allowed": "У вас нет права доступа к настройкам этого репозитория",
+ "registries": {
+ "add": "Добавить реестр",
+ "address": {
+ "address": "Адрес",
+ "placeholder": "Адрес реестра (например: docker.io)"
+ },
+ "created": "Данные для доступа к реестру добавлены",
+ "credentials": "Учётные данные для авторизации в реестре",
+ "delete": "Удалить реестр",
+ "deleted": "Данные для доступа к реестру удалены",
+ "desc": "Можно добавить учетные данные для доступа к реестру, чтобы использовать приветные образы из этого реестра в конвейере.",
+ "edit": "Изменить реестр",
+ "none": "Пока тут нет учётных данных для доступа к реестрам.",
+ "registries": "Реестры с образами",
+ "save": "Сохранить реестр",
+ "saved": "Данные для доступа к реестру сохранены",
+ "show": "Показать реестры"
+ },
+ "secrets": {
+ "add": "Создать секрет",
+ "created": "Секрет создан",
+ "delete": "Удалить секрет",
+ "delete_confirm": "Вы действительно хотите удалить этот секрет?",
+ "deleted": "Секрет успешно удалён",
+ "desc": "Секреты могут быть переданы отдельным этапам конвейера во время выполнения в качестве переменных окружения.",
+ "edit": "Изменить секрет",
+ "events": {
+ "events": "Доступен для следующих событий",
+ "pr_warning": "Пожалуйста, будьте осторожны с этой опцией, так как злоумышленник может отправить вредоносный запрос на слияние, который раскроет ваши секреты."
+ },
+ "images": {
+ "desc": "Список образов, для которых доступен этот секрет. Оставьте поле пустым, чтобы разрешить все образы",
+ "images": "Доступен только для этих образов"
+ },
+ "name": "Название",
+ "none": "Пока тут нет секретов.",
+ "plugins_only": "Доступен только для расширений",
+ "save": "Сохранить секрет",
+ "saved": "Секрет успешно сохранён",
+ "secrets": "Секреты",
+ "show": "Показать секрет",
+ "value": "Значение"
+ },
+ "settings": "Настройки"
},
- "show": "Показать задания Cron"
- },
- "general": {
- "allow_pr": {
- "allow": "Разрешить запросы на слияние",
- "desc": "Конвейеры смогут запускаться для запросов на слияние."
- },
- "cancel_prev": {
- "cancel": "Принудительно завершить все предыдущие конвейеры",
- "desc": "Позволяет отменить уже отложенные и запущенные конвейеры того же события и контекста перед запуском нового конвейера."
- },
- "general": "Главное",
- "netrc_only_trusted": {
- "desc": "Вводите учетные данные netrc только внутри контейнеров которым вы доверяете (рекомендуется).",
- "netrc_only_trusted": "Вводите учетные данные netrc только внутри контейнеров которым вы доверяете"
- },
- "pipeline_path": {
- "default": "По умолчанию: .woodpecker/*.{'{yaml,yml}'} -> .woodpecker.yaml -> .woodpecker.yml",
- "desc": "Путь к конфигурации вашего конвейера (например: {0}). При указании директории путь должен заканчиваться символом {1}.",
- "desc_path_example": "мой/путь/",
- "path": "Конфигурация конвейера"
- },
- "project": "Настройки проекта",
- "protected": {
- "desc": "Каждый конвейер должен быть проверен до того как он будет выполнен.",
- "protected": "Защищён"
- },
- "save": "Сохранить настройки",
- "success": "Настройки репозитория обновлены",
- "timeout": {
- "minutes": "минуты",
- "timeout": "Время ожидания"
- },
- "trusted": {
- "desc": "Доверенные конвейеры получат доступ к дополнительным возможностям. Например конвейер сможет выполнять монтирование томов.",
- "trusted": "Доверенный"
- },
- "visibility": {
- "internal": {
- "desc": "Только пользователи, вошедшие в систему, смогут видеть этот проект.",
- "internal": "Внутренний"
- },
- "private": {
- "desc": "Только вы и другие владельцы этого репозитория смогут видеть его.",
- "private": "Приватный"
- },
- "public": {
- "desc": "Любой незарегистрированный пользователь сможет увидеть этот проект.",
- "public": "Публичный"
- },
- "visibility": "Видимость проекта"
- }
- },
- "not_allowed": "У вас нет права доступа к настройкам этого репозитория",
- "registries": {
- "add": "Добавить реестр",
- "address": {
- "address": "Адрес",
- "placeholder": "Адрес реестра (например: docker.io)"
- },
- "created": "Данные для доступа к реестру добавлены",
- "credentials": "Учётные данные для авторизации в реестре",
- "delete": "Удалить реестр",
- "deleted": "Данные для доступа к реестру удалены",
- "desc": "Можно добавить учетные данные для доступа к реестру, чтобы использовать приветные образы из этого реестра в конвейере.",
- "edit": "Изменить реестр",
- "none": "Пока тут нет учётных данных для доступа к реестрам.",
- "registries": "Реестры с образами",
- "save": "Сохранить реестр",
- "saved": "Данные для доступа к реестру сохранены",
- "show": "Показать реестры"
- },
- "secrets": {
- "add": "Создать секрет",
- "created": "Секрет создан",
- "delete": "Удалить секрет",
- "delete_confirm": "Вы действительно хотите удалить этот секрет?",
- "deleted": "Секрет успешно удалён",
- "desc": "Секреты могут быть переданы отдельным этапам конвейера во время выполнения в качестве переменных окружения.",
- "edit": "Изменить секрет",
- "events": {
- "events": "Доступен для следующих событий",
- "pr_warning": "Пожалуйста, будьте осторожны с этой опцией, так как злоумышленник может отправить вредоносный запрос на слияние, который раскроет ваши секреты."
- },
- "images": {
- "desc": "Список образов, для которых доступен этот секрет. Оставьте поле пустым, чтобы разрешить все образы",
- "images": "Доступен только для этих образов"
- },
- "name": "Название",
- "none": "Пока тут нет секретов.",
- "plugins_only": "Доступен только для расширений",
- "save": "Сохранить секрет",
- "saved": "Секрет успешно сохранён",
- "secrets": "Секреты",
- "show": "Показать секрет",
- "value": "Значение"
- },
- "settings": "Настройки"
+ "user_none": "Эта организация / пользователь не имеет ни одного проекта."
},
- "user_none": "Эта организация / пользователь не имеет ни одного проекта."
- },
- "repos": "Репозитории",
- "repositories": "Репозитории",
- "running_version": "Вы управляете Woodpecker {0}",
- "search": "Поиск…",
- "time": {
- "days_short": "д.",
- "hours_short": "ч.",
- "min_short": "мин.",
- "not_started": "не запускался ни разу",
- "sec_short": "сек.",
- "template": "D MMM, YYYY, HH:mm z",
- "weeks_short": "нед."
- },
- "unknown_error": "Произошла неизвестная ошибка",
- "update_woodpecker": "Пожалуйста, обновите свой экземпляр Woodpecker до {0}",
- "url": "URL",
- "user": {
- "access_denied": "У вас нет прав для входа в систему",
- "internal_error": "Произошла внутренняя ошибка",
- "oauth_error": "Ошибка при аутентификации через OAuth провайдера",
- "settings": {
- "api": {
- "api": "API",
- "api_usage": "Пример использования API",
- "cli_usage": "Пример использования CLI",
- "desc": "Токен персонального доступа и использование API",
- "dl_cli": "Загрузить CLI",
- "reset_token": "Сбросить токен",
- "shell_setup": "Настройка оболочки",
- "shell_setup_before": "выполните шаги по настройке оболочки перед",
- "swagger_ui": "Интерфейс Swagger",
- "token": "Токен персонального доступа"
- },
- "general": {
- "general": "Главное",
- "language": "Язык",
- "theme": {
- "auto": "Авто",
- "dark": "Темная",
- "light": "Светлая",
- "theme": "Тема"
+ "repos": "Репозитории",
+ "repositories": "Репозитории",
+ "running_version": "Вы используете Woodpecker {0}",
+ "search": "Поиск…",
+ "time": {
+ "days_short": "д.",
+ "hours_short": "ч.",
+ "min_short": "мин.",
+ "not_started": "ещё не запускался",
+ "sec_short": "сек.",
+ "template": "D MMM, YYYY, HH:mm z",
+ "weeks_short": "нед."
+ },
+ "unknown_error": "Произошла неизвестная ошибка",
+ "update_woodpecker": "Пожалуйста, обновите свой экземпляр Woodpecker до {0}",
+ "url": "URL",
+ "user": {
+ "access_denied": "У вас нет прав для входа в систему",
+ "internal_error": "Произошла внутренняя ошибка",
+ "oauth_error": "Ошибка при аутентификации через OAuth провайдера",
+ "settings": {
+ "api": {
+ "api": "API",
+ "api_usage": "Пример использования API",
+ "cli_usage": "Пример использования CLI",
+ "desc": "Токен персонального доступа и использование API",
+ "dl_cli": "Загрузить CLI",
+ "reset_token": "Сбросить токен",
+ "shell_setup": "Настройка оболочки",
+ "shell_setup_before": "выполните шаги по настройке оболочки перед",
+ "swagger_ui": "Интерфейс Swagger",
+ "token": "Токен персонального доступа"
+ },
+ "general": {
+ "general": "Главное",
+ "language": "Язык",
+ "theme": {
+ "auto": "Авто",
+ "dark": "Тёмная",
+ "light": "Светлая",
+ "theme": "Тема"
+ }
+ },
+ "secrets": {
+ "add": "Добавить секрет",
+ "created": "Секрет пользователя создан",
+ "deleted": "Секрет пользователя удален",
+ "desc": "Пользовательские секреты могут быть переданы в виде переменных окружения всем этапам конвейеров во всех репозиториях пользователя.",
+ "events": {
+ "events": "Доступно на следующих событий",
+ "pr_warning": "Пожалуйста, будьте осторожны с этой опцией, так как злоумышленник может отправить вредоносный запрос на слияние, который раскроет ваши секреты."
+ },
+ "images": {
+ "desc": "Список образов, для которых доступен этот секрет. Оставьте поле пустым, чтобы разрешить все образы",
+ "images": "Доступно для следующих образов"
+ },
+ "name": "Имя",
+ "none": "Секретов пользователей пока нет.",
+ "plugins_only": "Доступно только для плагинов",
+ "save": "Сохранить секрет",
+ "saved": "Секрет пользователя сохранен",
+ "secrets": "Секреты",
+ "show": "Показать секреты",
+ "value": "Значение"
+ },
+ "settings": "Настройки пользователя",
+ "cli_and_api": {
+ "token": "Персональный токен доступа",
+ "cli_and_api": "Командная строка и API",
+ "desc": "Персональный токен доступа, командная строка и API",
+ "download_cli": "Скачать интерфейс командной строки",
+ "cli_usage": "Пример использования командной строки",
+ "api_usage": "Пример использования API",
+ "reset_token": "Сбросить токен",
+ "swagger_ui": "Интерфейс Swagger"
+ },
+ "registries": {
+ "desc": "Добавление учётных данных реестра для пользователя даст возможность использовать частные образы во всех конвейерах пользователя."
+ }
}
- },
- "secrets": {
- "add": "Добавить секрет",
- "created": "Секрет пользователя создан",
- "deleted": "Секрет пользователя удален",
- "desc": "Пользовательские секреты могут быть переданы всем отдельным этапам конвейера пользовательского репозитория во время выполнения в качестве переменных окружения.",
- "events": {
- "events": "Доступно на следующих событий",
- "pr_warning": "Пожалуйста, будьте осторожны с этой опцией, так как злоумышленник может отправить вредоносный запрос на слияние, который раскроет ваши секреты."
- },
- "images": {
- "desc": "Список образов, для которых доступен этот секрет. Оставьте поле пустым, чтобы разрешить все образы",
- "images": "Доступно для следующих образов"
- },
- "name": "Имя",
- "none": "Секретов пользователей пока нет.",
- "plugins_only": "Доступно только для плагинов",
+ },
+ "username": "Имя пользователя",
+ "welcome": "Добро пожаловать в Woodpecker",
+ "secrets": {
+ "desc": "Секреты можно передавать отдельным шагам конвейера в качестве переменных окружения.",
"save": "Сохранить секрет",
- "saved": "Секрет пользователя сохранен",
- "secrets": "Секреты",
"show": "Показать секреты",
- "value": "Значение"
- },
- "settings": "Настройки пользователя"
- }
- },
- "username": "Имя пользователя",
- "welcome": "Добро пожаловать в Woodpecker"
+ "name": "Имя",
+ "value": "Значение",
+ "delete_confirm": "Вы действительно хотите удалить этот секрет?",
+ "deleted": "Секрет удалён",
+ "created": "Секрет создан",
+ "saved": "Секрет сохранён",
+ "add": "Добавить секрет",
+ "images": {
+ "images": "Доступно следующим образам",
+ "desc": "Список образов, которым доступен этот секрет; оставьте пустым, чтобы разрешить доступ всем образам."
+ },
+ "secrets": "Секреты",
+ "none": "Секретов пока нет.",
+ "events": {
+ "events": "Доступно следующим событиям",
+ "pr_warning": "Пожалуйста, будьте осторожны с этой опцией: злоумышленник может раскрыть ваши секреты, отправив вредоносный запрос на слияние."
+ },
+ "edit": "Редактировать секрет",
+ "delete": "Удалить секрет",
+ "plugins": {
+ "images": "Доступно только следующим плагинам",
+ "desc": "Список образов плагинов, которым доступен этот секрет. Оставьте значение пустым, чтобы разрешить доступ для всех плагинов и для обычных шагов конвейера."
+ }
+ },
+ "internal_error": "Произошла внутренняя ошибка",
+ "registration_closed": "Регистрация закрыта",
+ "registries": {
+ "address": {
+ "desc": "Адрес реестра (например, docker.io)",
+ "address": "Адрес"
+ },
+ "show": "Показать реестры",
+ "save": "Сохранить реестр",
+ "add": "Добавить реестр",
+ "view": "Просмотр реестра",
+ "none": "Учётных данных реестра пока нет.",
+ "registries": "Реестры",
+ "credentials": "Учётные данные реестра",
+ "desc": "Можно добавить учётные данные реестра, чтобы использовать частные образы в конвейерах.",
+ "edit": "Редактировать реестр",
+ "delete": "Удалить реестр",
+ "delete_confirm": "Вы действительно хотите удалить этот реестр?",
+ "created": "Учётные данные реестра созданы",
+ "saved": "Учётные данные реестра сохранены",
+ "deleted": "Учётные данные реестра удалены"
+ },
+ "login_to_cli": "Вход через командную строку",
+ "abort": "Прервать",
+ "cli_login_success": "Успешный вход в интерфейс командной строки",
+ "cli_login_failed": "Вход в интерфейс командной строки не удался",
+ "return_to_cli": "Теперь вы можете закрыть эту вкладку и вернуться в командную строку.",
+ "settings": "Настройки",
+ "login_to_cli_description": "Продолжите, чтобы войти через командную строку.",
+ "cli_login_denied": "Вход через командную строку запрещён",
+ "invalid_state": "Некорректное состояние OAuth",
+ "oauth_error": "Ошибка при аутентификации в провайдере OAuth",
+ "access_denied": "Вам не разрешён доступ к этому экземпляру",
+ "empty_list": "{entity} не найдены!",
+ "login_with": "Вход через {forge}"
}
diff --git a/web/src/components/admin/settings/AdminRegistriesTab.vue b/web/src/components/admin/settings/AdminRegistriesTab.vue
new file mode 100644
index 000000000..8c7ae8d31
--- /dev/null
+++ b/web/src/components/admin/settings/AdminRegistriesTab.vue
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/web/src/components/admin/settings/AdminReposTab.vue b/web/src/components/admin/settings/AdminReposTab.vue
index f2d22ebb7..570002606 100644
--- a/web/src/components/admin/settings/AdminReposTab.vue
+++ b/web/src/components/admin/settings/AdminReposTab.vue
@@ -42,6 +42,7 @@
import { useI18n } from 'vue-i18n';
import Badge from '~/components/atomic/Badge.vue';
+import Button from '~/components/atomic/Button.vue';
import IconButton from '~/components/atomic/IconButton.vue';
import ListItem from '~/components/atomic/ListItem.vue';
import Settings from '~/components/layout/Settings.vue';
diff --git a/web/src/components/admin/settings/AdminUsersTab.vue b/web/src/components/admin/settings/AdminUsersTab.vue
index 83e439f11..a73eeb33c 100644
--- a/web/src/components/admin/settings/AdminUsersTab.vue
+++ b/web/src/components/admin/settings/AdminUsersTab.vue
@@ -90,6 +90,7 @@ import Badge from '~/components/atomic/Badge.vue';
import Button from '~/components/atomic/Button.vue';
import IconButton from '~/components/atomic/IconButton.vue';
import ListItem from '~/components/atomic/ListItem.vue';
+import Checkbox from '~/components/form/Checkbox.vue';
import InputField from '~/components/form/InputField.vue';
import TextField from '~/components/form/TextField.vue';
import Settings from '~/components/layout/Settings.vue';
diff --git a/web/src/components/atomic/Button.vue b/web/src/components/atomic/Button.vue
index 9245a324f..f026b88c2 100644
--- a/web/src/components/atomic/Button.vue
+++ b/web/src/components/atomic/Button.vue
@@ -28,7 +28,7 @@
'bg-wp-control-error-200': color === 'red',
}"
>
-
+
diff --git a/web/src/components/atomic/Error.vue b/web/src/components/atomic/Error.vue
index 75a1b67f1..30b5ad5b1 100644
--- a/web/src/components/atomic/Error.vue
+++ b/web/src/components/atomic/Error.vue
@@ -10,6 +10,8 @@
diff --git a/web/src/components/atomic/Warning.vue b/web/src/components/atomic/Warning.vue
index f30885fac..71171a23b 100644
--- a/web/src/components/atomic/Warning.vue
+++ b/web/src/components/atomic/Warning.vue
@@ -10,6 +10,8 @@
diff --git a/web/src/components/layout/popups/DeployPipelinePopup.vue b/web/src/components/layout/popups/DeployPipelinePopup.vue
index 9a4eefea7..c1b25b4ff 100644
--- a/web/src/components/layout/popups/DeployPipelinePopup.vue
+++ b/web/src/components/layout/popups/DeployPipelinePopup.vue
@@ -33,7 +33,7 @@
:title="$t('repo.deploy_pipeline.variables.delete')"
@click="deleteVar(i)"
>
-
+
@@ -50,6 +50,7 @@ import { computed, onMounted, ref, toRef, watch } from 'vue';
import { useRouter } from 'vue-router';
import Button from '~/components/atomic/Button.vue';
+import Icon from '~/components/atomic/Icon.vue';
import InputField from '~/components/form/InputField.vue';
import TextField from '~/components/form/TextField.vue';
import Panel from '~/components/layout/Panel.vue';
diff --git a/web/src/components/layout/popups/ManualPipelinePopup.vue b/web/src/components/layout/popups/ManualPipelinePopup.vue
deleted file mode 100644
index 49909319f..000000000
--- a/web/src/components/layout/popups/ManualPipelinePopup.vue
+++ /dev/null
@@ -1,133 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/web/src/components/layout/scaffold/Header.vue b/web/src/components/layout/scaffold/Header.vue
index c31794c66..22a30eb13 100644
--- a/web/src/components/layout/scaffold/Header.vue
+++ b/web/src/components/layout/scaffold/Header.vue
@@ -52,6 +52,7 @@
diff --git a/web/src/components/pipeline-feed/PipelineFeedItem.vue b/web/src/components/pipeline-feed/PipelineFeedItem.vue
index eb5916b5a..936831dd0 100644
--- a/web/src/components/pipeline-feed/PipelineFeedItem.vue
+++ b/web/src/components/pipeline-feed/PipelineFeedItem.vue
@@ -12,7 +12,7 @@
{{ repo?.owner }} / {{ repo?.name }}
- {{ title }}
+ {{ shortMessage }}
@@ -45,5 +45,5 @@ const repoStore = useRepoStore();
const pipeline = toRef(props, 'pipeline');
const repo = repoStore.getRepo(computed(() => pipeline.value.repo_id));
-const { since, duration, message, title, created } = usePipeline(pipeline);
+const { since, duration, shortMessage, message, created } = usePipeline(pipeline);
diff --git a/web/src/components/registry/RegistryEdit.vue b/web/src/components/registry/RegistryEdit.vue
new file mode 100644
index 000000000..ace75126c
--- /dev/null
+++ b/web/src/components/registry/RegistryEdit.vue
@@ -0,0 +1,78 @@
+
+
+
+
+
diff --git a/web/src/components/registry/RegistryList.vue b/web/src/components/registry/RegistryList.vue
new file mode 100644
index 000000000..775a02eb4
--- /dev/null
+++ b/web/src/components/registry/RegistryList.vue
@@ -0,0 +1,63 @@
+
+
+
+ {{ registry.address }}
+
+
+
+
+
{{ $t('registries.none') }}
+
+
+
+
diff --git a/web/src/components/repo/pipeline/PipelineItem.vue b/web/src/components/repo/pipeline/PipelineItem.vue
index 40ee39fef..99c0054a0 100644
--- a/web/src/components/repo/pipeline/PipelineItem.vue
+++ b/web/src/components/repo/pipeline/PipelineItem.vue
@@ -32,21 +32,23 @@
class="text-wp-text-100
- {{ title }}
+ {{ shortMessage }}
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
{{ prettyRef }}
@@ -55,14 +57,14 @@
{{ pipeline.commit.slice(0, 10) }}
-
+
{{ duration }}
-
+
- {{ since }}
+ {{ since }}
@@ -70,7 +72,8 @@
diff --git a/web/src/components/repo/pipeline/PipelineLog.vue b/web/src/components/repo/pipeline/PipelineLog.vue
index 4636f2f48..5fa128cb6 100644
--- a/web/src/components/repo/pipeline/PipelineLog.vue
+++ b/web/src/components/repo/pipeline/PipelineLog.vue
@@ -13,7 +13,7 @@
@@ -88,18 +88,19 @@
-
{{ step.error }}
-
{{ $t('repo.pipeline.actions.canceled') }}
-
{{ $t('repo.pipeline.step_not_started') }}
+
{{ $t('repo.pipeline.actions.canceled') }}
+
{{ $t('repo.pipeline.step_not_started') }}
{{ $t('repo.pipeline.loading') }}
+
{{ $t('repo.pipeline.no_logs') }}
-
{{ $t('repo.pipeline.exit_code', { exitCode: step.exit_code }) }}
+
{{ step.error }}
+
{{ $t('repo.pipeline.exit_code', { exitCode: step.exit_code }) }}
@@ -160,7 +161,7 @@ const loadedLogs = computed(() => !!log.value);
const hasLogs = computed(
() =>
// we do not have logs for skipped steps
- repo?.value && pipeline.value && step.value && step.value.state !== 'skipped' && step.value.state !== 'killed',
+ repo?.value && pipeline.value && step.value && step.value.state !== 'skipped',
);
const autoScroll = useStorage('log-auto-scroll', false);
const showActions = ref(false);
@@ -180,11 +181,21 @@ function formatTime(time?: number): string {
return time === undefined ? '' : `${time}s`;
}
+function processText(text: string): string {
+ const urlRegex = /https?:\/\/\S+/g;
+ let txt = ansiUp.value.ansi_to_html(`${decode(text)}\n`);
+ txt = txt.replace(
+ urlRegex,
+ (url) => `${url}`,
+ );
+ return txt;
+}
+
function writeLog(line: Partial) {
logBuffer.value.push({
index: line.index ?? 0,
number: (line.index ?? 0) + 1,
- text: ansiUp.value.ansi_to_html(`${decode(line.text ?? '')}\n`),
+ text: processText(line.text ?? ''),
time: line.time ?? 0,
type: null, // TODO: implement way to detect errors and warnings
});
@@ -339,7 +350,7 @@ watch(stepSlug, async () => {
watch(step, async (newStep, oldStep) => {
if (oldStep?.name === newStep?.name) {
- if (oldStep?.end_time !== newStep?.end_time && autoScroll.value) {
+ if (oldStep?.finished !== newStep?.finished && autoScroll.value) {
scrollDown();
}
diff --git a/web/src/components/repo/pipeline/PipelineStepDuration.vue b/web/src/components/repo/pipeline/PipelineStepDuration.vue
index 8fd6e03d3..0b79a4bd1 100644
--- a/web/src/components/repo/pipeline/PipelineStepDuration.vue
+++ b/web/src/components/repo/pipeline/PipelineStepDuration.vue
@@ -19,8 +19,8 @@ const workflow = toRef(props, 'workflow');
const { durationAsNumber } = useDate();
const durationRaw = computed(() => {
- const start = (step.value ? step.value?.start_time : workflow.value?.start_time) || 0;
- const end = (step.value ? step.value?.end_time : workflow.value?.end_time) || 0;
+ const start = (step.value ? step.value?.started : workflow.value?.started) || 0;
+ const end = (step.value ? step.value?.finished : workflow.value?.finished) || 0;
if (end === 0 && start === 0) {
return undefined;
@@ -43,5 +43,5 @@ const duration = computed(() => {
return durationAsNumber(durationElapsed.value || 0);
});
-const started = computed(() => (step.value ? step.value?.start_time : workflow.value?.start_time) !== undefined);
+const started = computed(() => (step.value ? step.value?.started : workflow.value?.started) !== undefined);
diff --git a/web/src/components/repo/pipeline/PipelineStepList.vue b/web/src/components/repo/pipeline/PipelineStepList.vue
index 18e117a4c..50006de25 100644
--- a/web/src/components/repo/pipeline/PipelineStepList.vue
+++ b/web/src/components/repo/pipeline/PipelineStepList.vue
@@ -82,7 +82,7 @@
{{ workflow.name }}
diff --git a/web/src/components/repo/settings/CronTab.vue b/web/src/components/repo/settings/CronTab.vue
index 4e2e5ca8f..e19c9f0a0 100644
--- a/web/src/components/repo/settings/CronTab.vue
+++ b/web/src/components/repo/settings/CronTab.vue
@@ -16,12 +16,14 @@
:key="cron.id"
class="items-center !bg-wp-background-200 !dark:bg-wp-background-100"
>
- {{ cron.name }}
-
-
- {{ $t('repo.settings.crons.next_exec') }}: {{ date.toLocaleString(new Date(cron.next_exec * 1000)) }}
+
+ {{ cron.name }}
+
+
+ {{ $t('repo.settings.crons.next_exec') }}: {{ date.toLocaleString(new Date(cron.next_exec * 1000)) }}
+
+ {{ $t('repo.settings.crons.not_executed_yet') }}
- {{ $t('repo.settings.crons.not_executed_yet') }}
-
+
-
+
-
-
- {{ registry.address }}
-
-
-
+
-
{{ $t('repo.settings.registries.none') }}
-
-
-
+
diff --git a/web/src/components/repo/settings/SecretsTab.vue b/web/src/components/repo/settings/SecretsTab.vue
index a2c57a35b..d13189a4d 100644
--- a/web/src/components/repo/settings/SecretsTab.vue
+++ b/web/src/components/repo/settings/SecretsTab.vue
@@ -72,7 +72,6 @@ async function loadSecrets(page: number, level: 'repo' | 'org' | 'global'): Prom
const { resetPage, data: _secrets } = usePagination(loadSecrets, () => !selectedSecret.value, {
each: ['repo', 'org', 'global'],
- pageSize: 50,
});
const secrets = computed(() => {
const secretsList: Record = {};
diff --git a/web/src/components/secrets/SecretEdit.vue b/web/src/components/secrets/SecretEdit.vue
index 81aca0963..18d79b5d7 100644
--- a/web/src/components/secrets/SecretEdit.vue
+++ b/web/src/components/secrets/SecretEdit.vue
@@ -21,8 +21,8 @@
/>
-
- {{ $t('secrets.images.desc') }}
+
+ {{ $t('secrets.plugins.desc') }}
diff --git a/web/src/components/user/UserCLIAndAPITab.vue b/web/src/components/user/UserCLIAndAPITab.vue
index 5a2ed8fae..dea79cb2f 100644
--- a/web/src/components/user/UserCLIAndAPITab.vue
+++ b/web/src/components/user/UserCLIAndAPITab.vue
@@ -60,7 +60,7 @@ const usageWithCurl = computed(() => {
return usage;
});
-const usageWithCli = `# woodpecker setup --server-url ${address}`;
+const usageWithCli = `# woodpecker setup --server ${address}`;
const cliDownload = 'https://github.com/woodpecker-ci/woodpecker/releases';
diff --git a/web/src/components/user/UserGeneralTab.vue b/web/src/components/user/UserGeneralTab.vue
index 435f8c231..fea7cc833 100644
--- a/web/src/components/user/UserGeneralTab.vue
+++ b/web/src/components/user/UserGeneralTab.vue
@@ -23,6 +23,7 @@ import { SUPPORTED_LOCALES } from 'virtual:vue-i18n-supported-locales';
import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
+import InputField from '~/components/form/InputField.vue';
import SelectField from '~/components/form/SelectField.vue';
import Settings from '~/components/layout/Settings.vue';
import { setI18nLanguage } from '~/compositions/useI18n';
diff --git a/web/src/components/user/UserRegistriesTab.vue b/web/src/components/user/UserRegistriesTab.vue
new file mode 100644
index 000000000..012570e9a
--- /dev/null
+++ b/web/src/components/user/UserRegistriesTab.vue
@@ -0,0 +1,114 @@
+
+
+
+
+
{{ $t('registries.registries') }}
+
+ {{ $t('user.settings.registries.desc') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/web/src/compositions/useAsyncAction.ts b/web/src/compositions/useAsyncAction.ts
index 663c080bf..09098e9bd 100644
--- a/web/src/compositions/useAsyncAction.ts
+++ b/web/src/compositions/useAsyncAction.ts
@@ -1,10 +1,9 @@
import { computed, ref } from 'vue';
-import useNotifications from '~/compositions/useNotifications';
-
-const notifications = useNotifications();
-
-export function useAsyncAction
(action: (...a: T) => void | Promise) {
+export function useAsyncAction(
+ action: (...a: T) => void | Promise,
+ onerror: ((error: any) => void) | undefined = undefined,
+) {
const isLoading = ref(false);
async function doSubmit(...a: T) {
@@ -16,7 +15,10 @@ export function useAsyncAction(action: (...a: T) => void |
try {
await action(...a);
} catch (error) {
- notifications.notify({ title: (error as Error).message, type: 'error' });
+ console.error(error);
+ if (onerror) {
+ onerror(error);
+ }
}
isLoading.value = false;
}
diff --git a/web/src/compositions/useAuthentication.ts b/web/src/compositions/useAuthentication.ts
index d8bcb21fd..8ca3df563 100644
--- a/web/src/compositions/useAuthentication.ts
+++ b/web/src/compositions/useAuthentication.ts
@@ -7,11 +7,11 @@ export default () =>
user: useConfig().user,
- authenticate(url?: string) {
+ authenticate(url?: string, forgeId?: number) {
if (url !== undefined) {
const config = useUserConfig();
config.setUserConfig('redirectUrl', url);
}
- window.location.href = `${useConfig().rootPath}/authorize`;
+ window.location.href = `${useConfig().rootPath}/authorize?${forgeId !== undefined ? `forgeId=${forgeId}` : ''}`;
},
}) as const;
diff --git a/web/src/compositions/useDate.ts b/web/src/compositions/useDate.ts
index 50096b737..c467a244e 100644
--- a/web/src/compositions/useDate.ts
+++ b/web/src/compositions/useDate.ts
@@ -12,19 +12,24 @@ dayjs.extend(advancedFormat);
dayjs.extend(relativeTime);
dayjs.extend(duration);
+function toLocaleString(date: Date) {
+ return dayjs(date).format(useI18n().t('time.template'));
+}
+
+function timeAgo(date: Date | string | number) {
+ return dayjs().to(dayjs(date));
+}
+
+function prettyDuration(durationMs: number) {
+ return dayjs.duration(durationMs).humanize();
+}
+
+function durationAsNumber(durationMs: number): string {
+ const dur = dayjs.duration(durationMs);
+ return dur.format(dur.hours() > 1 ? 'HH:mm:ss' : 'mm:ss');
+}
+
export function useDate() {
- function toLocaleString(date: Date) {
- return dayjs(date).format(useI18n().t('time.template'));
- }
-
- function timeAgo(date: Date | string | number) {
- return dayjs().to(dayjs(date));
- }
-
- function prettyDuration(durationMs: number) {
- return dayjs.duration(durationMs).humanize();
- }
-
const addedLocales = ['en'];
async function setDayjsLocale(locale: string) {
@@ -36,11 +41,6 @@ export function useDate() {
}
}
- function durationAsNumber(durationMs: number): string {
- const dur = dayjs.duration(durationMs);
- return dur.format(dur.hours() > 1 ? 'HH:mm:ss' : 'mm:ss');
- }
-
return {
toLocaleString,
timeAgo,
diff --git a/web/src/compositions/useFavicon.ts b/web/src/compositions/useFavicon.ts
index ccfe80d35..dfd801175 100644
--- a/web/src/compositions/useFavicon.ts
+++ b/web/src/compositions/useFavicon.ts
@@ -31,15 +31,15 @@ watch(
);
function convertStatus(status: PipelineStatus): Status {
- if (['blocked', 'declined', 'error', 'failure', 'killed'].includes(status)) {
+ if (['declined', 'error', 'failure', 'killed'].includes(status)) {
return 'error';
}
- if (['started', 'running', 'pending'].includes(status)) {
+ if (['blocked', 'started', 'running', 'pending'].includes(status)) {
return 'pending';
}
- if (['success', 'declined', 'error', 'failure', 'killed'].includes(status)) {
+ if (status === 'success') {
return 'success';
}
diff --git a/web/src/compositions/usePaginate.test.ts b/web/src/compositions/usePaginate.test.ts
index 37d603925..a9e303e59 100644
--- a/web/src/compositions/usePaginate.test.ts
+++ b/web/src/compositions/usePaginate.test.ts
@@ -18,11 +18,11 @@ async function waitForState(ref: Ref, expected: T): Promise {
});
}
-// TODO enable again with eslint-plugin-promise eslint-disable-next-line promise/prefer-await-to-callbacks
+// eslint-disable-next-line promise/prefer-await-to-callbacks
export const mountComposition = (cb: () => void) => {
const wrapper = shallowMount({
setup() {
- // TODO enable again with eslint-plugin-promise eslint-disable-next-line promise/prefer-await-to-callbacks
+ // eslint-disable-next-line promise/prefer-await-to-callbacks
cb();
return {};
},
@@ -48,6 +48,7 @@ describe('usePaginate', () => {
usePaginationComposition = usePagination<{ name: string }>(
async (page) => repoSecrets[page - 1],
() => true,
+ { pageSize: 3 },
);
});
await waitForState(usePaginationComposition.loading, true);
@@ -63,6 +64,7 @@ describe('usePaginate', () => {
usePaginationComposition = usePagination<{ name: string }>(
async (page) => repoSecrets[page - 1],
() => true,
+ { pageSize: 3 },
);
});
await waitForState(usePaginationComposition.loading, true);
@@ -86,7 +88,7 @@ describe('usePaginate', () => {
return orgSecrets[page - 1];
},
() => true,
- { each: ['repo', 'org'] },
+ { each: ['repo', 'org'], pageSize: 3 },
);
});
await waitForState(usePaginationComposition.loading, true);
@@ -111,6 +113,7 @@ describe('usePaginate', () => {
usePaginationComposition = usePagination<{ name: string }>(
async (page) => repoSecrets[page - 1],
() => true,
+ { pageSize: 3 },
);
});
await waitForState(usePaginationComposition.loading, true);
@@ -132,6 +135,7 @@ describe('usePaginate', () => {
usePaginationComposition = usePagination<{ name: string }>(
async (page) => repoSecrets[page - 1],
() => true,
+ { pageSize: 3 },
);
});
await waitForState(usePaginationComposition.loading, true);
diff --git a/web/src/compositions/usePaginate.ts b/web/src/compositions/usePaginate.ts
index 9bcfdb44c..657f55cd1 100644
--- a/web/src/compositions/usePaginate.ts
+++ b/web/src/compositions/usePaginate.ts
@@ -1,19 +1,26 @@
import { useInfiniteScroll } from '@vueuse/core';
import { onMounted, ref, watch, type Ref, type UnwrapRef } from 'vue';
-export async function usePaginate(getSingle: (page: number) => Promise): Promise {
+const defaultPageSize = 50;
+
+// usePaginate loads all pages
+export async function usePaginate(
+ getSingle: (page: number) => Promise,
+ pageSize: number = defaultPageSize,
+): Promise {
let hasMore = true;
let page = 1;
const result: T[] = [];
while (hasMore) {
const singleRes = await getSingle(page);
result.push(...singleRes);
- hasMore = singleRes.length !== 0;
+ hasMore = singleRes.length >= pageSize;
page += 1;
}
return result;
}
+// usePagination loads pages on demand
export function usePagination(
_loadData: (page: number, arg: S) => Promise,
isActive: () => boolean = () => true,
@@ -25,7 +32,7 @@ export function usePagination(
) {
const scrollElement = _scrollElement === null ? null : ref(document.getElementById('scroll-component'));
const page = ref(1);
- const pageSize = ref(_pageSize ?? 0);
+ const pageSize = ref(_pageSize ?? defaultPageSize);
const hasMore = ref(true);
const data = ref([]) as Ref;
const loading = ref(false);
@@ -48,14 +55,12 @@ export function usePagination(
// use next each element
each.value.shift();
page.value = 1;
- pageSize.value = _pageSize ?? 0;
hasMore.value = each.value.length > 0;
if (hasMore.value) {
loading.value = false;
await loadData();
}
}
- pageSize.value = newData.length;
loading.value = false;
}
@@ -76,7 +81,6 @@ export function usePagination(
const _page = page.value;
page.value = 1;
- pageSize.value = _pageSize ?? 0;
hasMore.value = true;
data.value = [];
loading.value = false;
diff --git a/web/src/compositions/usePipeline.ts b/web/src/compositions/usePipeline.ts
index cd249d257..b4c8a6804 100644
--- a/web/src/compositions/usePipeline.ts
+++ b/web/src/compositions/usePipeline.ts
@@ -14,7 +14,7 @@ export default (pipeline: Ref) => {
return undefined;
}
- const start = pipeline.value.created_at || 0;
+ const start = pipeline.value.created || 0;
return start * 1000;
});
@@ -27,7 +27,8 @@ export default (pipeline: Ref) => {
const i18n = useI18n();
const since = computed(() => {
if (sinceRaw.value === 0) {
- return i18n.t('time.not_started');
+ // return i18n.t('time.not_started');
+ return '-';
}
if (sinceElapsed.value === undefined) {
@@ -43,8 +44,8 @@ export default (pipeline: Ref) => {
return undefined;
}
- const start = pipeline.value.started_at || 0;
- const end = pipeline.value.finished_at || pipeline.value.updated_at || 0;
+ const start = pipeline.value.started || 0;
+ const end = pipeline.value.finished || pipeline.value.updated || 0;
if (start === 0 || end === 0) {
return 0;
@@ -73,15 +74,11 @@ export default (pipeline: Ref) => {
return prettyDuration(durationElapsed.value);
});
- const message = computed(() => {
- if (!pipeline.value) {
- return '';
- }
+ const message = computed(() => convertEmojis(pipeline.value?.message ?? ''));
+ const shortMessage = computed(() => message.value.split('\n')[0]);
- return convertEmojis(pipeline.value.message);
- });
-
- const title = computed(() => message.value.split('\n')[0]);
+ const prTitleWithDescription = computed(() => convertEmojis(pipeline.value?.title ?? ''));
+ const prTitle = computed(() => prTitleWithDescription.value.split('\n')[0]);
const prettyRef = computed(() => {
if (pipeline.value?.event === 'push' || pipeline.value?.event === 'deployment') {
@@ -112,10 +109,10 @@ export default (pipeline: Ref) => {
return undefined;
}
- const start = pipeline.value.created_at || 0;
+ const start = pipeline.value.created || 0;
return toLocaleString(new Date(start * 1000));
});
- return { since, duration, message, title, prettyRef, created };
+ return { since, duration, message, shortMessage, prTitle, prTitleWithDescription, prettyRef, created };
};
diff --git a/web/src/compositions/usePipelineFeed.ts b/web/src/compositions/usePipelineFeed.ts
index 65d3609a7..def2166f1 100644
--- a/web/src/compositions/usePipelineFeed.ts
+++ b/web/src/compositions/usePipelineFeed.ts
@@ -7,20 +7,20 @@ import useAuthentication from './useAuthentication';
const userConfig = useUserConfig();
+function toggle() {
+ userConfig.setUserConfig('isPipelineFeedOpen', !userConfig.userConfig.value.isPipelineFeedOpen);
+}
+
+function close() {
+ userConfig.setUserConfig('isPipelineFeedOpen', false);
+}
+
export default () => {
const pipelineStore = usePipelineStore();
const { isAuthenticated } = useAuthentication();
const isOpen = computed(() => userConfig.userConfig.value.isPipelineFeedOpen && !!isAuthenticated);
- function toggle() {
- userConfig.setUserConfig('isPipelineFeedOpen', !userConfig.userConfig.value.isPipelineFeedOpen);
- }
-
- function close() {
- userConfig.setUserConfig('isPipelineFeedOpen', false);
- }
-
const sortedPipelines = toRef(pipelineStore, 'pipelineFeed');
const activePipelines = toRef(pipelineStore, 'activePipelines');
diff --git a/web/src/compositions/useTabs.ts b/web/src/compositions/useTabs.ts
index f7bd533ea..a9538979a 100644
--- a/web/src/compositions/useTabs.ts
+++ b/web/src/compositions/useTabs.ts
@@ -1,10 +1,12 @@
import { inject, onMounted, provide, ref, type Ref } from 'vue';
import { useRoute } from 'vue-router';
+import type { IconNames } from '~/components/atomic/Icon.vue';
+
export interface Tab {
id: string;
title: string;
- icon?: string;
+ icon?: IconNames;
iconClass?: string;
}
diff --git a/web/src/lib/api/client.ts b/web/src/lib/api/client.ts
index ca3d1dc89..7270cbfe0 100644
--- a/web/src/lib/api/client.ts
+++ b/web/src/lib/api/client.ts
@@ -52,14 +52,19 @@ export default class ApiClient {
});
if (!res.ok) {
+ let message = res.statusText;
+ const resText = await res.text();
+ if (resText) {
+ message = `${res.statusText}: ${resText}`;
+ }
const error: ApiError = {
status: res.status,
- message: res.statusText,
+ message,
};
if (this.onerror) {
this.onerror(error);
}
- throw new Error(res.statusText);
+ throw new Error(message);
}
const contentType = res.headers.get('Content-Type');
@@ -70,19 +75,19 @@ export default class ApiClient {
return res.text();
}
- _get(path: string) {
+ async _get(path: string) {
return this._request('GET', path);
}
- _post(path: string, data?: unknown) {
+ async _post(path: string, data?: unknown) {
return this._request('POST', path, data);
}
- _patch(path: string, data?: unknown) {
+ async _patch(path: string, data?: unknown) {
return this._request('PATCH', path, data);
}
- _delete(path: string) {
+ async _delete(path: string) {
return this._request('DELETE', path);
}
@@ -96,7 +101,7 @@ export default class ApiClient {
const events = new EventSource(_path);
events.onmessage = (event) => {
const data = JSON.parse(event.data as string) as T;
- // TODO enable again with eslint-plugin-promise eslint-disable-next-line promise/prefer-await-to-callbacks
+ // eslint-disable-next-line promise/prefer-await-to-callbacks
callback(data);
};
diff --git a/web/src/lib/api/index.ts b/web/src/lib/api/index.ts
index 532aa6661..e06c401a8 100644
--- a/web/src/lib/api/index.ts
+++ b/web/src/lib/api/index.ts
@@ -42,57 +42,57 @@ interface PaginationOptions {
}
export default class WoodpeckerClient extends ApiClient {
- getRepoList(opts?: RepoListOptions): Promise {
+ async getRepoList(opts?: RepoListOptions): Promise {
const query = encodeQueryString(opts);
return this._get(`/api/user/repos?${query}`) as Promise;
}
- lookupRepo(owner: string, name: string): Promise {
+ async lookupRepo(owner: string, name: string): Promise {
return this._get(`/api/repos/lookup/${owner}/${name}`) as Promise;
}
- getRepo(repoId: number): Promise {
+ async getRepo(repoId: number): Promise {
return this._get(`/api/repos/${repoId}`) as Promise;
}
- getRepoPermissions(repoId: number): Promise {
+ async getRepoPermissions(repoId: number): Promise {
return this._get(`/api/repos/${repoId}/permissions`) as Promise;
}
- getRepoBranches(repoId: number, opts?: PaginationOptions): Promise {
+ async getRepoBranches(repoId: number, opts?: PaginationOptions): Promise {
const query = encodeQueryString(opts);
return this._get(`/api/repos/${repoId}/branches?${query}`) as Promise;
}
- getRepoPullRequests(repoId: number, opts?: PaginationOptions): Promise {
+ async getRepoPullRequests(repoId: number, opts?: PaginationOptions): Promise {
const query = encodeQueryString(opts);
return this._get(`/api/repos/${repoId}/pull_requests?${query}`) as Promise;
}
- activateRepo(forgeRemoteId: string): Promise {
+ async activateRepo(forgeRemoteId: string): Promise {
return this._post(`/api/repos?forge_remote_id=${forgeRemoteId}`) as Promise;
}
- updateRepo(repoId: number, repoSettings: RepoSettings): Promise {
+ async updateRepo(repoId: number, repoSettings: RepoSettings): Promise {
return this._patch(`/api/repos/${repoId}`, repoSettings);
}
- deleteRepo(repoId: number, remove = true): Promise {
+ async deleteRepo(repoId: number, remove = true): Promise {
const query = encodeQueryString({ remove });
return this._delete(`/api/repos/${repoId}?${query}`);
}
- repairRepo(repoId: number): Promise {
+ async repairRepo(repoId: number): Promise {
return this._post(`/api/repos/${repoId}/repair`);
}
- createPipeline(repoId: number, options: PipelineOptions): Promise {
+ async createPipeline(repoId: number, options: PipelineOptions): Promise {
return this._post(`/api/repos/${repoId}/pipelines`, options) as Promise;
}
// Deploy triggers a deployment for an existing pipeline using the
// specified target environment and task.
- deployPipeline(repoId: number, pipelineNumber: string, options: DeploymentOptions): Promise {
+ async deployPipeline(repoId: number, pipelineNumber: string, options: DeploymentOptions): Promise {
const vars = {
...options.variables,
event: 'deployment',
@@ -103,36 +103,39 @@ export default class WoodpeckerClient extends ApiClient {
return this._post(`/api/repos/${repoId}/pipelines/${pipelineNumber}?${query}`) as Promise;
}
- getPipelineList(repoId: number, opts?: PaginationOptions & { before?: string; after?: string }): Promise {
+ async getPipelineList(
+ repoId: number,
+ opts?: PaginationOptions & { before?: string; after?: string },
+ ): Promise {
const query = encodeQueryString(opts);
return this._get(`/api/repos/${repoId}/pipelines?${query}`) as Promise;
}
- getPipeline(repoId: number, pipelineNumber: number | 'latest'): Promise {
+ async getPipeline(repoId: number, pipelineNumber: number | 'latest'): Promise {
return this._get(`/api/repos/${repoId}/pipelines/${pipelineNumber}`) as Promise;
}
- getPipelineConfig(repoId: number, pipelineNumber: number): Promise {
+ async getPipelineConfig(repoId: number, pipelineNumber: number): Promise {
return this._get(`/api/repos/${repoId}/pipelines/${pipelineNumber}/config`) as Promise;
}
- getPipelineFeed(): Promise {
+ async getPipelineFeed(): Promise {
return this._get(`/api/user/feed`) as Promise;
}
- cancelPipeline(repoId: number, pipelineNumber: number): Promise {
+ async cancelPipeline(repoId: number, pipelineNumber: number): Promise {
return this._post(`/api/repos/${repoId}/pipelines/${pipelineNumber}/cancel`);
}
- approvePipeline(repoId: number, pipelineNumber: string): Promise {
+ async approvePipeline(repoId: number, pipelineNumber: string): Promise {
return this._post(`/api/repos/${repoId}/pipelines/${pipelineNumber}/approve`);
}
- declinePipeline(repoId: number, pipelineNumber: string): Promise {
+ async declinePipeline(repoId: number, pipelineNumber: string): Promise {
return this._post(`/api/repos/${repoId}/pipelines/${pipelineNumber}/decline`);
}
- restartPipeline(
+ async restartPipeline(
repoId: number,
pipeline: string,
opts?: { event?: string; deploy_to?: string; fork?: boolean },
@@ -141,227 +144,261 @@ export default class WoodpeckerClient extends ApiClient {
return this._post(`/api/repos/${repoId}/pipelines/${pipeline}?${query}`) as Promise;
}
- getLogs(repoId: number, pipeline: number, step: number): Promise {
+ async getLogs(repoId: number, pipeline: number, step: number): Promise {
return this._get(`/api/repos/${repoId}/logs/${pipeline}/${step}`) as Promise;
}
- deleteLogs(repoId: number, pipeline: number, step: number): Promise {
+ async deleteLogs(repoId: number, pipeline: number, step: number): Promise {
return this._delete(`/api/repos/${repoId}/logs/${pipeline}/${step}`);
}
- getSecretList(repoId: number, opts?: PaginationOptions): Promise {
+ async getSecretList(repoId: number, opts?: PaginationOptions): Promise {
const query = encodeQueryString(opts);
return this._get(`/api/repos/${repoId}/secrets?${query}`) as Promise;
}
- createSecret(repoId: number, secret: Partial): Promise {
+ async createSecret(repoId: number, secret: Partial): Promise {
return this._post(`/api/repos/${repoId}/secrets`, secret);
}
- updateSecret(repoId: number, secret: Partial): Promise {
+ async updateSecret(repoId: number, secret: Partial): Promise {
const secretName = encodeURIComponent(secret.name ?? '');
return this._patch(`/api/repos/${repoId}/secrets/${secretName}`, secret);
}
- deleteSecret(repoId: number, secretName: string): Promise {
+ async deleteSecret(repoId: number, secretName: string): Promise {
const name = encodeURIComponent(secretName);
return this._delete(`/api/repos/${repoId}/secrets/${name}`);
}
- getRegistryList(repoId: number, opts?: PaginationOptions): Promise {
+ async getRegistryList(repoId: number, opts?: PaginationOptions): Promise {
const query = encodeQueryString(opts);
- return this._get(`/api/repos/${repoId}/registry?${query}`) as Promise;
+ return this._get(`/api/repos/${repoId}/registries?${query}`) as Promise;
}
- createRegistry(repoId: number, registry: Partial): Promise {
- return this._post(`/api/repos/${repoId}/registry`, registry);
+ async createRegistry(repoId: number, registry: Partial): Promise {
+ return this._post(`/api/repos/${repoId}/registries`, registry);
}
- updateRegistry(repoId: number, registry: Partial): Promise {
- return this._patch(`/api/repos/${repoId}/registry/${registry.address}`, registry);
+ async updateRegistry(repoId: number, registry: Partial): Promise {
+ return this._patch(`/api/repos/${repoId}/registries/${registry.address}`, registry);
}
- deleteRegistry(repoId: number, registryAddress: string): Promise {
- return this._delete(`/api/repos/${repoId}/registry/${registryAddress}`);
+ async deleteRegistry(repoId: number, registryAddress: string): Promise {
+ return this._delete(`/api/repos/${repoId}/registries/${registryAddress}`);
}
- getCronList(repoId: number, opts?: PaginationOptions): Promise {
+ async getOrgRegistryList(orgId: number, opts?: PaginationOptions): Promise {
+ const query = encodeQueryString(opts);
+ return this._get(`/api/orgs/${orgId}/registries?${query}`) as Promise;
+ }
+
+ async createOrgRegistry(orgId: number, registry: Partial): Promise {
+ return this._post(`/api/orgs/${orgId}/registries`, registry);
+ }
+
+ async updateOrgRegistry(orgId: number, registry: Partial): Promise {
+ return this._patch(`/api/orgs/${orgId}/registries/${registry.address}`, registry);
+ }
+
+ async deleteOrgRegistry(orgId: number, registryAddress: string): Promise {
+ return this._delete(`/api/orgs/${orgId}/registries/${registryAddress}`);
+ }
+
+ async getGlobalRegistryList(opts?: PaginationOptions): Promise {
+ const query = encodeQueryString(opts);
+ return this._get(`/api/registries?${query}`) as Promise;
+ }
+
+ async createGlobalRegistry(registry: Partial): Promise {
+ return this._post(`/api/registries`, registry);
+ }
+
+ async updateGlobalRegistry(registry: Partial): Promise {
+ return this._patch(`/api/registries/${registry.address}`, registry);
+ }
+
+ async deleteGlobalRegistry(registryAddress: string): Promise {
+ return this._delete(`/api/registries/${registryAddress}`);
+ }
+
+ async getCronList(repoId: number, opts?: PaginationOptions): Promise {
const query = encodeQueryString(opts);
return this._get(`/api/repos/${repoId}/cron?${query}`) as Promise;
}
- createCron(repoId: number, cron: Partial): Promise {
+ async createCron(repoId: number, cron: Partial): Promise {
return this._post(`/api/repos/${repoId}/cron`, cron);
}
- updateCron(repoId: number, cron: Partial): Promise {
+ async updateCron(repoId: number, cron: Partial): Promise {
return this._patch(`/api/repos/${repoId}/cron/${cron.id}`, cron);
}
- deleteCron(repoId: number, cronId: number): Promise {
+ async deleteCron(repoId: number, cronId: number): Promise {
return this._delete(`/api/repos/${repoId}/cron/${cronId}`);
}
- runCron(repoId: number, cronId: number): Promise {
+ async runCron(repoId: number, cronId: number): Promise {
return this._post(`/api/repos/${repoId}/cron/${cronId}`) as Promise;
}
- getOrg(orgId: number): Promise {
+ async getOrg(orgId: number): Promise {
return this._get(`/api/orgs/${orgId}`) as Promise;
}
- lookupOrg(name: string): Promise {
+ async lookupOrg(name: string): Promise {
return this._get(`/api/orgs/lookup/${name}`) as Promise;
}
- getOrgPermissions(orgId: number): Promise {
+ async getOrgPermissions(orgId: number): Promise {
return this._get(`/api/orgs/${orgId}/permissions`) as Promise;
}
- getOrgSecretList(orgId: number, opts?: PaginationOptions): Promise {
+ async getOrgSecretList(orgId: number, opts?: PaginationOptions): Promise {
const query = encodeQueryString(opts);
return this._get(`/api/orgs/${orgId}/secrets?${query}`) as Promise;
}
- createOrgSecret(orgId: number, secret: Partial): Promise {
+ async createOrgSecret(orgId: number, secret: Partial): Promise {
return this._post(`/api/orgs/${orgId}/secrets`, secret);
}
- updateOrgSecret(orgId: number, secret: Partial): Promise {
+ async updateOrgSecret(orgId: number, secret: Partial): Promise {
const secretName = encodeURIComponent(secret.name ?? '');
return this._patch(`/api/orgs/${orgId}/secrets/${secretName}`, secret);
}
- deleteOrgSecret(orgId: number, secretName: string): Promise {
+ async deleteOrgSecret(orgId: number, secretName: string): Promise {
const name = encodeURIComponent(secretName);
return this._delete(`/api/orgs/${orgId}/secrets/${name}`);
}
- getGlobalSecretList(opts?: PaginationOptions): Promise {
+ async getGlobalSecretList(opts?: PaginationOptions): Promise {
const query = encodeQueryString(opts);
return this._get(`/api/secrets?${query}`) as Promise;
}
- createGlobalSecret(secret: Partial): Promise {
+ async createGlobalSecret(secret: Partial): Promise