mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-02-07 23:22:21 +00:00
Merge branch 'main' into pr/anbraten/3849
This commit is contained in:
commit
b804585b88
1043 changed files with 37686 additions and 25984 deletions
87
.cspell.json
87
.cspell.json
|
@ -6,39 +6,51 @@
|
|||
"en_us",
|
||||
// code
|
||||
"go",
|
||||
"node",
|
||||
// package names
|
||||
"npm"
|
||||
"node"
|
||||
],
|
||||
"words": [
|
||||
"abool",
|
||||
"addgroup",
|
||||
"adduser",
|
||||
"anbraten",
|
||||
"antfu",
|
||||
"apimachinery",
|
||||
"appleboy",
|
||||
"Archlinux",
|
||||
"autoincr",
|
||||
"automerge",
|
||||
"autoscaler",
|
||||
"backporting",
|
||||
"backports",
|
||||
"binutils",
|
||||
"bitbucketdatacenter",
|
||||
"Boguslawski",
|
||||
"bradrydzewski",
|
||||
"BUILDPLATFORM",
|
||||
"buildx",
|
||||
"caddyfile",
|
||||
"ccmenu",
|
||||
"certmagic",
|
||||
"charmbracelet",
|
||||
"cicd",
|
||||
"ciphertext",
|
||||
"Cloudron",
|
||||
"Codeberg",
|
||||
"compatiblelicenses",
|
||||
"corepack",
|
||||
"cpuset",
|
||||
"creativecommons",
|
||||
"Curr",
|
||||
"CERTDIR",
|
||||
"datacenter",
|
||||
"DATASOURCE",
|
||||
"Debugf",
|
||||
"desaturate",
|
||||
"devx",
|
||||
"dind",
|
||||
"Dockle",
|
||||
"doublestar",
|
||||
"emojify",
|
||||
"envsubst",
|
||||
"errgroup",
|
||||
"estree",
|
||||
|
@ -46,64 +58,90 @@
|
|||
"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",
|
||||
"openapi",
|
||||
"opensource",
|
||||
"Pacman",
|
||||
"picus",
|
||||
"Pinia",
|
||||
"pkce",
|
||||
"pnpx",
|
||||
"Polyform",
|
||||
"posix",
|
||||
"ppid",
|
||||
"Println",
|
||||
|
@ -123,19 +161,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 +188,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 +241,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",
|
||||
// generated
|
||||
"go.sum",
|
||||
"flake.lock",
|
||||
"pnpm-lock.yaml",
|
||||
"**/node_modules/**/*",
|
||||
"cmd/server/openapi/docs.go",
|
||||
"renovate.json",
|
||||
// TODO: remove the following
|
||||
"docs/"
|
||||
"docs/**/*.js",
|
||||
"docs/**/*.ts"
|
||||
],
|
||||
// Exclude imports, because they are also strings.
|
||||
"ignoreRegExpList": [
|
||||
|
@ -210,7 +273,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"]
|
||||
}
|
||||
|
|
5
.ecrc
5
.ecrc
|
@ -1,14 +1,15 @@
|
|||
{
|
||||
"Exclude": [
|
||||
".git",
|
||||
"go.mod", "go.sum",
|
||||
"go.mod",
|
||||
"go.sum",
|
||||
"vendor",
|
||||
"fixtures",
|
||||
"LICENSE",
|
||||
"node_modules",
|
||||
"server/store/datastore/migration/test-files/sqlite.db",
|
||||
"server/store/datastore/feed.go",
|
||||
"cmd/server/docs/docs.go",
|
||||
"cmd/server/openapi/docs.go",
|
||||
"_test.go",
|
||||
"Makefile"
|
||||
]
|
||||
|
|
11
.github/pull_request_template.md
vendored
Normal file
11
.github/pull_request_template.md
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
<!--
|
||||
|
||||
Please check the following tips:
|
||||
1. Avoid using force-push and commands that require it (such as `commit --amend` and `rebase origin/main`). This makes it more difficult for the maintainers to review your work. Add new commits on top of the current branch, and merge the new state of `main` into your branch with plain `merge`.
|
||||
2. Provide a meaningful title for this pull request. It will be used as the commit message when this pull request is merged. Add as many commits as you like with any messages you like, they will be squashed into one commit.
|
||||
3. If this pull request fixes an issue, refer to the issue with messages like `Closes #1234`, or `Fixes #1234` in the pull description.
|
||||
4. Please check that you are targeting the `main` branch. Pull requests on release branches are only allowed for backports.
|
||||
5. Make sure you have read contribution guidelines: https://woodpecker-ci.org/docs/development/getting-started
|
||||
6. It is recommended to enable "Allow edits by maintainers", so maintainers can help you more easily.
|
||||
|
||||
-->
|
12
.github/renovate.json
vendored
12
.github/renovate.json
vendored
|
@ -1,12 +1,13 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["github>woodpecker-ci/renovate-config"],
|
||||
"automergeType": "pr",
|
||||
"customManagers": [
|
||||
{
|
||||
"customType": "regex",
|
||||
"fileMatch": ["shared/constant/constant.go"],
|
||||
"matchStrings": [
|
||||
"//\\s*renovate:\\s*datasource=(?<datasource>.*?) depName=(?<depName>.*?)( versioning=(?<versioning>.*?))?\\s+DefaultCloneImage = \"docker.io/woodpeckerci/plugin-git:(?<currentValue>.*)\""
|
||||
"//\\s*renovate:\\s*datasource=(?<datasource>.*?) depName=(?<depName>.*?)( versioning=(?<versioning>.*?))?\\s+DefaultClonePlugin = \"docker.io/woodpeckerci/plugin-git:(?<currentValue>.*)\""
|
||||
],
|
||||
"versioningTemplate": "{{#if versioning}}{{{versioning}}}{{else}}semver{{/if}}"
|
||||
}
|
||||
|
@ -29,8 +30,8 @@
|
|||
},
|
||||
{
|
||||
"groupName": "golang-lang",
|
||||
"matchPackagePatterns": ["^golang$", "xgo"],
|
||||
"matchUpdateTypes": ["minor", "patch"]
|
||||
"matchUpdateTypes": ["minor", "patch"],
|
||||
"matchPackageNames": ["/^golang$/", "/xgo/"]
|
||||
},
|
||||
{
|
||||
"groupName": "golang-packages",
|
||||
|
@ -60,9 +61,10 @@
|
|||
"matchFileNames": ["docs/**/package.json"]
|
||||
},
|
||||
{
|
||||
"description": "Extract version from xgo container tags",
|
||||
"matchDatasources": ["docker"],
|
||||
"matchPackagePatterns": ["xgo"],
|
||||
"versioning": "regex:^go-(?<major>\\d+)?(\\.(?<minor>\\d+))?(\\.(?<patch>\\d+))$"
|
||||
"versioning": "regex:^go-(?<major>\\d+)\\.(?<minor>\\d+)\\.x$",
|
||||
"matchPackageNames": ["/techknowlogick/xgo/"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -51,4 +51,7 @@ docs/venv
|
|||
|
||||
### Generated by CI ###
|
||||
docs/docs/40-cli.md
|
||||
docs/openapi.json
|
||||
|
||||
# Removed once v3.0.x is minimum version to be touched
|
||||
docs/swagger.json
|
||||
|
|
|
@ -112,9 +112,10 @@ vscode:
|
|||
- 'EditorConfig.EditorConfig'
|
||||
- 'dbaeumer.vscode-eslint'
|
||||
- 'esbenp.prettier-vscode'
|
||||
- 'voorjaar.windicss-intellisense'
|
||||
- 'bradlc.vscode-tailwindcss'
|
||||
- 'Vue.volar'
|
||||
- 'redhat.vscode-yaml'
|
||||
- 'davidanson.vscode-markdownlint'
|
||||
- 'streetsidesoftware.code-spell-checker'
|
||||
- 'stivo.tailwind-fold'
|
||||
# cSpell:enable
|
||||
|
|
1
.lycheeignore
Normal file
1
.lycheeignore
Normal file
|
@ -0,0 +1 @@
|
|||
https://stackoverflow.com/*
|
|
@ -5,16 +5,16 @@ repos:
|
|||
- id: check-hooks-apply
|
||||
- id: check-useless-excludes
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.6.0
|
||||
rev: v5.0.0
|
||||
hooks:
|
||||
- id: end-of-file-fixer
|
||||
- id: trailing-whitespace
|
||||
- repo: https://github.com/golangci/golangci-lint
|
||||
rev: v1.59.1
|
||||
rev: v1.63.4
|
||||
hooks:
|
||||
- id: golangci-lint
|
||||
- repo: https://github.com/igorshubovych/markdownlint-cli
|
||||
rev: v0.41.0
|
||||
rev: v0.43.0
|
||||
hooks:
|
||||
- id: markdownlint
|
||||
exclude: '^(docs/versioned_docs/.*|CHANGELOG.md)$'
|
||||
|
@ -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.13.0-beta
|
||||
rev: v2.13.1-beta
|
||||
hooks:
|
||||
- id: hadolint
|
||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||
rev: v4.0.0-alpha.8
|
||||
- repo: https://github.com/rbubley/mirrors-prettier
|
||||
rev: v3.4.2
|
||||
hooks:
|
||||
- id: prettier
|
||||
- repo: https://github.com/adrienverge/yamllint.git
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
build/
|
||||
docs/versioned_docs/
|
||||
docs/.docusaurus/
|
||||
docs/pnpm-lock.yaml
|
||||
dist/
|
||||
CHANGELOG.md
|
||||
|
||||
# web/ must be directly formatted from there
|
||||
# web/ and docs/ must be directly formatted from there
|
||||
# to prevent conflicts with different prettier version
|
||||
web/
|
||||
docs/
|
||||
|
|
5
.vscode/extensions.json
vendored
5
.vscode/extensions.json
vendored
|
@ -5,10 +5,11 @@
|
|||
"EditorConfig.EditorConfig",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode",
|
||||
"voorjaar.windicss-intellisense",
|
||||
"bradlc.vscode-tailwindcss",
|
||||
"Vue.volar",
|
||||
"redhat.vscode-yaml",
|
||||
"davidanson.vscode-markdownlint"
|
||||
"davidanson.vscode-markdownlint",
|
||||
"stivo.tailwind-fold"
|
||||
],
|
||||
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
||||
"unwantedRecommendations": []
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
when:
|
||||
event: tag
|
||||
- event: tag
|
||||
- event: pull_request
|
||||
branch: ${CI_REPO_DEFAULT_BRANCH}
|
||||
path:
|
||||
- Makefile
|
||||
- .woodpecker/binaries.yaml
|
||||
|
||||
variables:
|
||||
- &golang_image 'docker.io/golang:1.22'
|
||||
- &node_image 'docker.io/node:22-alpine'
|
||||
- &xgo_image 'docker.io/techknowlogick/xgo:go-1.22.x'
|
||||
- &golang_image 'docker.io/golang:1.23'
|
||||
- &node_image 'docker.io/node:23-alpine'
|
||||
- &xgo_image 'docker.io/techknowlogick/xgo:go-1.23.x'
|
||||
|
||||
# cspell:words bindata netgo TARGZ
|
||||
# cspell:words bindata netgo
|
||||
|
||||
steps:
|
||||
build-web:
|
||||
|
@ -35,7 +40,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 +55,8 @@ steps:
|
|||
- vendor
|
||||
image: *golang_image
|
||||
commands:
|
||||
- apt update
|
||||
- apt install -y zip
|
||||
- make release-agent
|
||||
|
||||
build-cli:
|
||||
|
@ -57,6 +64,8 @@ steps:
|
|||
- vendor
|
||||
image: *golang_image
|
||||
commands:
|
||||
- apt update
|
||||
- apt install -y zip
|
||||
- make release-cli
|
||||
|
||||
build-deb-rpm:
|
||||
|
@ -90,13 +99,16 @@ steps:
|
|||
release:
|
||||
depends_on:
|
||||
- checksums
|
||||
image: woodpeckerci/plugin-release:0.1.0
|
||||
image: woodpeckerci/plugin-release:0.2.2
|
||||
settings:
|
||||
api_key:
|
||||
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
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
variables:
|
||||
- &golang_image 'docker.io/golang:1.22'
|
||||
- &node_image 'docker.io/node:22-alpine'
|
||||
- &xgo_image 'docker.io/techknowlogick/xgo:go-1.22.x'
|
||||
- &buildx_plugin 'docker.io/woodpeckerci/plugin-docker-buildx:4.0.0'
|
||||
- &golang_image 'docker.io/golang:1.23'
|
||||
- &node_image 'docker.io/node:23-alpine'
|
||||
- &xgo_image 'docker.io/techknowlogick/xgo:go-1.23.x'
|
||||
- &buildx_plugin 'docker.io/woodpeckerci/plugin-docker-buildx:5.1.0'
|
||||
- &platforms_release 'linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/386,linux/amd64,linux/ppc64le,linux/riscv64,linux/s390x,freebsd/arm64,freebsd/amd64,openbsd/arm64,openbsd/amd64'
|
||||
- &platforms_server 'linux/arm/v7,linux/arm64/v8,linux/amd64,linux/ppc64le,linux/riscv64'
|
||||
- &platforms_preview 'linux/amd64'
|
||||
- &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
|
||||
|
@ -41,9 +41,6 @@ variables:
|
|||
|
||||
when:
|
||||
- event: [pull_request, tag]
|
||||
- event: push
|
||||
branch:
|
||||
- renovate/*
|
||||
- event: push
|
||||
branch: ${CI_REPO_DEFAULT_BRANCH}
|
||||
path: *when_path
|
||||
|
@ -61,7 +58,6 @@ steps:
|
|||
path: *when_path
|
||||
- branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
- renovate/*
|
||||
event: [push, tag]
|
||||
path: *when_path
|
||||
|
||||
|
@ -82,7 +78,6 @@ steps:
|
|||
path: *when_path
|
||||
- branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
- renovate/*
|
||||
event: [push, tag]
|
||||
path: *when_path
|
||||
|
||||
|
@ -104,9 +99,6 @@ steps:
|
|||
evaluate: 'CI_COMMIT_PULL_REQUEST_LABELS contains "build_pr_images"'
|
||||
- event: pull_request
|
||||
path: *when_path
|
||||
- event: push
|
||||
path: *when_path
|
||||
branch: renovate/*
|
||||
|
||||
cross-compile-server:
|
||||
depends_on:
|
||||
|
@ -127,31 +119,19 @@ steps:
|
|||
event: [push, tag]
|
||||
path: *when_path
|
||||
|
||||
publish-server-preview:
|
||||
depends_on:
|
||||
- cross-compile-server-preview
|
||||
image: *buildx_plugin
|
||||
settings:
|
||||
repo: woodpeckerci/woodpecker-server
|
||||
dockerfile: docker/Dockerfile.server.multiarch
|
||||
platforms: *platforms_preview
|
||||
tag: pull_${CI_COMMIT_PULL_REQUEST}
|
||||
logins: *publish_logins
|
||||
when: &when-preview
|
||||
evaluate: 'CI_COMMIT_PULL_REQUEST_LABELS contains "build_pr_images"'
|
||||
event: pull_request
|
||||
|
||||
publish-server-alpine-preview:
|
||||
depends_on:
|
||||
- cross-compile-server-preview
|
||||
image: *buildx_plugin
|
||||
settings:
|
||||
repo: woodpeckerci/woodpecker-server
|
||||
dockerfile: docker/Dockerfile.server.alpine.multiarch
|
||||
dockerfile: docker/Dockerfile.server.alpine.multiarch.rootless
|
||||
platforms: *platforms_preview
|
||||
tag: pull_${CI_COMMIT_PULL_REQUEST}-alpine
|
||||
logins: *publish_logins
|
||||
when: *when-preview
|
||||
when: &when-preview
|
||||
evaluate: 'CI_COMMIT_PULL_REQUEST_LABELS contains "build_pr_images"'
|
||||
event: pull_request
|
||||
|
||||
build-server-dryrun:
|
||||
depends_on:
|
||||
|
@ -162,16 +142,13 @@ steps:
|
|||
settings:
|
||||
dry_run: true
|
||||
repo: woodpeckerci/woodpecker-server
|
||||
dockerfile: docker/Dockerfile.server.multiarch
|
||||
dockerfile: docker/Dockerfile.server.multiarch.rootless
|
||||
platforms: *platforms_preview
|
||||
tag: pull_${CI_COMMIT_PULL_REQUEST}
|
||||
when: &when-dryrun
|
||||
- evaluate: 'not (CI_COMMIT_PULL_REQUEST_LABELS contains "build_pr_images")'
|
||||
event: pull_request
|
||||
path: *when_path
|
||||
- event: push
|
||||
path: *when_path
|
||||
branch: renovate/*
|
||||
|
||||
publish-next-server:
|
||||
depends_on:
|
||||
|
@ -179,7 +156,7 @@ steps:
|
|||
image: *buildx_plugin
|
||||
settings:
|
||||
repo: *publish_repos_server
|
||||
dockerfile: docker/Dockerfile.server.multiarch
|
||||
dockerfile: docker/Dockerfile.server.multiarch.rootless
|
||||
platforms: *platforms_server
|
||||
tag: [next, 'next-${CI_COMMIT_SHA:0:10}']
|
||||
logins: *publish_logins
|
||||
|
@ -194,7 +171,7 @@ steps:
|
|||
image: *buildx_plugin
|
||||
settings:
|
||||
repo: *publish_repos_server
|
||||
dockerfile: docker/Dockerfile.server.alpine.multiarch
|
||||
dockerfile: docker/Dockerfile.server.alpine.multiarch.rootless
|
||||
platforms: *platforms_alpine
|
||||
tag: [next-alpine, 'next-${CI_COMMIT_SHA:0:10}-alpine']
|
||||
logins: *publish_logins
|
||||
|
@ -206,10 +183,9 @@ steps:
|
|||
image: *buildx_plugin
|
||||
settings:
|
||||
repo: *publish_repos_server
|
||||
dockerfile: docker/Dockerfile.server.multiarch
|
||||
dockerfile: docker/Dockerfile.server.multiarch.rootless
|
||||
platforms: *platforms_server
|
||||
# remove 'latest' on older version branches to avoid accidental downgrade
|
||||
tag: [latest, '${CI_COMMIT_TAG}']
|
||||
tag: ['${CI_COMMIT_TAG%%.*}', '${CI_COMMIT_TAG%.*}-alpine', '${CI_COMMIT_TAG}']
|
||||
logins: *publish_logins
|
||||
when: &when-release
|
||||
event: tag
|
||||
|
@ -220,10 +196,9 @@ steps:
|
|||
image: *buildx_plugin
|
||||
settings:
|
||||
repo: *publish_repos_server
|
||||
dockerfile: docker/Dockerfile.server.alpine.multiarch
|
||||
dockerfile: docker/Dockerfile.server.alpine.multiarch.rootless
|
||||
platforms: *platforms_alpine
|
||||
# remove 'latest-alpine' on older version branches to avoid accidental downgrade
|
||||
tag: [latest-alpine, '${CI_COMMIT_TAG}-alpine']
|
||||
tag: ['${CI_COMMIT_TAG%%.*}-alpine', '${CI_COMMIT_TAG%.*}-alpine', '${CI_COMMIT_TAG}-alpine']
|
||||
logins: *publish_logins
|
||||
when: *when-release
|
||||
|
||||
|
@ -231,15 +206,15 @@ steps:
|
|||
# A g e n t #
|
||||
#############
|
||||
|
||||
publish-agent-preview:
|
||||
publish-agent-preview-alpine:
|
||||
depends_on:
|
||||
- vendor
|
||||
image: *buildx_plugin
|
||||
settings:
|
||||
repo: woodpeckerci/woodpecker-agent
|
||||
dockerfile: docker/Dockerfile.agent.multiarch
|
||||
dockerfile: docker/Dockerfile.agent.alpine.multiarch
|
||||
platforms: *platforms_preview
|
||||
tag: pull_${CI_COMMIT_PULL_REQUEST}
|
||||
tag: pull_${CI_COMMIT_PULL_REQUEST}-alpine
|
||||
build_args: *build_args
|
||||
logins: *publish_logins
|
||||
when: *when-preview
|
||||
|
@ -303,8 +278,7 @@ steps:
|
|||
repo: *publish_repos_agent
|
||||
dockerfile: docker/Dockerfile.agent.multiarch
|
||||
platforms: *platforms_release
|
||||
# remove 'latest' on older version branches to avoid accidental downgrade
|
||||
tag: [latest, '${CI_COMMIT_TAG}']
|
||||
tag: ['${CI_COMMIT_TAG%%.*}', '${CI_COMMIT_TAG%.*}', '${CI_COMMIT_TAG}']
|
||||
logins: *publish_logins
|
||||
build_args: *build_args
|
||||
when: *when-release
|
||||
|
@ -320,8 +294,7 @@ steps:
|
|||
repo: *publish_repos_agent
|
||||
dockerfile: docker/Dockerfile.agent.alpine.multiarch
|
||||
platforms: *platforms_alpine
|
||||
# remove 'latest-alpine' on older version branches to avoid accidental downgrade
|
||||
tag: [latest-alpine, '${CI_COMMIT_TAG}-alpine']
|
||||
tag: ['${CI_COMMIT_TAG%%.*}-alpine', '${CI_COMMIT_TAG%.*}-alpine', '${CI_COMMIT_TAG}-alpine']
|
||||
logins: *publish_logins
|
||||
build_args: *build_args
|
||||
when: *when-release
|
||||
|
@ -330,19 +303,6 @@ steps:
|
|||
# C L I #
|
||||
#########
|
||||
|
||||
publish-cli-preview:
|
||||
depends_on:
|
||||
- vendor
|
||||
image: *buildx_plugin
|
||||
settings:
|
||||
repo: woodpeckerci/woodpecker-cli
|
||||
dockerfile: docker/Dockerfile.cli.multiarch
|
||||
platforms: *platforms_preview
|
||||
tag: pull_${CI_COMMIT_PULL_REQUEST}
|
||||
build_args: *build_args
|
||||
logins: *publish_logins
|
||||
when: *when-preview
|
||||
|
||||
build-cli-dryrun:
|
||||
depends_on:
|
||||
- vendor
|
||||
|
@ -350,7 +310,7 @@ steps:
|
|||
settings:
|
||||
dry_run: true
|
||||
repo: woodpeckerci/woodpecker-cli
|
||||
dockerfile: docker/Dockerfile.cli.multiarch
|
||||
dockerfile: docker/Dockerfile.cli.multiarch.rootless
|
||||
platforms: *platforms_preview
|
||||
tag: pull_${CI_COMMIT_PULL_REQUEST}
|
||||
build_args: *build_args
|
||||
|
@ -365,7 +325,7 @@ steps:
|
|||
image: *buildx_plugin
|
||||
settings:
|
||||
repo: *publish_repos_cli
|
||||
dockerfile: docker/Dockerfile.cli.multiarch
|
||||
dockerfile: docker/Dockerfile.cli.multiarch.rootless
|
||||
platforms: *platforms_release
|
||||
tag: [next, 'next-${CI_COMMIT_SHA:0:10}']
|
||||
logins: *publish_logins
|
||||
|
@ -381,7 +341,7 @@ steps:
|
|||
image: *buildx_plugin
|
||||
settings:
|
||||
repo: *publish_repos_cli
|
||||
dockerfile: docker/Dockerfile.cli.alpine.multiarch
|
||||
dockerfile: docker/Dockerfile.cli.alpine.multiarch.rootless
|
||||
platforms: *platforms_alpine
|
||||
tag: [next-alpine, 'next-${CI_COMMIT_SHA:0:10}-alpine']
|
||||
logins: *publish_logins
|
||||
|
@ -397,10 +357,9 @@ steps:
|
|||
image: *buildx_plugin
|
||||
settings:
|
||||
repo: *publish_repos_cli
|
||||
dockerfile: docker/Dockerfile.cli.multiarch
|
||||
dockerfile: docker/Dockerfile.cli.multiarch.rootless
|
||||
platforms: *platforms_release
|
||||
# remove 'latest' on older version branches to avoid accidental downgrade
|
||||
tag: [latest, '${CI_COMMIT_TAG}']
|
||||
tag: ['${CI_COMMIT_TAG%%.*}', '${CI_COMMIT_TAG%.*}', '${CI_COMMIT_TAG}']
|
||||
logins: *publish_logins
|
||||
build_args: *build_args
|
||||
when: *when-release
|
||||
|
@ -414,10 +373,9 @@ steps:
|
|||
image: *buildx_plugin
|
||||
settings:
|
||||
repo: *publish_repos_cli
|
||||
dockerfile: docker/Dockerfile.cli.alpine.multiarch
|
||||
dockerfile: docker/Dockerfile.cli.alpine.multiarch.rootless
|
||||
platforms: *platforms_alpine
|
||||
# remove 'latest-alpine' on older version branches to avoid accidental downgrade
|
||||
tag: [latest-alpine, '${CI_COMMIT_TAG}-alpine']
|
||||
tag: ['${CI_COMMIT_TAG%%.*}-alpine', '${CI_COMMIT_TAG%.*}-alpine', '${CI_COMMIT_TAG}-alpine']
|
||||
logins: *publish_logins
|
||||
build_args: *build_args
|
||||
when: *when-release
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
variables:
|
||||
- &golang_image 'docker.io/golang:1.22'
|
||||
- &node_image 'docker.io/node:21-alpine'
|
||||
- &alpine_image 'docker.io/alpine:3.19'
|
||||
- &golang_image 'docker.io/golang:1.23'
|
||||
- &node_image 'docker.io/node:23-alpine'
|
||||
- &alpine_image 'docker.io/alpine:3.21'
|
||||
- path: &when_path
|
||||
- 'docs/**'
|
||||
- '.woodpecker/docs.yaml'
|
||||
|
@ -31,13 +31,22 @@ when:
|
|||
- <<: *docker_path
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
- renovate/*
|
||||
- event: pull_request_closed
|
||||
path: *when_path
|
||||
- event: manual
|
||||
evaluate: 'TASK == "docs"'
|
||||
|
||||
steps:
|
||||
prettier:
|
||||
image: docker.io/woodpeckerci/plugin-prettier:next
|
||||
settings:
|
||||
version: 3.3.3
|
||||
plugins:
|
||||
- 'prettier-plugin-tailwindcss'
|
||||
- '@ianvs/prettier-plugin-sort-imports'
|
||||
when:
|
||||
- event: pull_request
|
||||
|
||||
build-cli:
|
||||
image: *golang_image
|
||||
commands:
|
||||
|
@ -60,7 +69,7 @@ steps:
|
|||
- event: manual
|
||||
|
||||
deploy-preview:
|
||||
image: docker.io/woodpeckerci/plugin-surge-preview:1.3.0
|
||||
image: docker.io/woodpeckerci/plugin-surge-preview:1.3.3
|
||||
settings:
|
||||
path: 'docs/build/'
|
||||
surge_token:
|
||||
|
@ -69,13 +78,14 @@ steps:
|
|||
from_secret: GITHUB_TOKEN_SURGE
|
||||
failure: ignore
|
||||
when:
|
||||
event: [pull_request, pull_request_closed]
|
||||
path: *when_path
|
||||
- event: [pull_request, pull_request_closed]
|
||||
path: *when_path
|
||||
|
||||
deploy-prepare:
|
||||
image: *alpine_image
|
||||
secrets:
|
||||
- BOT_PRIVATE_KEY
|
||||
environment:
|
||||
BOT_PRIVATE_KEY:
|
||||
from_secret: BOT_PRIVATE_KEY
|
||||
commands:
|
||||
- apk add openssh-client git
|
||||
- mkdir -p $HOME/.ssh
|
||||
|
@ -127,8 +137,9 @@ steps:
|
|||
|
||||
deploy:
|
||||
image: *alpine_image
|
||||
secrets:
|
||||
- BOT_PRIVATE_KEY
|
||||
environment:
|
||||
BOT_PRIVATE_KEY:
|
||||
from_secret: BOT_PRIVATE_KEY
|
||||
commands:
|
||||
- apk add openssh-client rsync git
|
||||
- mkdir -p $HOME/.ssh
|
||||
|
|
31
.woodpecker/links.yaml
Normal file
31
.woodpecker/links.yaml
Normal file
|
@ -0,0 +1,31 @@
|
|||
when:
|
||||
- event: cron
|
||||
cron: links
|
||||
|
||||
steps:
|
||||
- name: links
|
||||
image: docker.io/lycheeverse/lychee:0.15.1
|
||||
failure: ignore
|
||||
depends_on: []
|
||||
commands:
|
||||
- lychee pipeline/frontend/yaml/linter/schema/schema.json > links.md
|
||||
- lychee --exclude localhost docs/docs/ >> links.md
|
||||
- lychee --exclude localhost docs/src/pages/ >> links.md
|
||||
- echo -e "\nLast checked:$(date)" >> links.md
|
||||
|
||||
- name: Update issue
|
||||
image: docker.io/alpine:3.21
|
||||
depends_on: links
|
||||
environment:
|
||||
GITHUB_TOKEN:
|
||||
from_secret: github_token
|
||||
commands:
|
||||
- apk add -q --no-cache jq curl
|
||||
- export ISSUE_NUMBER=4514
|
||||
- export DESCRIPTION=$(cat links.md)
|
||||
- |
|
||||
curl -X PATCH \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
https://api.github.com/repos/${CI_REPO}/issues/$ISSUE_NUMBER \
|
||||
-d "$(jq -n --arg body "$DESCRIPTION" '{body: $body}')"
|
|
@ -1,16 +1,15 @@
|
|||
when:
|
||||
- event: push
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
- release/*
|
||||
|
||||
steps:
|
||||
release-helper:
|
||||
image: woodpeckerci/plugin-ready-release-go:1.1.2
|
||||
pull: true
|
||||
- name: release-helper
|
||||
image: docker.io/woodpeckerci/plugin-ready-release-go:3.1.1
|
||||
settings:
|
||||
release_branch: ${CI_REPO_DEFAULT_BRANCH}
|
||||
release_branch: ${CI_COMMIT_BRANCH}
|
||||
forge_type: github
|
||||
git_email: woodpecker-bot@obermui.de
|
||||
github_token:
|
||||
from_secret: GITHUB_TOKEN
|
||||
|
||||
when:
|
||||
- event: push
|
||||
branch: ${CI_REPO_DEFAULT_BRANCH}
|
||||
- event: manual
|
||||
evaluate: 'TASK == "release-helper"'
|
||||
|
|
|
@ -1,24 +1,25 @@
|
|||
when:
|
||||
- event: [pull_request, cron]
|
||||
- event: [pull_request]
|
||||
- event: push
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
- renovate/*
|
||||
|
||||
variables:
|
||||
- &trivy_plugin docker.io/woodpeckerci/plugin-trivy:1.1.0
|
||||
- &trivy_plugin docker.io/woodpeckerci/plugin-trivy:1.3.0
|
||||
|
||||
steps:
|
||||
backend:
|
||||
depends_on: []
|
||||
image: *trivy_plugin
|
||||
settings:
|
||||
server: server
|
||||
skip-dirs: web/,docs/
|
||||
|
||||
docs:
|
||||
depends_on: []
|
||||
image: *trivy_plugin
|
||||
settings:
|
||||
server: server
|
||||
skip-dirs: node_modules/,plugins/woodpecker-plugins/node_modules/
|
||||
dir: docs/
|
||||
|
||||
|
@ -26,5 +27,15 @@ steps:
|
|||
depends_on: []
|
||||
image: *trivy_plugin
|
||||
settings:
|
||||
server: server
|
||||
skip-dirs: node_modules/
|
||||
dir: web/
|
||||
|
||||
services:
|
||||
server:
|
||||
image: *trivy_plugin
|
||||
settings:
|
||||
service: true
|
||||
db-repository: docker.io/aquasec/trivy-db:2
|
||||
ports:
|
||||
- 10000
|
||||
|
|
|
@ -1,19 +1,15 @@
|
|||
when:
|
||||
- event: pull_request
|
||||
- event: push
|
||||
branch: renovate/*
|
||||
|
||||
steps:
|
||||
- name: lint-editorconfig
|
||||
image: docker.io/mstruebing/editorconfig-checker:v3.0.3
|
||||
image: docker.io/woodpeckerci/plugin-editorconfig-checker:0.2.0
|
||||
depends_on: []
|
||||
when:
|
||||
- event: pull_request
|
||||
- event: push
|
||||
branch: renovate/*
|
||||
|
||||
- name: spellcheck
|
||||
image: docker.io/node:22-alpine
|
||||
image: docker.io/node:23-alpine
|
||||
depends_on: []
|
||||
commands:
|
||||
- corepack enable
|
||||
|
@ -23,15 +19,11 @@ 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:next
|
||||
pull: true
|
||||
depends_on: []
|
||||
settings:
|
||||
version: 3.2.5
|
||||
|
||||
- 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/
|
||||
version: 3.3.3
|
||||
plugins:
|
||||
- 'prettier-plugin-tailwindcss'
|
||||
- '@ianvs/prettier-plugin-sort-imports'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
variables:
|
||||
- &golang_image 'docker.io/golang:1.22'
|
||||
- &golang_image 'docker.io/golang:1.23'
|
||||
- &when
|
||||
- path: &when_path # related config files
|
||||
- '.woodpecker/test.yaml'
|
||||
|
@ -10,14 +10,9 @@ variables:
|
|||
# schema changes
|
||||
- 'pipeline/schema/**'
|
||||
event: pull_request
|
||||
- event: push
|
||||
branch: renovate/*
|
||||
path: *when_path
|
||||
|
||||
when:
|
||||
- event: pull_request
|
||||
- event: push
|
||||
branch: renovate/*
|
||||
- event: push
|
||||
branch: ${CI_REPO_DEFAULT_BRANCH}
|
||||
path: *when_path
|
||||
|
@ -37,9 +32,11 @@ steps:
|
|||
- vendor
|
||||
image: *golang_image
|
||||
commands:
|
||||
- go run go.woodpecker-ci.org/woodpecker/v2/cmd/cli lint
|
||||
- go run go.woodpecker-ci.org/woodpecker/v3/cmd/cli lint
|
||||
environment:
|
||||
WOODPECKER_DISABLE_UPDATE_CHECK: true
|
||||
WOODPECKER_LINT_STRICT: true
|
||||
WOODPECKER_PLUGINS_PRIVILEGED: 'docker.io/woodpeckerci/plugin-docker-buildx'
|
||||
when:
|
||||
- event: pull_request
|
||||
path:
|
||||
|
@ -61,14 +58,14 @@ steps:
|
|||
- make lint
|
||||
when: *when
|
||||
|
||||
check-swagger:
|
||||
check-openapi:
|
||||
depends_on:
|
||||
- vendor
|
||||
image: *golang_image
|
||||
commands:
|
||||
- 'make generate-swagger'
|
||||
- 'make generate-openapi'
|
||||
- 'DIFF=$(git diff | head)'
|
||||
- '[ -n "$DIFF" ] && { echo "swagger not up to date, exec `make generate-swagger` and commit"; exit 1; } || true'
|
||||
- '[ -n "$DIFF" ] && { echo "openapi not up to date, exec `make generate-openapi` and commit"; exit 1; } || true'
|
||||
when: *when
|
||||
|
||||
lint-license-header:
|
||||
|
@ -128,7 +125,7 @@ steps:
|
|||
- test
|
||||
- sqlite
|
||||
pull: true
|
||||
image: docker.io/woodpeckerci/plugin-codecov:2.1.2
|
||||
image: docker.io/woodpeckerci/plugin-codecov:2.1.6
|
||||
settings:
|
||||
files:
|
||||
- agent-coverage.out
|
||||
|
@ -144,7 +141,7 @@ steps:
|
|||
|
||||
services:
|
||||
postgres:
|
||||
image: docker.io/postgres:16
|
||||
image: docker.io/postgres:17
|
||||
ports: ['5432']
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
|
@ -152,7 +149,7 @@ services:
|
|||
when: *when
|
||||
|
||||
mysql:
|
||||
image: docker.io/mysql:8.2.0
|
||||
image: docker.io/mysql:9.1.0
|
||||
ports: ['3306']
|
||||
environment:
|
||||
MYSQL_DATABASE: test
|
||||
|
|
|
@ -3,10 +3,9 @@ when:
|
|||
- event: push
|
||||
branch:
|
||||
- release/*
|
||||
- renovate/*
|
||||
|
||||
variables:
|
||||
- &node_image 'docker.io/node:22-alpine'
|
||||
- &node_image 'docker.io/node:23-alpine'
|
||||
- &when
|
||||
path:
|
||||
# related config files
|
||||
|
@ -25,6 +24,18 @@ steps:
|
|||
- pnpm install --frozen-lockfile
|
||||
when: *when
|
||||
|
||||
prettier:
|
||||
depends_on:
|
||||
- install-dependencies
|
||||
image: docker.io/woodpeckerci/plugin-prettier:next
|
||||
pull: true
|
||||
settings:
|
||||
version: 3.3.3
|
||||
plugins:
|
||||
- 'prettier-plugin-tailwindcss'
|
||||
- '@ianvs/prettier-plugin-sort-imports'
|
||||
when: *when
|
||||
|
||||
lint:
|
||||
depends_on:
|
||||
- install-dependencies
|
||||
|
@ -58,6 +69,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:
|
||||
|
|
|
@ -6,6 +6,7 @@ ignore-from-file:
|
|||
- .gitignore
|
||||
- server/store/datastore/migration/test-files/.gitignore
|
||||
- web/.gitignore
|
||||
- web/.yamlignore
|
||||
|
||||
rules:
|
||||
line-length: disable
|
||||
|
|
485
CHANGELOG.md
485
CHANGELOG.md
|
@ -1,5 +1,490 @@
|
|||
# Changelog
|
||||
|
||||
## [3.0.0](https://github.com/woodpecker-ci/woodpecker/releases/tag/v3.0.0) - 2024-12-13
|
||||
|
||||
### ❤️ Thanks to all contributors! ❤️
|
||||
|
||||
@6543, @Fishbowler, @M0Rf30, @anbraten, @cduchenoy, @fernandrone, @gnowland, @greenaar, @hg, @j04n-f, @jenrik, @johanneskastl, @jolheiser, @lafriks, @lukashass, @meln5674, @not-my-profile, @pat-s, @qwerty287, @smainz, @tori-27, @tsufeki, @xoxys, @xtexChooser, @zc-devs
|
||||
|
||||
### 💥 Breaking changes
|
||||
|
||||
- Drop native Let's Encrypt support [[#4541](https://github.com/woodpecker-ci/woodpecker/pull/4541)]
|
||||
- Set new default approval mode based on repo visibility [[#4456](https://github.com/woodpecker-ci/woodpecker/pull/4456)]
|
||||
- Do not set empty environment variables [[#4193](https://github.com/woodpecker-ci/woodpecker/pull/4193)]
|
||||
- Unify cli commands and flags [[#4481](https://github.com/woodpecker-ci/woodpecker/pull/4481)]
|
||||
- Move pipeline logs command [[#4480](https://github.com/woodpecker-ci/woodpecker/pull/4480)]
|
||||
- Fix woodpecker-go repo model to match server [[#4479](https://github.com/woodpecker-ci/woodpecker/pull/4479)]
|
||||
- Restructure cli commands [[#4467](https://github.com/woodpecker-ci/woodpecker/pull/4467)]
|
||||
- Add pagination options to all supported endpoints in sdk [[#4463](https://github.com/woodpecker-ci/woodpecker/pull/4463)]
|
||||
- Allow to set custom trusted clone plugins [[#4352](https://github.com/woodpecker-ci/woodpecker/pull/4352)]
|
||||
- Add PipelineListsOptions to woodpecker-go [[#3652](https://github.com/woodpecker-ci/woodpecker/pull/3652)]
|
||||
- Remove `secrets` in favor of `from_secret` [[#4363](https://github.com/woodpecker-ci/woodpecker/pull/4363)]
|
||||
- Kubernetes | Docker: Add support for rootless images [[#4151](https://github.com/woodpecker-ci/woodpecker/pull/4151)]
|
||||
- Split repo trusted setting [[#4025](https://github.com/woodpecker-ci/woodpecker/pull/4025)]
|
||||
- Move docker resource limit settings from server to agent [[#3174](https://github.com/woodpecker-ci/woodpecker/pull/3174)]
|
||||
- Set `/woodpecker` as default workdir for the **woodpecker-cli** container [[#4130](https://github.com/woodpecker-ci/woodpecker/pull/4130)]
|
||||
- Require upgrade from 2.x [[#4112](https://github.com/woodpecker-ci/woodpecker/pull/4112)]
|
||||
- Don't expose task data via api [[#4108](https://github.com/woodpecker-ci/woodpecker/pull/4108)]
|
||||
- Remove some ci environment variables [[#3846](https://github.com/woodpecker-ci/woodpecker/pull/3846)]
|
||||
- Remove all default privileged plugins [[#4053](https://github.com/woodpecker-ci/woodpecker/pull/4053)]
|
||||
- Add option to filter secrets by plugins with specific tags [[#4069](https://github.com/woodpecker-ci/woodpecker/pull/4069)]
|
||||
- Remove old pipeline options [[#4016](https://github.com/woodpecker-ci/woodpecker/pull/4016)]
|
||||
- Remove various deprecations [[#4017](https://github.com/woodpecker-ci/woodpecker/pull/4017)]
|
||||
- Drop repo name fallback for hooks [[#4013](https://github.com/woodpecker-ci/woodpecker/pull/4013)]
|
||||
- Improve local backend detection [[#4006](https://github.com/woodpecker-ci/woodpecker/pull/4006)]
|
||||
- Refactor JSON and SDK fields [[#3968](https://github.com/woodpecker-ci/woodpecker/pull/3968)]
|
||||
- Migrate to maintained cron lib and remove seconds [[#3785](https://github.com/woodpecker-ci/woodpecker/pull/3785)]
|
||||
- Switch to profile-based AppArmor configuration [[#4008](https://github.com/woodpecker-ci/woodpecker/pull/4008)]
|
||||
- Remove Kubernetes default image pull secret name `regcred` [[#4005](https://github.com/woodpecker-ci/woodpecker/pull/4005)]
|
||||
- Drop "WOODPECKER_WEBHOOK_HOST" env var and adjust docs [[#3969](https://github.com/woodpecker-ci/woodpecker/pull/3969)]
|
||||
- Drop version in schema [[#3970](https://github.com/woodpecker-ci/woodpecker/pull/3970)]
|
||||
- Update docker to v27 [[#3972](https://github.com/woodpecker-ci/woodpecker/pull/3972)]
|
||||
- Require gitlab 12.4 [[#3966](https://github.com/woodpecker-ci/woodpecker/pull/3966)]
|
||||
- Migrate to maintained httpsign library [[#3839](https://github.com/woodpecker-ci/woodpecker/pull/3839)]
|
||||
- Remove `WOODPECKER_DEV_OAUTH_HOST` and `WOODPECKER_DEV_GITEA_OAUTH_URL` [[#3961](https://github.com/woodpecker-ci/woodpecker/pull/3961)]
|
||||
- Remove deprecated pipeline keywords: `pipeline:`, `platform:`, `branches:` [[#3916](https://github.com/woodpecker-ci/woodpecker/pull/3916)]
|
||||
- server: remove old unused routes [[#3845](https://github.com/woodpecker-ci/woodpecker/pull/3845)]
|
||||
- CLI: remove step-id and add step-number as option to logs [[#3927](https://github.com/woodpecker-ci/woodpecker/pull/3927)]
|
||||
|
||||
### 🔒 Security
|
||||
|
||||
- Add server config to disable user registered agents [[#4206](https://github.com/woodpecker-ci/woodpecker/pull/4206)]
|
||||
- chore: fix `http-proxy-middleware` CVE [[#4257](https://github.com/woodpecker-ci/woodpecker/pull/4257)]
|
||||
- Allow altering trusted clone plugins and filter them via tag [[#4074](https://github.com/woodpecker-ci/woodpecker/pull/4074)]
|
||||
- Update gitea sdk [[#4012](https://github.com/woodpecker-ci/woodpecker/pull/4012)]
|
||||
- Update Forgejo SDK [[#3948](https://github.com/woodpecker-ci/woodpecker/pull/3948)]
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- Add user as docker backend_option [[#4526](https://github.com/woodpecker-ci/woodpecker/pull/4526)]
|
||||
- Implement org/user agents [[#3539](https://github.com/woodpecker-ci/woodpecker/pull/3539)]
|
||||
- Replay pipeline using `cli exec` by downloading metadata [[#4103](https://github.com/woodpecker-ci/woodpecker/pull/4103)]
|
||||
- Update clone plugin to support sha256 [[#4136](https://github.com/woodpecker-ci/woodpecker/pull/4136)]
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- Fix BB ambiguous commit status key [[#4544](https://github.com/woodpecker-ci/woodpecker/pull/4544)]
|
||||
- fix: addon JSON pointers [[#4508](https://github.com/woodpecker-ci/woodpecker/pull/4508)]
|
||||
- Fix apparmorProfile being ignored when it's the only field [[#4507](https://github.com/woodpecker-ci/woodpecker/pull/4507)]
|
||||
- Sanitize strings in table output [[#4466](https://github.com/woodpecker-ci/woodpecker/pull/4466)]
|
||||
- Cleanup openapi generation [[#4331](https://github.com/woodpecker-ci/woodpecker/pull/4331)]
|
||||
- Support github refresh tokens [[#3811](https://github.com/woodpecker-ci/woodpecker/pull/3811)]
|
||||
- Fix not working overflow on repo list message [[#4420](https://github.com/woodpecker-ci/woodpecker/pull/4420)]
|
||||
- Fix avatar column type [[#4340](https://github.com/woodpecker-ci/woodpecker/pull/4340)]
|
||||
- fix `error="io: read/write on closed pipe"` on k8s backend [[#4281](https://github.com/woodpecker-ci/woodpecker/pull/4281)]
|
||||
- Move update notifier dot into settings button [[#4334](https://github.com/woodpecker-ci/woodpecker/pull/4334)]
|
||||
- gitea: add check if pull_request webhook is missing pull info [[#4305](https://github.com/woodpecker-ci/woodpecker/pull/4305)]
|
||||
- Refresh token before loading branches [[#4284](https://github.com/woodpecker-ci/woodpecker/pull/4284)]
|
||||
- Delete GitLab webhooks with partial URL match [[#4259](https://github.com/woodpecker-ci/woodpecker/pull/4259)]
|
||||
- Increase `WOODPECKER_FORGE_TIMEOUT` to fix config fetching for GitLab [[#4262](https://github.com/woodpecker-ci/woodpecker/pull/4262)]
|
||||
- Ensure cli exec has by default not the same prefix [[#4132](https://github.com/woodpecker-ci/woodpecker/pull/4132)]
|
||||
- Fix repo add loading spinner [[#4135](https://github.com/woodpecker-ci/woodpecker/pull/4135)]
|
||||
- Fix migration registries table [[#4111](https://github.com/woodpecker-ci/woodpecker/pull/4111)]
|
||||
- Wait for tracer to be done before finishing workflow [[#4068](https://github.com/woodpecker-ci/woodpecker/pull/4068)]
|
||||
- Fix schema with detached steps [[#4066](https://github.com/woodpecker-ci/woodpecker/pull/4066)]
|
||||
- Fix schema with commands and entrypoint [[#4065](https://github.com/woodpecker-ci/woodpecker/pull/4065)]
|
||||
- Read long log lines from file storage correctly [[#4048](https://github.com/woodpecker-ci/woodpecker/pull/4048)]
|
||||
- Set refspec for gitlab MR [[#4021](https://github.com/woodpecker-ci/woodpecker/pull/4021)]
|
||||
- Set `CI_PREV_COMMIT_{SOURCE,TARGET}_BRANCH` as mentioned in the documentation [[#4001](https://github.com/woodpecker-ci/woodpecker/pull/4001)]
|
||||
- [Bitbucket Datacenter] Return empty list instead of null [[#4010](https://github.com/woodpecker-ci/woodpecker/pull/4010)]
|
||||
- Fix BB PR pipeline ref [[#3985](https://github.com/woodpecker-ci/woodpecker/pull/3985)]
|
||||
- Change Bitbucket PR hook to point the source branch, commit & ref [[#3965](https://github.com/woodpecker-ci/woodpecker/pull/3965)]
|
||||
- Add updated, merged and declined events to bb webhook activation [[#3963](https://github.com/woodpecker-ci/woodpecker/pull/3963)]
|
||||
- Fix login via navbar [[#3962](https://github.com/woodpecker-ci/woodpecker/pull/3962)]
|
||||
- Truncate creation in list [[#3952](https://github.com/woodpecker-ci/woodpecker/pull/3952)]
|
||||
- Fix panic if forge is unreachable [[#3944](https://github.com/woodpecker-ci/woodpecker/pull/3944)]
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- Show client flags [[#4542](https://github.com/woodpecker-ci/woodpecker/pull/4542)]
|
||||
- chore(deps): update react monorepo to v19 (major) [[#4523](https://github.com/woodpecker-ci/woodpecker/pull/4523)]
|
||||
- chore(deps): update docs npm deps non-major [[#4519](https://github.com/woodpecker-ci/woodpecker/pull/4519)]
|
||||
- chore(deps): lock file maintenance [[#4502](https://github.com/woodpecker-ci/woodpecker/pull/4502)]
|
||||
- chore(deps): lock file maintenance [[#4501](https://github.com/woodpecker-ci/woodpecker/pull/4501)]
|
||||
- chore(deps): update dependency isomorphic-dompurify to v2.18.0 [[#4493](https://github.com/woodpecker-ci/woodpecker/pull/4493)]
|
||||
- fix(deps): update docs npm deps non-major [[#4484](https://github.com/woodpecker-ci/woodpecker/pull/4484)]
|
||||
- Add migration notes for restructured cli commands [[#4476](https://github.com/woodpecker-ci/woodpecker/pull/4476)]
|
||||
- Various fixes for `awesome.md` [[#4448](https://github.com/woodpecker-ci/woodpecker/pull/4448)]
|
||||
- chore(deps): lock file maintenance [[#4453](https://github.com/woodpecker-ci/woodpecker/pull/4453)]
|
||||
- chore(deps): update dependency isomorphic-dompurify to v2.17.0 [[#4449](https://github.com/woodpecker-ci/woodpecker/pull/4449)]
|
||||
- fix(deps): update docs npm deps non-major [[#4441](https://github.com/woodpecker-ci/woodpecker/pull/4441)]
|
||||
- chore(deps): update dependency @docusaurus/tsconfig to v3.6.2 [[#4433](https://github.com/woodpecker-ci/woodpecker/pull/4433)]
|
||||
- chore(deps): lock file maintenance [[#4435](https://github.com/woodpecker-ci/woodpecker/pull/4435)]
|
||||
- Bump minimum nodejs to v20 [[#4417](https://github.com/woodpecker-ci/woodpecker/pull/4417)]
|
||||
- chore(deps): lock file maintenance [[#4402](https://github.com/woodpecker-ci/woodpecker/pull/4402)]
|
||||
- Add microsoft teams plugin [[#4400](https://github.com/woodpecker-ci/woodpecker/pull/4400)]
|
||||
- fix(deps): update docs npm deps non-major [[#4394](https://github.com/woodpecker-ci/woodpecker/pull/4394)]
|
||||
- chore(deps): update dependency @types/node to v22 [[#4395](https://github.com/woodpecker-ci/woodpecker/pull/4395)]
|
||||
- chore(deps): update dependency marked to v15 [[#4396](https://github.com/woodpecker-ci/woodpecker/pull/4396)]
|
||||
- Podman is not (official) supported [[#4367](https://github.com/woodpecker-ci/woodpecker/pull/4367)]
|
||||
- Add EditorConfig-Checker Plugin to docs [[#4371](https://github.com/woodpecker-ci/woodpecker/pull/4371)]
|
||||
- Update netrc option description [[#4342](https://github.com/woodpecker-ci/woodpecker/pull/4342)]
|
||||
- Fix deployment event note [[#4283](https://github.com/woodpecker-ci/woodpecker/pull/4283)]
|
||||
- Improve migration notes [[#4291](https://github.com/woodpecker-ci/woodpecker/pull/4291)]
|
||||
- Add instructions how to build images locally [[#4277](https://github.com/woodpecker-ci/woodpecker/pull/4277)]
|
||||
- chore(deps): update docs npm deps non-major [[#4238](https://github.com/woodpecker-ci/woodpecker/pull/4238)]
|
||||
- Correct spelling [[#4279](https://github.com/woodpecker-ci/woodpecker/pull/4279)]
|
||||
- Add Telegram plugin [[#4229](https://github.com/woodpecker-ci/woodpecker/pull/4229)]
|
||||
- Remove archived plugin [[#4227](https://github.com/woodpecker-ci/woodpecker/pull/4227)]
|
||||
- Use "Woodpecker Authors" as copyright on website [[#4225](https://github.com/woodpecker-ci/woodpecker/pull/4225)]
|
||||
- chore(deps): update dependency cookie to v1 [[#4224](https://github.com/woodpecker-ci/woodpecker/pull/4224)]
|
||||
- fix(deps): update docs npm deps non-major [[#4221](https://github.com/woodpecker-ci/woodpecker/pull/4221)]
|
||||
- Fix errant apostrophe in docker-compose documentation [[#4203](https://github.com/woodpecker-ci/woodpecker/pull/4203)]
|
||||
- chore(deps): lock file maintenance [[#4186](https://github.com/woodpecker-ci/woodpecker/pull/4186)]
|
||||
- chore(deps): update dependency concurrently to v9 [[#4176](https://github.com/woodpecker-ci/woodpecker/pull/4176)]
|
||||
- chore(deps): update docs npm deps non-major [[#4164](https://github.com/woodpecker-ci/woodpecker/pull/4164)]
|
||||
- Update image filter error message [[#4143](https://github.com/woodpecker-ci/woodpecker/pull/4143)]
|
||||
- Docs: reference to built-in docker compose and remove deprecated version from compose examples [[#4123](https://github.com/woodpecker-ci/woodpecker/pull/4123)]
|
||||
- directory key is allowed for services [[#4127](https://github.com/woodpecker-ci/woodpecker/pull/4127)]
|
||||
- [docs] Removes dot prefix from pipeline configuration filenames [[#4105](https://github.com/woodpecker-ci/woodpecker/pull/4105)]
|
||||
- Use kaniko plugin in docs as example [[#4072](https://github.com/woodpecker-ci/woodpecker/pull/4072)]
|
||||
- Add some posts and videos [[#4070](https://github.com/woodpecker-ci/woodpecker/pull/4070)]
|
||||
- Move event type descriptions from Terminology to Workflow Syntax [[#4062](https://github.com/woodpecker-ci/woodpecker/pull/4062)]
|
||||
- Add community posts from discussions [[#4058](https://github.com/woodpecker-ci/woodpecker/pull/4058)]
|
||||
- Add a pull request template with some basic guidelines [[#4055](https://github.com/woodpecker-ci/woodpecker/pull/4055)]
|
||||
- Add examples of CI environment variable values [[#4009](https://github.com/woodpecker-ci/woodpecker/pull/4009)]
|
||||
- Fix inline author warning [[#4040](https://github.com/woodpecker-ci/woodpecker/pull/4040)]
|
||||
- Updated Secrets image filter docs [[#4028](https://github.com/woodpecker-ci/woodpecker/pull/4028)]
|
||||
- Update dependency marked to v14 [[#4036](https://github.com/woodpecker-ci/woodpecker/pull/4036)]
|
||||
- Update docs npm deps non-major [[#4033](https://github.com/woodpecker-ci/woodpecker/pull/4033)]
|
||||
- Overhaul README [[#3995](https://github.com/woodpecker-ci/woodpecker/pull/3995)]
|
||||
- fix(deps): update docs npm deps non-major [[#3990](https://github.com/woodpecker-ci/woodpecker/pull/3990)]
|
||||
- Add spellchecking for docs [[#3787](https://github.com/woodpecker-ci/woodpecker/pull/3787)]
|
||||
|
||||
### 📈 Enhancement
|
||||
|
||||
- Use docusaurus faster [[#4528](https://github.com/woodpecker-ci/woodpecker/pull/4528)]
|
||||
- Use pagination helper to list pipelines in cli [[#4478](https://github.com/woodpecker-ci/woodpecker/pull/4478)]
|
||||
- Some UI improvements [[#4497](https://github.com/woodpecker-ci/woodpecker/pull/4497)]
|
||||
- Add status filter to list pipeline API [[#4494](https://github.com/woodpecker-ci/woodpecker/pull/4494)]
|
||||
- Use JS-native date/time formatting [[#4488](https://github.com/woodpecker-ci/woodpecker/pull/4488)]
|
||||
- Add pipeline purge command to cli [[#4470](https://github.com/woodpecker-ci/woodpecker/pull/4470)]
|
||||
- Add option to limit the resultset returned by paginate helper [[#4475](https://github.com/woodpecker-ci/woodpecker/pull/4475)]
|
||||
- Add filter to list repository pipelines API [[#4416](https://github.com/woodpecker-ci/woodpecker/pull/4416)]
|
||||
- Increase log level when failing to fetch YAML [[#4107](https://github.com/woodpecker-ci/woodpecker/pull/4107)]
|
||||
- Trim space to all config flags that allow to read value from file [[#4468](https://github.com/woodpecker-ci/woodpecker/pull/4468)]
|
||||
- Change default icon size to 20 [[#4458](https://github.com/woodpecker-ci/woodpecker/pull/4458)]
|
||||
- Add visibility icon to repo list [[#4460](https://github.com/woodpecker-ci/woodpecker/pull/4460)]
|
||||
- Unify pipeline status icons [[#4414](https://github.com/woodpecker-ci/woodpecker/pull/4414)]
|
||||
- Improve project settings descriptions [[#4410](https://github.com/woodpecker-ci/woodpecker/pull/4410)]
|
||||
- Add count badge to visualize counters in tab title [[#4419](https://github.com/woodpecker-ci/woodpecker/pull/4419)]
|
||||
- Redesign repo list and include last pipeline [[#4386](https://github.com/woodpecker-ci/woodpecker/pull/4386)]
|
||||
- Use KeyValueEditor for DeployPipelinePopup too [[#4412](https://github.com/woodpecker-ci/woodpecker/pull/4412)]
|
||||
- Use separate routes instead of anchors [[#4285](https://github.com/woodpecker-ci/woodpecker/pull/4285)]
|
||||
- Untangle settings / header slots [[#4403](https://github.com/woodpecker-ci/woodpecker/pull/4403)]
|
||||
- Fix responsiveness of the settings template [[#4383](https://github.com/woodpecker-ci/woodpecker/pull/4383)]
|
||||
- Use squared spinner for active pipelines [[#4379](https://github.com/woodpecker-ci/woodpecker/pull/4379)]
|
||||
- Add server configuration option to add default set of labels for workflows that has no labels specified [[#4326](https://github.com/woodpecker-ci/woodpecker/pull/4326)]
|
||||
- Add `cli lint` option to treat warnings as errors [[#4373](https://github.com/woodpecker-ci/woodpecker/pull/4373)]
|
||||
- Improve error message for wrong secrets / environment config [[#4359](https://github.com/woodpecker-ci/woodpecker/pull/4359)]
|
||||
- Improve linter messages in UI [[#4351](https://github.com/woodpecker-ci/woodpecker/pull/4351)]
|
||||
- Pass settings to services [[#4338](https://github.com/woodpecker-ci/woodpecker/pull/4338)]
|
||||
- Inline model types for migrations [[#4293](https://github.com/woodpecker-ci/woodpecker/pull/4293)]
|
||||
- Add options to control the database connections (open,idle,timeout) [[#4212](https://github.com/woodpecker-ci/woodpecker/pull/4212)]
|
||||
- Move Queue creation behind new func that evaluates queue type [[#4252](https://github.com/woodpecker-ci/woodpecker/pull/4252)]
|
||||
- Add additional error message on swagger v2 to v3 convert [[#4254](https://github.com/woodpecker-ci/woodpecker/pull/4254)]
|
||||
- Deprecate `secrets` [[#4235](https://github.com/woodpecker-ci/woodpecker/pull/4235)]
|
||||
- Agent edit/detail view: change the help url based on the backend [[#4219](https://github.com/woodpecker-ci/woodpecker/pull/4219)]
|
||||
- Use middleware to load org [[#4208](https://github.com/woodpecker-ci/woodpecker/pull/4208)]
|
||||
- Assign workflows to agents with the best label matches [[#4201](https://github.com/woodpecker-ci/woodpecker/pull/4201)]
|
||||
- Report custom labels set by agent admins back [[#4141](https://github.com/woodpecker-ci/woodpecker/pull/4141)]
|
||||
- Highlight invalid entries in manual pipeline trigger [[#4153](https://github.com/woodpecker-ci/woodpecker/pull/4153)]
|
||||
- Print agent labels in debug mode [[#4155](https://github.com/woodpecker-ci/woodpecker/pull/4155)]
|
||||
- Implement registries for Kubernetes backend [[#4092](https://github.com/woodpecker-ci/woodpecker/pull/4092)]
|
||||
- Correct cli exec flags and remove ineffective ones [[#4129](https://github.com/woodpecker-ci/woodpecker/pull/4129)]
|
||||
- Set repo user to repairing user when old user is missing [[#4128](https://github.com/woodpecker-ci/woodpecker/pull/4128)]
|
||||
- Restart tasks on dead agents sooner [[#4114](https://github.com/woodpecker-ci/woodpecker/pull/4114)]
|
||||
- Adjust cli exec metadata structure to equal server metadata [[#4119](https://github.com/woodpecker-ci/woodpecker/pull/4119)]
|
||||
- Allow to restart declined pipelines [[#4109](https://github.com/woodpecker-ci/woodpecker/pull/4109)]
|
||||
- Add indices to repo table [[#4087](https://github.com/woodpecker-ci/woodpecker/pull/4087)]
|
||||
- Add systemd unit files to the RPM/DEB packages [[#3986](https://github.com/woodpecker-ci/woodpecker/pull/3986)]
|
||||
- Duplicate key `workflow_id` in the agent logs [[#4046](https://github.com/woodpecker-ci/woodpecker/pull/4046)]
|
||||
- Improve error on config loading [[#4024](https://github.com/woodpecker-ci/woodpecker/pull/4024)]
|
||||
- Show error if secret name is missing [[#4014](https://github.com/woodpecker-ci/woodpecker/pull/4014)]
|
||||
- Show error returned from API [[#3980](https://github.com/woodpecker-ci/woodpecker/pull/3980)]
|
||||
- Move manual popup to own page [[#3981](https://github.com/woodpecker-ci/woodpecker/pull/3981)]
|
||||
- Fail on InvalidImageName [[#4007](https://github.com/woodpecker-ci/woodpecker/pull/4007)]
|
||||
- Use Bitbucket PR title for pipeline message [[#3984](https://github.com/woodpecker-ci/woodpecker/pull/3984)]
|
||||
- Show logs if step has error [[#3979](https://github.com/woodpecker-ci/woodpecker/pull/3979)]
|
||||
- Refactor docker backend and add more test coverage [[#2700](https://github.com/woodpecker-ci/woodpecker/pull/2700)]
|
||||
- Make cli plugin log purge recognize steps by name [[#3953](https://github.com/woodpecker-ci/woodpecker/pull/3953)]
|
||||
- Pin page size [[#3946](https://github.com/woodpecker-ci/woodpecker/pull/3946)]
|
||||
- Improve cron list [[#3947](https://github.com/woodpecker-ci/woodpecker/pull/3947)]
|
||||
- Add PULLREQUEST_DRONE_PULL_REQUEST drone env [[#3939](https://github.com/woodpecker-ci/woodpecker/pull/3939)]
|
||||
- Make agent gRPC errors distinguishable [[#3936](https://github.com/woodpecker-ci/woodpecker/pull/3936)]
|
||||
|
||||
### 📦️ Dependency
|
||||
|
||||
- fix(deps): update module google.golang.org/grpc to v1.69.0 [[#4563](https://github.com/woodpecker-ci/woodpecker/pull/4563)]
|
||||
- fix(deps): update golang-packages [[#4553](https://github.com/woodpecker-ci/woodpecker/pull/4553)]
|
||||
- Update kin-openapi [[#4560](https://github.com/woodpecker-ci/woodpecker/pull/4560)]
|
||||
- fix(deps): update module golang.org/x/crypto to v0.31.0 [security] [[#4557](https://github.com/woodpecker-ci/woodpecker/pull/4557)]
|
||||
- fix(deps): update golang-packages [[#4546](https://github.com/woodpecker-ci/woodpecker/pull/4546)]
|
||||
- chore(deps): update docker.io/woodpeckerci/plugin-ready-release-go docker tag to v3.1.0 [[#4536](https://github.com/woodpecker-ci/woodpecker/pull/4536)]
|
||||
- chore(deps): update docker.io/curlimages/curl docker tag to v8.11.0 [[#4530](https://github.com/woodpecker-ci/woodpecker/pull/4530)]
|
||||
- fix(deps): update golang-packages [[#4496](https://github.com/woodpecker-ci/woodpecker/pull/4496)]
|
||||
- chore(deps): update docker.io/woodpeckerci/plugin-docker-buildx docker tag to v5.1.0 [[#4524](https://github.com/woodpecker-ci/woodpecker/pull/4524)]
|
||||
- chore(deps): update docker.io/woodpeckerci/plugin-prettier docker tag to v1 [[#4522](https://github.com/woodpecker-ci/woodpecker/pull/4522)]
|
||||
- chore(deps): update docker.io/alpine docker tag to v3.21 [[#4520](https://github.com/woodpecker-ci/woodpecker/pull/4520)]
|
||||
- chore(deps): update dependency vite to v6 [[#4485](https://github.com/woodpecker-ci/woodpecker/pull/4485)]
|
||||
- chore(deps): update docker.io/woodpeckerci/plugin-ready-release-go docker tag to v3 [[#4506](https://github.com/woodpecker-ci/woodpecker/pull/4506)]
|
||||
- chore(deps): update docker.io/woodpeckerci/plugin-surge-preview docker tag to v1.3.3 [[#4495](https://github.com/woodpecker-ci/woodpecker/pull/4495)]
|
||||
- fix(deps): update golang-packages [[#4477](https://github.com/woodpecker-ci/woodpecker/pull/4477)]
|
||||
- fix(deps): update dependency @vueuse/core to v12 [[#4486](https://github.com/woodpecker-ci/woodpecker/pull/4486)]
|
||||
- fix(deps): update module github.com/google/go-github/v66 to v67 [[#4487](https://github.com/woodpecker-ci/woodpecker/pull/4487)]
|
||||
- chore(deps): update woodpeckerci/plugin-release docker tag to v0.2.2 [[#4483](https://github.com/woodpecker-ci/woodpecker/pull/4483)]
|
||||
- chore(deps): update pre-commit hook golangci/golangci-lint to v1.62.2 [[#4482](https://github.com/woodpecker-ci/woodpecker/pull/4482)]
|
||||
- fix(deps): update golang-packages [[#4452](https://github.com/woodpecker-ci/woodpecker/pull/4452)]
|
||||
- fix(deps): update golang-packages [[#4411](https://github.com/woodpecker-ci/woodpecker/pull/4411)]
|
||||
- chore(deps): update pre-commit hook igorshubovych/markdownlint-cli to v0.43.0 [[#4443](https://github.com/woodpecker-ci/woodpecker/pull/4443)]
|
||||
- chore(deps): update postgres docker tag to v17.2 [[#4442](https://github.com/woodpecker-ci/woodpecker/pull/4442)]
|
||||
- chore(deps): update docker.io/woodpeckerci/plugin-trivy docker tag to v1.3.0 [[#4434](https://github.com/woodpecker-ci/woodpecker/pull/4434)]
|
||||
- chore(deps): update web npm deps non-major [[#4432](https://github.com/woodpecker-ci/woodpecker/pull/4432)]
|
||||
- fix(deps): update golang-packages [[#4401](https://github.com/woodpecker-ci/woodpecker/pull/4401)]
|
||||
- chore(deps): update web npm deps non-major [[#4391](https://github.com/woodpecker-ci/woodpecker/pull/4391)]
|
||||
- fix(deps): update dependency @intlify/unplugin-vue-i18n to v6 [[#4397](https://github.com/woodpecker-ci/woodpecker/pull/4397)]
|
||||
- chore(deps): update pre-commit hook golangci/golangci-lint to v1.62.0 [[#4390](https://github.com/woodpecker-ci/woodpecker/pull/4390)]
|
||||
- chore(deps): update postgres docker tag to v17.1 [[#4389](https://github.com/woodpecker-ci/woodpecker/pull/4389)]
|
||||
- chore(deps): update docker.io/techknowlogick/xgo docker tag to go-1.23.x [[#4388](https://github.com/woodpecker-ci/woodpecker/pull/4388)]
|
||||
- chore(config): migrate renovate config [[#4296](https://github.com/woodpecker-ci/woodpecker/pull/4296)]
|
||||
- chore(deps): update docker.io/woodpeckerci/plugin-trivy docker tag to v1.2.0 [[#4289](https://github.com/woodpecker-ci/woodpecker/pull/4289)]
|
||||
- chore(deps): update docker.io/techknowlogick/xgo docker tag to go-1.23.x [[#4282](https://github.com/woodpecker-ci/woodpecker/pull/4282)]
|
||||
- fix(deps): update golang-packages [[#4251](https://github.com/woodpecker-ci/woodpecker/pull/4251)]
|
||||
- fix(deps): update web npm deps non-major [[#4258](https://github.com/woodpecker-ci/woodpecker/pull/4258)]
|
||||
- chore(deps): update web npm deps non-major [[#4250](https://github.com/woodpecker-ci/woodpecker/pull/4250)]
|
||||
- chore(deps): update node.js to v23 [[#4239](https://github.com/woodpecker-ci/woodpecker/pull/4239)]
|
||||
- chore(deps): update web npm deps non-major [[#4237](https://github.com/woodpecker-ci/woodpecker/pull/4237)]
|
||||
- chore(deps): update docker.io/mysql docker tag to v9.1.0 [[#4236](https://github.com/woodpecker-ci/woodpecker/pull/4236)]
|
||||
- fix(deps): update dependency simple-icons to v13.14.0 [[#4226](https://github.com/woodpecker-ci/woodpecker/pull/4226)]
|
||||
- fix(deps): update web npm deps non-major [[#4223](https://github.com/woodpecker-ci/woodpecker/pull/4223)]
|
||||
- fix(deps): update golang-packages [[#4215](https://github.com/woodpecker-ci/woodpecker/pull/4215)]
|
||||
- fix(deps): update golang-packages [[#4210](https://github.com/woodpecker-ci/woodpecker/pull/4210)]
|
||||
- fix(deps): update module github.com/google/go-github/v65 to v66 [[#4205](https://github.com/woodpecker-ci/woodpecker/pull/4205)]
|
||||
- fix(deps): update dependency vue-i18n to v10.0.4 [[#4200](https://github.com/woodpecker-ci/woodpecker/pull/4200)]
|
||||
- chore(deps): update pre-commit hook pre-commit/pre-commit-hooks to v5 [[#4192](https://github.com/woodpecker-ci/woodpecker/pull/4192)]
|
||||
- fix(deps): update dependency simple-icons to v13.13.0 [[#4196](https://github.com/woodpecker-ci/woodpecker/pull/4196)]
|
||||
- chore(deps): update web npm deps non-major [[#4174](https://github.com/woodpecker-ci/woodpecker/pull/4174)]
|
||||
- chore(deps): update docker.io/postgres docker tag to v17 [[#4179](https://github.com/woodpecker-ci/woodpecker/pull/4179)]
|
||||
- fix(deps): update dependency @intlify/unplugin-vue-i18n to v5 [[#4183](https://github.com/woodpecker-ci/woodpecker/pull/4183)]
|
||||
- fix(deps): update dependency @vueuse/core to v11 [[#4184](https://github.com/woodpecker-ci/woodpecker/pull/4184)]
|
||||
- chore(deps): update docker.io/woodpeckerci/plugin-codecov docker tag to v2.1.5 [[#4167](https://github.com/woodpecker-ci/woodpecker/pull/4167)]
|
||||
- fix(deps): update module github.com/google/go-github/v64 to v65 [[#4185](https://github.com/woodpecker-ci/woodpecker/pull/4185)]
|
||||
- chore(deps): update docker.io/mysql docker tag to v9 [[#4178](https://github.com/woodpecker-ci/woodpecker/pull/4178)]
|
||||
- chore(deps): update docker.io/alpine docker tag to v3.20 [[#4169](https://github.com/woodpecker-ci/woodpecker/pull/4169)]
|
||||
- fix(deps): update github.com/urfave/cli/v3 digest to 20ef97b [[#4166](https://github.com/woodpecker-ci/woodpecker/pull/4166)]
|
||||
- chore(deps): update docker.io/woodpeckerci/plugin-surge-preview docker tag to v1.3.2 [[#4168](https://github.com/woodpecker-ci/woodpecker/pull/4168)]
|
||||
- chore(deps): update woodpeckerci/plugin-release docker tag to v0.2.1 [[#4175](https://github.com/woodpecker-ci/woodpecker/pull/4175)]
|
||||
- chore(deps): update woodpeckerci/plugin-ready-release-go docker tag to v2 [[#4182](https://github.com/woodpecker-ci/woodpecker/pull/4182)]
|
||||
- fix(deps): update github.com/muesli/termenv digest to 82936c5 [[#4165](https://github.com/woodpecker-ci/woodpecker/pull/4165)]
|
||||
- chore(deps): update postgres docker tag to v17 [[#4181](https://github.com/woodpecker-ci/woodpecker/pull/4181)]
|
||||
- chore(deps): update pre-commit non-major [[#4173](https://github.com/woodpecker-ci/woodpecker/pull/4173)]
|
||||
- chore(deps): update docker.io/golang docker tag to v1.23 [[#4170](https://github.com/woodpecker-ci/woodpecker/pull/4170)]
|
||||
- chore(deps): update node.js to v22 [[#4180](https://github.com/woodpecker-ci/woodpecker/pull/4180)]
|
||||
- fix(deps): update golang-packages [[#4161](https://github.com/woodpecker-ci/woodpecker/pull/4161)]
|
||||
- chore(deps): update dependency @antfu/eslint-config to v3 [[#4095](https://github.com/woodpecker-ci/woodpecker/pull/4095)]
|
||||
- chore(deps): update dependency jsdom to v25 [[#4094](https://github.com/woodpecker-ci/woodpecker/pull/4094)]
|
||||
- chore(deps): update docker.io/golang docker tag to v1.23 [[#4081](https://github.com/woodpecker-ci/woodpecker/pull/4081)]
|
||||
- chore(deps): update docker.io/woodpeckerci/plugin-prettier docker tag to v0.2.0 [[#4082](https://github.com/woodpecker-ci/woodpecker/pull/4082)]
|
||||
- fix(deps): update module github.com/google/go-github/v63 to v64 [[#4073](https://github.com/woodpecker-ci/woodpecker/pull/4073)]
|
||||
- fix(deps): update golang-packages [[#4059](https://github.com/woodpecker-ci/woodpecker/pull/4059)]
|
||||
- Update github.com/urfave/cli/v3 digest to fc07a8c [[#4043](https://github.com/woodpecker-ci/woodpecker/pull/4043)]
|
||||
- Update woodpeckerci/plugin-git Docker tag to v2.5.2 [[#4041](https://github.com/woodpecker-ci/woodpecker/pull/4041)]
|
||||
- Update web npm deps non-major [[#4034](https://github.com/woodpecker-ci/woodpecker/pull/4034)]
|
||||
- Update dependency simple-icons to v13 [[#4037](https://github.com/woodpecker-ci/woodpecker/pull/4037)]
|
||||
- chore(deps): lock file maintenance [[#3991](https://github.com/woodpecker-ci/woodpecker/pull/3991)]
|
||||
- fix(deps): update golang-packages [[#3958](https://github.com/woodpecker-ci/woodpecker/pull/3958)]
|
||||
|
||||
### Misc
|
||||
|
||||
- Move link checks into cron-curated issue dashboard [[#4515](https://github.com/woodpecker-ci/woodpecker/pull/4515)]
|
||||
- Add settings title action [[#4499](https://github.com/woodpecker-ci/woodpecker/pull/4499)]
|
||||
- Use same default sort for repo and org repo list [[#4461](https://github.com/woodpecker-ci/woodpecker/pull/4461)]
|
||||
- Add dns config option to official feature set [[#4418](https://github.com/woodpecker-ci/woodpecker/pull/4418)]
|
||||
- Remove `renovate` branch triggers [[#4437](https://github.com/woodpecker-ci/woodpecker/pull/4437)]
|
||||
- Improve tab layout and add hover effect [[#4431](https://github.com/woodpecker-ci/woodpecker/pull/4431)]
|
||||
- Dont run pipeline on push events to renovate branches [[#4406](https://github.com/woodpecker-ci/woodpecker/pull/4406)]
|
||||
- Harden and correct fifo task queue tests [[#4377](https://github.com/woodpecker-ci/woodpecker/pull/4377)]
|
||||
- Kubernetes documentation enhancements [[#4374](https://github.com/woodpecker-ci/woodpecker/pull/4374)]
|
||||
- Use release-helper for release/* branches [[#4301](https://github.com/woodpecker-ci/woodpecker/pull/4301)]
|
||||
- Fix wording for privileged plugins linter error [[#4280](https://github.com/woodpecker-ci/woodpecker/pull/4280)]
|
||||
- Fix renovate support for `xgo` [[#4276](https://github.com/woodpecker-ci/woodpecker/pull/4276)]
|
||||
- Improve nix development environment [[#4256](https://github.com/woodpecker-ci/woodpecker/pull/4256)]
|
||||
- [pre-commit.ci] pre-commit autoupdate [[#4209](https://github.com/woodpecker-ci/woodpecker/pull/4209)]
|
||||
- Add `.lycheeignore` [[#4154](https://github.com/woodpecker-ci/woodpecker/pull/4154)]
|
||||
- Add eslint-plugin-promise back [[#4022](https://github.com/woodpecker-ci/woodpecker/pull/4022)]
|
||||
- Improve wording [[#3951](https://github.com/woodpecker-ci/woodpecker/pull/3951)]
|
||||
- Fix typos and optimize wording [[#3940](https://github.com/woodpecker-ci/woodpecker/pull/3940)]
|
||||
|
||||
## [2.7.2](https://github.com/woodpecker-ci/woodpecker/releases/tag/v2.7.2) - 2024-11-03
|
||||
|
||||
### Important
|
||||
|
||||
To secure your instance, set `WOODPECKER_PLUGINS_PRIVILEGED` to only allow specific versions of the `woodpeckerci/plugin-docker-buildx` plugin, use version 5.0.0 or above. This prevents older, potentially unstable versions from being privileged.
|
||||
|
||||
For example, to allow only version 5.0.0, use:
|
||||
|
||||
```bash
|
||||
WOODPECKER_PLUGINS_PRIVILEGED=woodpeckerci/plugin-docker-buildx:5.0.0
|
||||
```
|
||||
|
||||
To allow multiple versions, you can separate them with commas:
|
||||
|
||||
```bash
|
||||
WOODPECKER_PLUGINS_PRIVILEGED=woodpeckerci/plugin-docker-buildx:5.0.0,woodpeckerci/plugin-docker-buildx:5.1.0
|
||||
```
|
||||
|
||||
This setup ensures only specified, stable plugin versions are given privileged access.
|
||||
|
||||
Read more about it in [#4213](https://github.com/woodpecker-ci/woodpecker/pull/4213)
|
||||
|
||||
### ❤️ Thanks to all contributors! ❤️
|
||||
|
||||
@6543, @anbraten, @j04n-f, @pat-s, @qwerty287
|
||||
|
||||
### 🔒 Security
|
||||
|
||||
- Chore(deps): update dependency vite to v5.4.6 [security] ([#4163](https://github.com/woodpecker-ci/woodpecker/pull/4163)) [[#4187](https://github.com/woodpecker-ci/woodpecker/pull/4187)]
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- Don't parse forge config files multiple times if no error occured ([#4272](https://github.com/woodpecker-ci/woodpecker/pull/4272)) [[#4273](https://github.com/woodpecker-ci/woodpecker/pull/4273)]
|
||||
- Fix repo/owner parsing for gitlab ([#4255](https://github.com/woodpecker-ci/woodpecker/pull/4255)) [[#4261](https://github.com/woodpecker-ci/woodpecker/pull/4261)]
|
||||
- Run queue.process() in background [[#4115](https://github.com/woodpecker-ci/woodpecker/pull/4115)]
|
||||
- Only update agent.LastWork if not done recently ([#4031](https://github.com/woodpecker-ci/woodpecker/pull/4031)) [[#4100](https://github.com/woodpecker-ci/woodpecker/pull/4100)]
|
||||
|
||||
### Misc
|
||||
|
||||
- Backport JS dependency updates [[#4189](https://github.com/woodpecker-ci/woodpecker/pull/4189)]
|
||||
|
||||
## [2.7.1](https://github.com/woodpecker-ci/woodpecker/releases/tag/v2.7.1) - 2024-09-07
|
||||
|
||||
### ❤️ Thanks to all contributors! ❤️
|
||||
|
||||
@6543, @anbraten, @j04n-f, @qwerty287
|
||||
|
||||
### 🔒 Security
|
||||
|
||||
- Lint privileged plugin match and allow to be set empty [[#4084](https://github.com/woodpecker-ci/woodpecker/pull/4084)]
|
||||
- Allow admins to specify privileged plugins by name **and tag** [[#4076](https://github.com/woodpecker-ci/woodpecker/pull/4076)]
|
||||
- Warn if using secrets/env with plugin [[#4039](https://github.com/woodpecker-ci/woodpecker/pull/4039)]
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- Set refspec for gitlab MR [[#4021](https://github.com/woodpecker-ci/woodpecker/pull/4021)]
|
||||
- Change Bitbucket PR hook to point the source branch, commit & ref [[#3965](https://github.com/woodpecker-ci/woodpecker/pull/3965)]
|
||||
- Add updated, merged and declined events to bb webhook activation [[#3963](https://github.com/woodpecker-ci/woodpecker/pull/3963)]
|
||||
- Fix login via navbar [[#3962](https://github.com/woodpecker-ci/woodpecker/pull/3962)]
|
||||
- Fix panic if forge is unreachable [[#3944](https://github.com/woodpecker-ci/woodpecker/pull/3944)]
|
||||
- Fix org settings page [[#4093](https://github.com/woodpecker-ci/woodpecker/pull/4093)]
|
||||
|
||||
### Misc
|
||||
|
||||
- Bump github.com/docker/docker from v24.0.9 to v24.0.9+30 [[#4077](https://github.com/woodpecker-ci/woodpecker/pull/4077)]
|
||||
|
||||
## [2.7.0](https://github.com/woodpecker-ci/woodpecker/releases/tag/v2.7.0) - 2024-07-18
|
||||
|
||||
### ❤️ Thanks to all contributors! ❤️
|
||||
|
||||
@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)]
|
||||
- Enhance pipeline list [[#3898](https://github.com/woodpecker-ci/woodpecker/pull/3898)]
|
||||
- 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! ❤️
|
||||
|
|
101
Makefile
101
Makefile
|
@ -30,7 +30,7 @@ else
|
|||
endif
|
||||
|
||||
TAGS ?=
|
||||
LDFLAGS := -X go.woodpecker-ci.org/woodpecker/v2/version.Version=${VERSION}
|
||||
LDFLAGS := -X go.woodpecker-ci.org/woodpecker/v3/version.Version=${VERSION}
|
||||
STATIC_BUILD ?= true
|
||||
ifeq ($(STATIC_BUILD),true)
|
||||
LDFLAGS := -s -w -extldflags "-static" $(LDFLAGS)
|
||||
|
@ -39,7 +39,8 @@ CGO_ENABLED ?= 1 # only used to compile server
|
|||
|
||||
HAS_GO = $(shell hash go > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
|
||||
ifeq ($(HAS_GO),GO)
|
||||
XGO_VERSION ?= go-1.20.x
|
||||
# renovate: datasource=docker depName=docker.io/techknowlogick/xgo
|
||||
XGO_VERSION ?= go-1.23.x
|
||||
CGO_CFLAGS ?= $(shell go env CGO_CFLAGS)
|
||||
endif
|
||||
CGO_CFLAGS ?=
|
||||
|
@ -108,15 +109,15 @@ clean: ## Clean build artifacts
|
|||
clean-all: clean ## Clean all artifacts
|
||||
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
|
||||
rm -rf docs/docs/40-cli.md docs/openapi.json
|
||||
|
||||
.PHONY: generate
|
||||
generate: install-tools generate-swagger ## Run all code generations
|
||||
generate: install-tools generate-openapi ## Run all code generations
|
||||
CGO_ENABLED=0 go generate ./...
|
||||
|
||||
generate-swagger: install-tools ## Run swagger code generation
|
||||
swag init -g server/api/ -g cmd/server/swagger.go --outputTypes go -output cmd/server/docs
|
||||
CGO_ENABLED=0 go generate cmd/server/swagger.go
|
||||
generate-openapi: install-tools ## Run openapi code generation and format it
|
||||
go run github.com/swaggo/swag/cmd/swag fmt
|
||||
CGO_ENABLED=0 go generate cmd/server/openapi.go
|
||||
|
||||
generate-license-header: install-tools
|
||||
addlicense -c "Woodpecker Authors" -ignore "vendor/**" **/*.go
|
||||
|
@ -133,9 +134,6 @@ install-tools: ## Install development tools
|
|||
hash gofumpt > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
go install mvdan.cc/gofumpt@latest; \
|
||||
fi ; \
|
||||
hash swag > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
go install github.com/swaggo/swag/cmd/swag@latest; \
|
||||
fi ; \
|
||||
hash addlicense > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
go install github.com/google/addlicense@latest; \
|
||||
fi ; \
|
||||
|
@ -163,20 +161,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 60s -tags 'test $(TAGS)' 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/v3/cmd/agent go.woodpecker-ci.org/woodpecker/v3/agent/...
|
||||
|
||||
test-server: ## Test server code
|
||||
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')
|
||||
go test -race -cover -coverprofile server-coverage.out -timeout 60s -tags 'test $(TAGS)' go.woodpecker-ci.org/woodpecker/v3/cmd/server $(shell go list go.woodpecker-ci.org/woodpecker/v3/server/... | grep -v '/store')
|
||||
|
||||
test-cli: ## Test cli code
|
||||
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/...
|
||||
go test -race -cover -coverprofile cli-coverage.out -timeout 60s -tags 'test $(TAGS)' go.woodpecker-ci.org/woodpecker/v3/cmd/cli go.woodpecker-ci.org/woodpecker/v3/cli/...
|
||||
|
||||
test-server-datastore: ## Test server datastore
|
||||
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/...
|
||||
go test -timeout 300s -tags 'test $(TAGS)' -run TestMigrate go.woodpecker-ci.org/woodpecker/v3/server/store/...
|
||||
go test -race -timeout 100s -tags 'test $(TAGS)' -skip TestMigrate go.woodpecker-ci.org/woodpecker/v3/server/store/...
|
||||
|
||||
test-server-datastore-coverage: ## Test server datastore with coverage report
|
||||
go test -race -cover -coverprofile datastore-coverage.out -timeout 300s -tags 'test $(TAGS)' 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/v3/server/store/...
|
||||
|
||||
test-ui: ui-dependencies ## Test UI code
|
||||
(cd web/; pnpm run lint)
|
||||
|
@ -195,14 +193,14 @@ test: test-agent test-server test-server-datastore test-cli test-lib ## Run all
|
|||
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 -tags '$(TAGS)' -ldflags '${LDFLAGS}' -o ${DIST_DIR}/woodpecker-server${BIN_SUFFIX} go.woodpecker-ci.org/woodpecker/v2/cmd/server
|
||||
build-server: build-ui generate-openapi ## Build 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/v3/cmd/server
|
||||
|
||||
build-agent: ## Build 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
|
||||
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/v3/cmd/agent
|
||||
|
||||
build-cli: ## Build 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
|
||||
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/v3/cmd/cli
|
||||
|
||||
build-tarball: ## Build tar archive
|
||||
mkdir -p ${DIST_DIR} && tar chzvf ${DIST_DIR}/woodpecker-src.tar.gz \
|
||||
|
@ -235,54 +233,75 @@ 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)"
|
||||
|
||||
# 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 .
|
||||
@if [ "$${XGO_IN_XGO:-0}" -eq "1" ]; then echo "inside xgo image"; \
|
||||
# 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"; \
|
||||
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
|
||||
@[ "$${TARGZ:-0}" -eq "1" ] && tar -cvzf ${DIST_DIR}/woodpecker-server_$(TARGETOS)_$(TARGETARCH_BUILDX).tar.gz -C ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX) woodpecker-server$(BIN_SUFFIX) || echo "skip creating '${DIST_DIR}/woodpecker-server_$(TARGETOS)_$(TARGETARCH_BUILDX).tar.gz'"
|
||||
# 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
|
||||
|
||||
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_DIR}/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/v3/cmd/server
|
||||
# tar binary files
|
||||
tar -cvzf ${DIST_DIR}/woodpecker-server_$(TARGETOS)_$(TARGETARCH).tar.gz -C ${DIST_DIR}/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_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
|
||||
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/v3/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/v3/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/v3/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/v3/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/v3/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/v3/cmd/agent
|
||||
# tar binary files
|
||||
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_windows_amd64.tar.gz -C ${DIST_DIR}/agent/windows_amd64 woodpecker-agent.exe
|
||||
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_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
|
||||
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o ${DIST_DIR}/cli/linux_amd64/woodpecker-cli go.woodpecker-ci.org/woodpecker/v3/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/v3/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/v3/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/v3/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/v3/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/v3/cmd/cli
|
||||
# tar binary files
|
||||
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_windows_amd64.tar.gz -C ${DIST_DIR}/cli/windows_amd64 woodpecker-cli.exe
|
||||
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
|
||||
|
@ -321,6 +340,6 @@ spellcheck:
|
|||
.PHONY: docs
|
||||
docs: ## Generate docs (currently only for the cli)
|
||||
CGO_ENABLED=0 go generate cmd/cli/app.go
|
||||
CGO_ENABLED=0 go generate cmd/server/swagger.go
|
||||
CGO_ENABLED=0 go generate cmd/server/openapi.go
|
||||
|
||||
endif
|
||||
|
|
65
README.md
65
README.md
|
@ -19,11 +19,11 @@
|
|||
<a href="https://matrix.to/#/#woodpecker:matrix.org" title="Join the Matrix space at https://matrix.to/#/#woodpecker:matrix.org">
|
||||
<img src="https://img.shields.io/matrix/woodpecker:matrix.org?label=matrix" alt="Matrix space">
|
||||
</a>
|
||||
<a href="https://goreportcard.com/report/go.woodpecker-ci.org/woodpecker/v2" title="Go Report Card">
|
||||
<img src="https://goreportcard.com/badge/go.woodpecker-ci.org/woodpecker/v2" alt="Go Report Card">
|
||||
<a href="https://goreportcard.com/report/go.woodpecker-ci.org/woodpecker/v3" title="Go Report Card">
|
||||
<img src="https://goreportcard.com/badge/go.woodpecker-ci.org/woodpecker/v3" alt="Go Report Card">
|
||||
</a>
|
||||
<a href="https://pkg.go.dev/go.woodpecker-ci.org/woodpecker/v2" title="go reference">
|
||||
<img src="https://pkg.go.dev/badge/go.woodpecker-ci.org/woodpecker/v2" alt="go reference">
|
||||
<a href="https://pkg.go.dev/go.woodpecker-ci.org/woodpecker/v3" title="go reference">
|
||||
<img src="https://pkg.go.dev/badge/go.woodpecker-ci.org/woodpecker/v3" alt="go reference">
|
||||
</a>
|
||||
<a href="https://github.com/woodpecker-ci/woodpecker/releases/latest" title="GitHub release">
|
||||
<img src="https://img.shields.io/github/v/release/woodpecker-ci/woodpecker?sort=semver" alt="GitHub release">
|
||||
|
@ -43,55 +43,48 @@
|
|||
</p>
|
||||
<br/>
|
||||
|
||||
Woodpecker is a simple yet powerful CI/CD engine with great extensibility.
|
||||
Woodpecker is a simple, yet powerful CI/CD engine with great extensibility.
|
||||
|
||||
![woodpecker](docs/docs/woodpecker.png)
|
||||
![woodpecker](docs/woodpecker.png)
|
||||
|
||||
## 🫶 Support
|
||||
## Installation & Resources
|
||||
|
||||
Please consider donating and become a backer. 🙏 [[Become a backer](https://opencollective.com/woodpecker-ci#category-CONTRIBUTE)]
|
||||
Woodpecker can be installed in various ways (see the [Installation Instructions](https://woodpecker-ci.org/docs/administration/getting-started)) and runs with SQLite as database by default.
|
||||
It requires around 100 MB of RAM (Server) and 30 MB (Agent) at runtime in idle mode.
|
||||
|
||||
## Support
|
||||
|
||||
You can support the project by becoming a backer on [Open Collective](https://opencollective.com/woodpecker-ci#category-CONTRIBUTE) or via [GitHub Sponsors](https://github.com/sponsors/woodpecker-ci).
|
||||
|
||||
<a href="https://opencollective.com/woodpecker-ci" target="_blank"><img src="https://opencollective.com/woodpecker-ci/backers.svg?width=890" alt="Open Collective backers"></a>
|
||||
|
||||
## 📖 Documentation
|
||||
## Documentation
|
||||
|
||||
<https://woodpecker-ci.org/>
|
||||
Our documentation can be found at <https://woodpecker-ci.org/docs/intro>.
|
||||
|
||||
## ✨ Contribute
|
||||
## Translation
|
||||
|
||||
See [Contributing Guide](https://github.com/woodpecker-ci/.github/blob/main/CONTRIBUTING.md)
|
||||
We have a self-hosted [Weblate](https://weblate.org/en/) instance at [translate.woodpecker-ci.org](https://translate.woodpecker-ci.org).
|
||||
|
||||
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://woodpecker-ci.org/docs/next/development/getting-started#gitpod)
|
||||
An overview of the current translation state is available at <https://translate.woodpecker-ci.org/projects/woodpecker-ci/#languages>.
|
||||
|
||||
## 📣 Translate
|
||||
## Public Woodpecker Instances
|
||||
|
||||
We use an own [Weblate](https://weblate.org/en/) instance at [translate.woodpecker-ci.org](https://translate.woodpecker-ci.org).
|
||||
Woodpecker is used as the main CI/CD engine at [Codeberg](https://codeberg.org), an alternative Git hosting platform with a focus on privacy and free software development.
|
||||
|
||||
<a href="https://translate.woodpecker-ci.org/engage/woodpecker-ci/">
|
||||
<img src="https://translate.woodpecker-ci.org/widgets/woodpecker-ci/-/ui/multi-blue.svg" alt="Translation status" />
|
||||
</a>
|
||||
## Plugins
|
||||
|
||||
## 👋 Who uses Woodpecker?
|
||||
Woodpecker can be extended via plugins.
|
||||
The [plugin overview website](https://woodpecker-ci.org/plugins) helps browsing available plugins.
|
||||
It combines both plugins by the Woodpecker core team and community-maintained ones.
|
||||
|
||||
Woodpecker is used by [itself](https://ci.woodpecker-ci.org/woodpecker/woodpecker-ci/), multiple well-known companies, organizations like [Codeberg](https://codeberg.org), hobbyists and many others.
|
||||
## Star History
|
||||
|
||||
Leave a [comment](https://github.com/woodpecker-ci/woodpecker/discussions/2149) if you're using it as well.
|
||||
|
||||
Also consider using the topic `WoodpeckerCI` in your repository, so others can learn from your config and use the hashtag `#WoodpeckerCI` when talking about the project on social media!
|
||||
|
||||
Here are some places where people mention Woodpecker:
|
||||
|
||||
- [GitHub](https://github.com/topics/WoodpeckerCI)
|
||||
- [Codeberg](https://codeberg.org/explore/repos?q=woodpeckerci&topic=1)
|
||||
- [Twitter](https://twitter.com/search?q=%23WoodpeckerCI&src=typed_query)
|
||||
- [Fediverse](https://mastodon.social/tags/WoodpeckerCI)
|
||||
|
||||
## ✨ Stars over time
|
||||
|
||||
[![Stargazers over time](https://starchart.cc/woodpecker-ci/woodpecker.svg)](https://starchart.cc/woodpecker-ci/woodpecker)
|
||||
[![Star History Chart](https://api.star-history.com/svg?repos=woodpecker-ci/woodpecker&type=Date)](https://star-history.com/#woodpecker-ci/woodpecker&Date)
|
||||
|
||||
## License
|
||||
|
||||
Woodpecker is Apache 2.0 licensed with the source files in this repository having a header indicating which license they are under and what copyrights apply.
|
||||
Woodpecker is Apache 2.0 licensed.
|
||||
The source files have a header indicating which license they are under and what copyrights apply.
|
||||
|
||||
Files under the `docs/` folder are licensed under Creative Commons Attribution-ShareAlike 4.0 International Public License.
|
||||
Everything in `docs/` is licensed under the Creative Commons Attribution-ShareAlike 4.0 International Public License.
|
||||
|
|
|
@ -20,16 +20,10 @@ import (
|
|||
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline"
|
||||
backend "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/log"
|
||||
"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
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline"
|
||||
backend "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/log"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc"
|
||||
)
|
||||
|
||||
func (r *Runner) createLogger(_logger zerolog.Logger, uploads *sync.WaitGroup, workflow *rpc.Workflow) pipeline.Logger {
|
||||
|
@ -38,7 +32,6 @@ func (r *Runner) createLogger(_logger zerolog.Logger, uploads *sync.WaitGroup, w
|
|||
|
||||
logger := _logger.With().
|
||||
Str("image", step.Image).
|
||||
Str("workflow_id", workflow.ID).
|
||||
Logger()
|
||||
|
||||
uploads.Add(1)
|
||||
|
@ -51,7 +44,7 @@ func (r *Runner) createLogger(_logger zerolog.Logger, uploads *sync.WaitGroup, w
|
|||
logger.Debug().Msg("log stream opened")
|
||||
|
||||
logStream := log.NewLineWriter(r.client, step.UUID, secrets...)
|
||||
if err := log.CopyLineByLine(logStream, rc, maxLogLineLength); err != nil {
|
||||
if err := log.CopyLineByLine(logStream, rc, pipeline.MaxLogLineLength); err != nil {
|
||||
logger.Error().Err(err).Msg("copy limited logStream part")
|
||||
}
|
||||
|
||||
|
|
|
@ -20,9 +20,11 @@ import (
|
|||
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc/proto"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/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{
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -17,44 +17,57 @@ package rpc
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/cenkalti/backoff/v5"
|
||||
"github.com/rs/zerolog/log"
|
||||
"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"
|
||||
backend "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/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()
|
||||
}
|
||||
|
||||
func (c *client) newBackOff() backoff.BackOff {
|
||||
b := backoff.NewExponentialBackOff()
|
||||
b.MaxElapsedTime = 0
|
||||
b.MaxInterval = 10 * time.Second //nolint:mnd
|
||||
b.InitialInterval = 10 * time.Millisecond //nolint:mnd
|
||||
return b
|
||||
|
@ -73,13 +86,13 @@ func (c *client) Version(ctx context.Context) (*rpc.Version, error) {
|
|||
}
|
||||
|
||||
// Next returns the next workflow in the queue.
|
||||
func (c *client) Next(ctx context.Context, f rpc.Filter) (*rpc.Workflow, error) {
|
||||
func (c *client) Next(ctx context.Context, filter rpc.Filter) (*rpc.Workflow, error) {
|
||||
var res *proto.NextResponse
|
||||
var err error
|
||||
retry := c.newBackOff()
|
||||
req := new(proto.NextRequest)
|
||||
req.Filter = new(proto.Filter)
|
||||
req.Filter.Labels = f.Labels
|
||||
req.Filter.Labels = filter.Labels
|
||||
for {
|
||||
res, err = c.client.Next(ctx, req)
|
||||
if err == nil {
|
||||
|
@ -90,8 +103,10 @@ func (c *client) Next(ctx context.Context, f rpc.Filter) (*rpc.Workflow, error)
|
|||
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,
|
||||
|
@ -105,10 +120,11 @@ func (c *client) Next(ctx context.Context, f rpc.Filter) (*rpc.Workflow, error)
|
|||
// 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: next(): code: %v", status.Code(err))
|
||||
log.Warn().Err(err).Msgf("grpc error: next(): code: %v", status.Code(err))
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("grpc error: next(): code: %v: %w", status.Code(err), err)
|
||||
log.Error().Err(err).Msgf("grpc error: next(): code: %v", status.Code(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
select {
|
||||
|
@ -143,9 +159,15 @@ func (c *client) Wait(ctx context.Context, workflowID string) (err error) {
|
|||
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,
|
||||
|
@ -153,7 +175,9 @@ func (c *client) Wait(ctx context.Context, workflowID 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
|
||||
}
|
||||
|
||||
|
@ -184,6 +208,14 @@ func (c *client) Init(ctx context.Context, workflowID string, state rpc.Workflow
|
|||
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,
|
||||
|
@ -191,7 +223,9 @@ func (c *client) Init(ctx context.Context, workflowID string, state rpc.Workflow
|
|||
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
|
||||
}
|
||||
|
||||
|
@ -222,6 +256,14 @@ func (c *client) Done(ctx context.Context, workflowID string, state rpc.Workflow
|
|||
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 +271,9 @@ func (c *client) Done(ctx context.Context, workflowID string, state rpc.Workflow
|
|||
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
|
||||
}
|
||||
|
||||
|
@ -256,6 +300,14 @@ func (c *client) Extend(ctx context.Context, workflowID 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 +315,9 @@ func (c *client) Extend(ctx context.Context, workflowID 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
|
||||
}
|
||||
|
||||
|
@ -297,6 +351,14 @@ func (c *client) Update(ctx context.Context, workflowID string, state rpc.StepSt
|
|||
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 +366,9 @@ func (c *client) Update(ctx context.Context, workflowID string, state rpc.StepSt
|
|||
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 +381,82 @@ func (c *client) Update(ctx context.Context, workflowID string, state rpc.StepSt
|
|||
return nil
|
||||
}
|
||||
|
||||
// Log writes the step 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 +464,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
|
||||
}
|
||||
|
||||
|
@ -356,12 +479,15 @@ func (c *client) Log(ctx context.Context, logEntry *rpc.LogEntry) (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *client) RegisterAgent(ctx context.Context, platform, backend, version string, capacity int) (int64, error) {
|
||||
func (c *client) RegisterAgent(ctx context.Context, info rpc.AgentInfo) (int64, error) {
|
||||
req := new(proto.RegisterAgentRequest)
|
||||
req.Platform = platform
|
||||
req.Backend = backend
|
||||
req.Version = version
|
||||
req.Capacity = int32(capacity)
|
||||
req.Info = &proto.AgentInfo{
|
||||
Platform: info.Platform,
|
||||
Backend: info.Backend,
|
||||
Version: info.Version,
|
||||
Capacity: int32(info.Capacity),
|
||||
CustomLabels: info.CustomLabels,
|
||||
}
|
||||
|
||||
res, err := c.client.RegisterAgent(ctx, req)
|
||||
return res.GetAgentId(), err
|
||||
|
@ -383,6 +509,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 +524,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
|
||||
}
|
||||
|
||||
|
|
|
@ -25,10 +25,11 @@ import (
|
|||
"github.com/rs/zerolog/log"
|
||||
"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/utils"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline"
|
||||
backend "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/shared/constant"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/shared/utils"
|
||||
)
|
||||
|
||||
type Runner struct {
|
||||
|
@ -49,7 +50,7 @@ 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)
|
||||
|
@ -118,7 +119,7 @@ func (r *Runner) Run(runnerCtx context.Context) error { //nolint:contextcheck
|
|||
logger.Debug().Msg("pipeline done")
|
||||
return
|
||||
|
||||
case <-time.After(time.Minute):
|
||||
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")
|
||||
|
@ -176,7 +177,11 @@ func (r *Runner) Run(runnerCtx context.Context) error { //nolint:contextcheck
|
|||
Str("error", state.Error).
|
||||
Msg("updating workflow status")
|
||||
|
||||
if err := r.client.Done(runnerCtx, workflow.ID, state); err != nil {
|
||||
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 workflow status complete")
|
||||
|
|
|
@ -23,8 +23,8 @@ import (
|
|||
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc"
|
||||
)
|
||||
|
||||
func (r *Runner) createTracer(ctxMeta context.Context, uploads *sync.WaitGroup, logger zerolog.Logger, workflow *rpc.Workflow) pipeline.TraceFunc {
|
||||
|
@ -74,21 +74,12 @@ func (r *Runner) createTracer(ctxMeta context.Context, uploads *sync.WaitGroup,
|
|||
// TODO: find better way to update this state and move it to pipeline to have the same env in cli-exec
|
||||
state.Pipeline.Step.Environment["CI_MACHINE"] = r.hostname
|
||||
|
||||
state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "success"
|
||||
state.Pipeline.Step.Environment["CI_PIPELINE_STARTED"] = strconv.FormatInt(state.Pipeline.Started, 10)
|
||||
state.Pipeline.Step.Environment["CI_PIPELINE_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
|
||||
state.Pipeline.Step.Environment["CI_STEP_STATUS"] = "success"
|
||||
state.Pipeline.Step.Environment["CI_STEP_STARTED"] = strconv.FormatInt(state.Pipeline.Started, 10)
|
||||
state.Pipeline.Step.Environment["CI_STEP_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
|
||||
state.Pipeline.Step.Environment["CI_SYSTEM_PLATFORM"] = runtime.GOOS + "/" + runtime.GOARCH
|
||||
|
||||
if state.Pipeline.Error != nil {
|
||||
state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "failure"
|
||||
state.Pipeline.Step.Environment["CI_STEP_STATUS"] = "failure"
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,16 +15,22 @@
|
|||
package admin
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/admin/registry"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/admin/loglevel"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/admin/registry"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/admin/secret"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/admin/user"
|
||||
)
|
||||
|
||||
// Command exports the admin command set.
|
||||
var Command = &cli.Command{
|
||||
Name: "admin",
|
||||
Usage: "administer server settings",
|
||||
Subcommands: []*cli.Command{
|
||||
Usage: "manage server settings",
|
||||
Commands: []*cli.Command{
|
||||
loglevel.Command,
|
||||
registry.Command,
|
||||
secret.Command,
|
||||
user.Command,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -15,24 +15,26 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
// Command exports the log-level command used to change the servers log-level.
|
||||
var Command = &cli.Command{
|
||||
Name: "log-level",
|
||||
ArgsUsage: "[level]",
|
||||
Usage: "get the logging level of the server, or set it with [level]",
|
||||
Usage: "retrieve log level from server, or set it with [level]",
|
||||
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
|
||||
}
|
||||
|
@ -57,6 +59,6 @@ func logLevel(c *cli.Context) error {
|
|||
}
|
||||
}
|
||||
|
||||
log.Info().Msgf("logging level: %s", ll.Level)
|
||||
log.Info().Msgf("log level: %s", ll.Level)
|
||||
return nil
|
||||
}
|
|
@ -15,18 +15,18 @@
|
|||
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 global registries",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
registryCreateCmd,
|
||||
registryDeleteCmd,
|
||||
registryUpdateCmd,
|
||||
registryInfoCmd,
|
||||
registryListCmd,
|
||||
registryShowCmd,
|
||||
registryUpdateCmd,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -15,18 +15,19 @@
|
|||
package registry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"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"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var registryCreateCmd = &cli.Command{
|
||||
Name: "add",
|
||||
Usage: "adds a registry",
|
||||
Usage: "add a registry",
|
||||
Action: registryCreate,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
|
@ -45,14 +46,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")
|
||||
)
|
||||
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,13 +15,15 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var registryListCmd = &cli.Command{
|
||||
|
@ -33,15 +35,17 @@ var registryListCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func registryList(c *cli.Context) error {
|
||||
func registryList(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
|
||||
}
|
||||
|
||||
list, err := client.GlobalRegistryList()
|
||||
opt := woodpecker.RegistryListOptions{}
|
||||
|
||||
list, err := client.GlobalRegistryList(opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,9 +15,11 @@
|
|||
package registry
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"context"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
)
|
||||
|
||||
var registryDeleteCmd = &cli.Command{
|
||||
|
@ -33,10 +35,10 @@ var registryDeleteCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func registryDelete(c *cli.Context) error {
|
||||
func registryDelete(ctx context.Context, c *cli.Command) error {
|
||||
hostname := c.String("hostname")
|
||||
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,14 +15,15 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var registryUpdateCmd = &cli.Command{
|
||||
|
@ -47,14 +48,14 @@ 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")
|
||||
)
|
||||
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,19 +15,20 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
)
|
||||
|
||||
var registryInfoCmd = &cli.Command{
|
||||
Name: "info",
|
||||
Usage: "display registry info",
|
||||
Action: registryInfo,
|
||||
var registryShowCmd = &cli.Command{
|
||||
Name: "show",
|
||||
Usage: "show registry information",
|
||||
Action: registryShow,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "hostname",
|
||||
|
@ -38,13 +39,13 @@ var registryInfoCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func registryInfo(c *cli.Context) error {
|
||||
func registryShow(ctx context.Context, c *cli.Command) error {
|
||||
var (
|
||||
hostname = c.String("hostname")
|
||||
format = c.String("format") + "\n"
|
||||
)
|
||||
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright 2021 Woodpecker Authors
|
||||
// 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
|
||||
// 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,21 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package migration
|
||||
package secret
|
||||
|
||||
import (
|
||||
"src.techknowlogick.com/xormigrate"
|
||||
"xorm.io/xorm"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var alterTableReposDropCounter = xormigrate.Migration{
|
||||
ID: "alter-table-drop-counter",
|
||||
MigrateSession: func(sess *xorm.Session) error {
|
||||
return dropTableColumns(sess, "repos", "repo_counter")
|
||||
// Command exports the secret command.
|
||||
var Command = &cli.Command{
|
||||
Name: "secret",
|
||||
Usage: "manage global secrets",
|
||||
Commands: []*cli.Command{
|
||||
secretCreateCmd,
|
||||
secretDeleteCmd,
|
||||
secretListCmd,
|
||||
secretShowCmd,
|
||||
secretUpdateCmd,
|
||||
},
|
||||
}
|
82
cli/admin/secret/secret_add.go
Normal file
82
cli/admin/secret/secret_add.go
Normal file
|
@ -0,0 +1,82 @@
|
|||
// 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 secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var secretCreateCmd = &cli.Command{
|
||||
Name: "add",
|
||||
Usage: "add a secret",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretCreate,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "value",
|
||||
Usage: "secret value",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "event",
|
||||
Usage: "secret limited to these events",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "image",
|
||||
Usage: "secret limited to these images",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func secretCreate(ctx context.Context, c *cli.Command) error {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secret := &woodpecker.Secret{
|
||||
Name: strings.ToLower(c.String("name")),
|
||||
Value: c.String("value"),
|
||||
Images: c.StringSlice("image"),
|
||||
Events: c.StringSlice("event"),
|
||||
}
|
||||
if len(secret.Events) == 0 {
|
||||
secret.Events = defaultSecretEvents
|
||||
}
|
||||
if strings.HasPrefix(secret.Value, "@") {
|
||||
path := strings.TrimPrefix(secret.Value, "@")
|
||||
out, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
secret.Value = string(out)
|
||||
}
|
||||
|
||||
_, err = client.GlobalSecretCreate(secret)
|
||||
return err
|
||||
}
|
||||
|
||||
var defaultSecretEvents = []string{
|
||||
woodpecker.EventPush,
|
||||
woodpecker.EventTag,
|
||||
woodpecker.EventRelease,
|
||||
woodpecker.EventDeploy,
|
||||
}
|
|
@ -15,15 +15,16 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var secretListCmd = &cli.Command{
|
||||
|
@ -32,48 +33,25 @@ var secretListCmd = &cli.Command{
|
|||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretList,
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "global",
|
||||
Usage: "global secret",
|
||||
},
|
||||
common.OrgFlag,
|
||||
common.RepoFlag,
|
||||
common.FormatFlag(tmplSecretList, true),
|
||||
},
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
global, orgID, repoID, err := parseTargetArgs(client, c)
|
||||
opt := woodpecker.SecretListOptions{}
|
||||
|
||||
list, err := client.GlobalSecretList(opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var list []*woodpecker.Secret
|
||||
switch {
|
||||
case global:
|
||||
list, err = client.GlobalSecretList()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case orgID != -1:
|
||||
list, err = client.OrgSecretList(orgID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
list, err = client.SecretList(repoID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
tmpl, err := template.New("_").Funcs(secretFuncMap).Parse(format)
|
||||
if err != nil {
|
||||
return err
|
47
cli/admin/secret/secret_rm.go
Normal file
47
cli/admin/secret/secret_rm.go
Normal file
|
@ -0,0 +1,47 @@
|
|||
// 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 secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
)
|
||||
|
||||
var secretDeleteCmd = &cli.Command{
|
||||
Name: "rm",
|
||||
Usage: "remove a secret",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretDelete,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "secret name",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func secretDelete(ctx context.Context, c *cli.Command) error {
|
||||
secretName := c.String("name")
|
||||
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return client.GlobalSecretDelete(secretName)
|
||||
}
|
76
cli/admin/secret/secret_set.go
Normal file
76
cli/admin/secret/secret_set.go
Normal file
|
@ -0,0 +1,76 @@
|
|||
// 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 secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var secretUpdateCmd = &cli.Command{
|
||||
Name: "update",
|
||||
Usage: "update a secret",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretUpdate,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "secret name",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "value",
|
||||
Usage: "secret value",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "event",
|
||||
Usage: "secret limited to these events",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "image",
|
||||
Usage: "secret limited to these images",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func secretUpdate(ctx context.Context, c *cli.Command) error {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secret := &woodpecker.Secret{
|
||||
Name: strings.ToLower(c.String("name")),
|
||||
Value: c.String("value"),
|
||||
Images: c.StringSlice("image"),
|
||||
Events: c.StringSlice("event"),
|
||||
}
|
||||
if strings.HasPrefix(secret.Value, "@") {
|
||||
path := strings.TrimPrefix(secret.Value, "@")
|
||||
out, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
secret.Value = string(out)
|
||||
}
|
||||
|
||||
_, err = client.GlobalSecretUpdate(secret)
|
||||
return err
|
||||
}
|
68
cli/admin/secret/secret_show.go
Normal file
68
cli/admin/secret/secret_show.go
Normal file
|
@ -0,0 +1,68 @@
|
|||
// 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 secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"os"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
)
|
||||
|
||||
var secretShowCmd = &cli.Command{
|
||||
Name: "show",
|
||||
Usage: "show secret information",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretShow,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "secret name",
|
||||
},
|
||||
common.FormatFlag(tmplSecretList, true),
|
||||
},
|
||||
}
|
||||
|
||||
func secretShow(ctx context.Context, c *cli.Command) error {
|
||||
var (
|
||||
secretName = c.String("name")
|
||||
format = c.String("format") + "\n"
|
||||
)
|
||||
|
||||
if secretName == "" {
|
||||
return fmt.Errorf("secret name is missing")
|
||||
}
|
||||
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secret, err := client.GlobalSecret(secretName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpl, err := template.New("_").Funcs(secretFuncMap).Parse(format)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tmpl.Execute(os.Stdout, secret)
|
||||
}
|
|
@ -15,17 +15,17 @@
|
|||
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{
|
||||
userListCmd,
|
||||
userInfoCmd,
|
||||
Commands: []*cli.Command{
|
||||
userAddCmd,
|
||||
userListCmd,
|
||||
userRemoveCmd,
|
||||
userShowCmd,
|
||||
},
|
||||
}
|
|
@ -15,25 +15,26 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var userAddCmd = &cli.Command{
|
||||
Name: "add",
|
||||
Usage: "adds a user",
|
||||
Usage: "add a user",
|
||||
ArgsUsage: "<username>",
|
||||
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
|
||||
}
|
|
@ -15,13 +15,15 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var userListCmd = &cli.Command{
|
||||
|
@ -32,13 +34,15 @@ 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
|
||||
}
|
||||
|
||||
users, err := client.UserList()
|
||||
opt := woodpecker.UserListOptions{}
|
||||
|
||||
users, err := client.UserList(opt)
|
||||
if err != nil || len(users) == 0 {
|
||||
return err
|
||||
}
|
|
@ -15,11 +15,12 @@
|
|||
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/v3/cli/internal"
|
||||
)
|
||||
|
||||
var userRemoveCmd = &cli.Command{
|
||||
|
@ -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
|
||||
}
|
|
@ -15,26 +15,27 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
)
|
||||
|
||||
var userInfoCmd = &cli.Command{
|
||||
Name: "info",
|
||||
Usage: "show user details",
|
||||
var userShowCmd = &cli.Command{
|
||||
Name: "show",
|
||||
Usage: "show user information",
|
||||
ArgsUsage: "<username>",
|
||||
Action: userInfo,
|
||||
Action: userShow,
|
||||
Flags: []cli.Flag{common.FormatFlag(tmplUserInfo)},
|
||||
}
|
||||
|
||||
func userInfo(c *cli.Context) error {
|
||||
client, err := internal.NewClient(c)
|
||||
func userShow(ctx context.Context, c *cli.Command) error {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
|
@ -15,52 +15,49 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/shared/logger"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/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,
|
||||
},
|
||||
}, logger.GlobalLoggerFlags...)
|
||||
|
||||
|
|
|
@ -6,10 +6,10 @@ 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"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal/config"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/update"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -17,12 +17,12 @@ var (
|
|||
cancelWaitForUpdate context.CancelCauseFunc
|
||||
)
|
||||
|
||||
func Before(c *cli.Context) error {
|
||||
if err := setupGlobalLogger(c); err != nil {
|
||||
return err
|
||||
func Before(ctx context.Context, c *cli.Command) (context.Context, error) {
|
||||
if err := setupGlobalLogger(ctx, c); err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
|
||||
go func() {
|
||||
go func(context.Context) {
|
||||
if c.Bool("disable-update-check") {
|
||||
return
|
||||
}
|
||||
|
@ -35,31 +35,31 @@ func Before(c *cli.Context) error {
|
|||
waitForUpdateCheck, cancelWaitForUpdate = context.WithCancelCause(context.Background())
|
||||
defer cancelWaitForUpdate(errors.New("update check finished"))
|
||||
|
||||
log.Debug().Msg("Checking for updates ...")
|
||||
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")
|
||||
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("new version of woodpecker-cli is available: %s, update with: %s update", newVersion.Version, c.Root().Name)
|
||||
} else {
|
||||
log.Debug().Msgf("No update required")
|
||||
log.Debug().Msgf("no update required")
|
||||
}
|
||||
}()
|
||||
}(ctx)
|
||||
|
||||
return config.Load(c)
|
||||
return ctx, config.Load(ctx, c)
|
||||
}
|
||||
|
||||
func After(_ *cli.Context) error {
|
||||
func After(_ context.Context, _ *cli.Command) error {
|
||||
if waitForUpdateCheck != nil {
|
||||
select {
|
||||
case <-waitForUpdateCheck.Done():
|
||||
// When the actual command already finished, we still wait 500ms for the update check to finish
|
||||
case <-time.After(time.Millisecond * 500):
|
||||
log.Debug().Msg("Update check stopped due to timeout")
|
||||
log.Debug().Msg("update check stopped due to timeout")
|
||||
cancelWaitForUpdate(errors.New("update check timeout"))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,13 +15,14 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/shared/constant"
|
||||
)
|
||||
|
||||
func DetectPipelineConfig() (isDir bool, config string, _ error) {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,11 +15,13 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"context"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/shared/logger"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v3/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)
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
package exec
|
||||
|
||||
import "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/dummy"
|
||||
import "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/dummy"
|
||||
|
||||
func init() { //nolint:gochecknoinits
|
||||
backends = append(backends, dummy.New())
|
||||
|
|
108
cli/exec/exec.go
108
cli/exec/exec.go
|
@ -25,23 +25,26 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/drone/envsubst"
|
||||
"github.com/oklog/ulid/v2"
|
||||
"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"
|
||||
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/utils"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/lint"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/backend"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/docker"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/kubernetes"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/local"
|
||||
backend_types "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/metadata"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml/compiler"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml/linter"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml/matrix"
|
||||
pipelineLog "go.woodpecker-ci.org/woodpecker/v3/pipeline/log"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/shared/constant"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/shared/utils"
|
||||
)
|
||||
|
||||
// Command exports the exec command.
|
||||
|
@ -59,11 +62,11 @@ var backends = []backend_types.Backend{
|
|||
local.New(),
|
||||
}
|
||||
|
||||
func run(c *cli.Context) error {
|
||||
return common.RunPipelineFunc(c, execFile, execDir)
|
||||
func run(ctx context.Context, c *cli.Command) error {
|
||||
return common.RunPipelineFunc(ctx, c, execFile, execDir)
|
||||
}
|
||||
|
||||
func execDir(c *cli.Context, dir string) error {
|
||||
func execDir(ctx context.Context, c *cli.Command, dir string) error {
|
||||
// TODO: respect pipeline dependency
|
||||
repoPath := c.String("repo-path")
|
||||
if repoPath != "" {
|
||||
|
@ -74,6 +77,7 @@ func execDir(c *cli.Context, dir string) error {
|
|||
if runtime.GOOS == "windows" {
|
||||
repoPath = convertPathForWindows(repoPath)
|
||||
}
|
||||
// TODO: respect depends_on and do parallel runs with output to multiple _windows_ e.g. tmux like
|
||||
return filepath.Walk(dir, func(path string, info os.FileInfo, e error) error {
|
||||
if e != nil {
|
||||
return e
|
||||
|
@ -82,7 +86,7 @@ func execDir(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, false) // TODO: should we drop errors or store them and report back?
|
||||
fmt.Println("")
|
||||
return nil
|
||||
}
|
||||
|
@ -91,7 +95,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)
|
||||
|
@ -101,10 +105,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, true)
|
||||
}
|
||||
|
||||
func runExec(c *cli.Context, file, repoPath string) error {
|
||||
func runExec(ctx context.Context, c *cli.Command, file, repoPath string, singleExec bool) error {
|
||||
dat, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -119,7 +123,7 @@ func runExec(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, singleExec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -127,8 +131,20 @@ 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, singleExec bool) error {
|
||||
metadataWorkflow := &metadata.Workflow{}
|
||||
if !singleExec {
|
||||
// TODO: proper try to use the engine to generate the same metadata for workflows
|
||||
// https://github.com/woodpecker-ci/woodpecker/pull/3967
|
||||
metadataWorkflow.Name = strings.TrimSuffix(strings.TrimSuffix(file, ".yaml"), ".yml")
|
||||
}
|
||||
metadata, err := metadataFromContext(ctx, c, axis, metadataWorkflow)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create metadata: %w", err)
|
||||
} else if metadata == nil {
|
||||
return fmt.Errorf("metadata is nil")
|
||||
}
|
||||
|
||||
environ := metadata.Environ()
|
||||
var secrets []compiler.Secret
|
||||
for key, val := range metadata.Workflow.Matrix {
|
||||
|
@ -166,6 +182,9 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
|
|||
return err
|
||||
}
|
||||
|
||||
// emulate server behavior https://github.com/woodpecker-ci/woodpecker/blob/eebaa10d104cbc3fa7ce4c0e344b0b7978405135/server/pipeline/stepbuilder/stepBuilder.go#L289-L295
|
||||
prefix := "wp_" + ulid.Make().String()
|
||||
|
||||
// configure volumes for local execution
|
||||
volumes := c.StringSlice("volumes")
|
||||
if c.Bool("local") {
|
||||
|
@ -180,18 +199,28 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
|
|||
workspacePath = c.String("workspace-path")
|
||||
}
|
||||
|
||||
volumes = append(volumes, c.String("prefix")+"_default:"+workspaceBase)
|
||||
volumes = append(volumes, prefix+"_default:"+workspaceBase)
|
||||
volumes = append(volumes, repoPath+":"+path.Join(workspaceBase, workspacePath))
|
||||
}
|
||||
|
||||
privilegedPlugins := c.StringSlice("plugins-privileged")
|
||||
|
||||
// lint the yaml file
|
||||
err = linter.New(linter.WithTrusted(true)).Lint([]*linter.WorkflowConfig{{
|
||||
err = linter.New(
|
||||
linter.WithTrusted(linter.TrustedConfiguration{
|
||||
Security: c.Bool("repo-trusted-security"),
|
||||
Network: c.Bool("repo-trusted-network"),
|
||||
Volumes: c.Bool("repo-trusted-volumes"),
|
||||
}),
|
||||
linter.PrivilegedPlugins(privilegedPlugins),
|
||||
linter.WithTrustedClonePlugins(constant.TrustedClonePlugins),
|
||||
).Lint([]*linter.WorkflowConfig{{
|
||||
File: path.Base(file),
|
||||
RawConfig: confStr,
|
||||
Workflow: conf,
|
||||
}})
|
||||
if err != nil {
|
||||
str, err := lint.FormatLintError(file, err)
|
||||
str, err := lint.FormatLintError(file, err, false)
|
||||
fmt.Print(str)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -201,7 +230,7 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
|
|||
// compiles the yaml file
|
||||
compiled, err := compiler.New(
|
||||
compiler.WithEscalated(
|
||||
c.StringSlice("privileged")...,
|
||||
privilegedPlugins...,
|
||||
),
|
||||
compiler.WithVolumes(volumes...),
|
||||
compiler.WithWorkspace(
|
||||
|
@ -211,9 +240,7 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
|
|||
compiler.WithNetworks(
|
||||
c.StringSlice("network")...,
|
||||
),
|
||||
compiler.WithPrefix(
|
||||
c.String("prefix"),
|
||||
),
|
||||
compiler.WithPrefix(prefix),
|
||||
compiler.WithProxy(compiler.ProxyOptions{
|
||||
NoProxy: c.String("backend-no-proxy"),
|
||||
HTTPProxy: c.String("backend-http-proxy"),
|
||||
|
@ -227,7 +254,7 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
|
|||
c.String("netrc-password"),
|
||||
c.String("netrc-machine"),
|
||||
),
|
||||
compiler.WithMetadata(metadata),
|
||||
compiler.WithMetadata(*metadata),
|
||||
compiler.WithSecret(secrets...),
|
||||
compiler.WithEnviron(pipelineEnv),
|
||||
).Compile(conf)
|
||||
|
@ -235,7 +262,7 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
|
|||
return err
|
||||
}
|
||||
|
||||
backendCtx := context.WithValue(c.Context, backend_types.CliContext, c)
|
||||
backendCtx := context.WithValue(ctx, backend_types.CliCommand, c)
|
||||
backendEngine, err := backend.FindBackend(backendCtx, backends, c.String("backend-engine"))
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -245,21 +272,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
|
||||
|
@ -281,8 +308,7 @@ func convertPathForWindows(path string) string {
|
|||
return filepath.ToSlash(path)
|
||||
}
|
||||
|
||||
const maxLogLineLength = 1024 * 1024 // 1mb
|
||||
var defaultLogger = pipeline.Logger(func(step *backend_types.Step, rc io.ReadCloser) error {
|
||||
logWriter := NewLineWriter(step.Name, step.UUID)
|
||||
return pipelineLog.CopyLineByLine(logWriter, rc, maxLogLineLength)
|
||||
return pipelineLog.CopyLineByLine(logWriter, rc, pipeline.MaxLogLineLength)
|
||||
})
|
||||
|
|
|
@ -17,53 +17,49 @@ 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.StringFlag{
|
||||
Sources: cli.EnvVars("WOODPECKER_METADATA_FILE"),
|
||||
Name: "metadata-file",
|
||||
Usage: "path to pipeline metadata file (normally downloaded from UI). Parameters can be adjusted by applying additional cli flags",
|
||||
},
|
||||
&cli.DurationFlag{
|
||||
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"},
|
||||
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 +69,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 +93,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 +106,298 @@ 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",
|
||||
Usage: "Set the metadata environment variable \"CI_SYSTEM_PLATFORM\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_SYSTEM_NAME"},
|
||||
Sources: cli.EnvVars("CI_SYSTEM_HOST"),
|
||||
Name: "system-host",
|
||||
Usage: "Set the metadata environment variable \"CI_SYSTEM_HOST\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_SYSTEM_NAME"),
|
||||
Name: "system-name",
|
||||
Usage: "Set the metadata environment variable \"CI_SYSTEM_NAME\".",
|
||||
Value: "woodpecker",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_SYSTEM_URL"},
|
||||
Sources: cli.EnvVars("CI_SYSTEM_URL"),
|
||||
Name: "system-url",
|
||||
Usage: "Set the metadata environment variable \"CI_SYSTEM_URL\".",
|
||||
Value: "https://github.com/woodpecker-ci/woodpecker",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_REPO"},
|
||||
Sources: cli.EnvVars("CI_REPO"),
|
||||
Name: "repo",
|
||||
Usage: "full repo name",
|
||||
Usage: "Set the full name to derive metadata environment variables \"CI_REPO\", \"CI_REPO_NAME\" and \"CI_REPO_OWNER\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_REPO_REMOTE_ID"},
|
||||
Sources: cli.EnvVars("CI_REPO_REMOTE_ID"),
|
||||
Name: "repo-remote-id",
|
||||
Usage: "Set the metadata environment variable \"CI_REPO_REMOTE_ID\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_REPO_URL"},
|
||||
Sources: cli.EnvVars("CI_REPO_URL"),
|
||||
Name: "repo-url",
|
||||
Usage: "Set the metadata environment variable \"CI_REPO_URL\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_REPO_CLONE_URL"},
|
||||
Sources: cli.EnvVars("CI_REPO_DEFAULT_BRANCH"),
|
||||
Name: "repo-default-branch",
|
||||
Usage: "Set the metadata environment variable \"CI_REPO_DEFAULT_BRANCH\".",
|
||||
Value: "main",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_REPO_CLONE_URL"),
|
||||
Name: "repo-clone-url",
|
||||
Usage: "Set the metadata environment variable \"CI_REPO_CLONE_URL\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_REPO_CLONE_SSH_URL"},
|
||||
Sources: cli.EnvVars("CI_REPO_CLONE_SSH_URL"),
|
||||
Name: "repo-clone-ssh-url",
|
||||
Usage: "Set the metadata environment variable \"CI_REPO_CLONE_SSH_URL\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_REPO_PRIVATE"},
|
||||
Sources: cli.EnvVars("CI_REPO_PRIVATE"),
|
||||
Name: "repo-private",
|
||||
Usage: "Set the metadata environment variable \"CI_REPO_PRIVATE\".",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
EnvVars: []string{"CI_REPO_TRUSTED"},
|
||||
Name: "repo-trusted",
|
||||
Sources: cli.EnvVars("CI_REPO_TRUSTED_NETWORK"),
|
||||
Name: "repo-trusted-network",
|
||||
Usage: "Set the metadata environment variable \"CI_REPO_TRUSTED_NETWORK\".",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Sources: cli.EnvVars("CI_REPO_TRUSTED_VOLUMES"),
|
||||
Name: "repo-trusted-volumes",
|
||||
Usage: "Set the metadata environment variable \"CI_REPO_TRUSTED_VOLUMES\".",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Sources: cli.EnvVars("CI_REPO_TRUSTED_SECURITY"),
|
||||
Name: "repo-trusted-security",
|
||||
Usage: "Set the metadata environment variable \"CI_REPO_TRUSTED_SECURITY\".",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
EnvVars: []string{"CI_PIPELINE_NUMBER"},
|
||||
Sources: cli.EnvVars("CI_PIPELINE_NUMBER"),
|
||||
Name: "pipeline-number",
|
||||
Usage: "Set the metadata environment variable \"CI_PIPELINE_NUMBER\".",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
EnvVars: []string{"CI_PIPELINE_PARENT"},
|
||||
Sources: cli.EnvVars("CI_PIPELINE_PARENT"),
|
||||
Name: "pipeline-parent",
|
||||
Usage: "Set the metadata environment variable \"CI_PIPELINE_PARENT\".",
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
EnvVars: []string{"CI_PIPELINE_CREATED"},
|
||||
&cli.IntFlag{
|
||||
Sources: cli.EnvVars("CI_PIPELINE_CREATED"),
|
||||
Name: "pipeline-created",
|
||||
Usage: "Set the metadata environment variable \"CI_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",
|
||||
Usage: "Set the metadata environment variable \"CI_PIPELINE_STARTED\".",
|
||||
},
|
||||
&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",
|
||||
Usage: "Set the metadata environment variable \"CI_PIPELINE_EVENT\".",
|
||||
Value: "manual",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PIPELINE_URL"},
|
||||
Sources: cli.EnvVars("CI_PIPELINE_FORGE_URL"),
|
||||
Name: "pipeline-url",
|
||||
Usage: "Set the metadata environment variable \"CI_PIPELINE_FORGE_URL\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PIPELINE_DEPLOY_TARGET", "CI_PIPELINE_TARGET"}, // TODO: remove CI_PIPELINE_TARGET in 3.x
|
||||
Sources: cli.EnvVars("CI_PIPELINE_DEPLOY_TARGET"),
|
||||
Name: "pipeline-deploy-to",
|
||||
Usage: "Set the metadata environment variable \"CI_PIPELINE_DEPLOY_TARGET\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PIPELINE_DEPLOY_TASK", "CI_PIPELINE_TASK"}, // TODO: remove CI_PIPELINE_TASK in 3.x
|
||||
Sources: cli.EnvVars("CI_PIPELINE_DEPLOY_TASK"),
|
||||
Name: "pipeline-deploy-task",
|
||||
Usage: "Set the metadata environment variable \"CI_PIPELINE_DEPLOY_TASK\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_COMMIT_SHA"},
|
||||
Sources: cli.EnvVars("CI_PIPELINE_FILES"),
|
||||
Usage: "Set the metadata environment variable \"CI_PIPELINE_FILES\", either json formatted list of strings, or comma separated string list.",
|
||||
Name: "pipeline-changed-files",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_COMMIT_SHA"),
|
||||
Name: "commit-sha",
|
||||
Usage: "Set the metadata environment variable \"CI_COMMIT_SHA\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_COMMIT_REF"},
|
||||
Sources: cli.EnvVars("CI_COMMIT_REF"),
|
||||
Name: "commit-ref",
|
||||
Usage: "Set the metadata environment variable \"CI_COMMIT_REF\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_COMMIT_REFSPEC"},
|
||||
Sources: cli.EnvVars("CI_COMMIT_REFSPEC"),
|
||||
Name: "commit-refspec",
|
||||
Usage: "Set the metadata environment variable \"CI_COMMIT_REFSPEC\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_COMMIT_BRANCH"},
|
||||
Sources: cli.EnvVars("CI_COMMIT_BRANCH"),
|
||||
Name: "commit-branch",
|
||||
Usage: "Set the metadata environment variable \"CI_COMMIT_BRANCH\".",
|
||||
Value: "main",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_COMMIT_MESSAGE"},
|
||||
Sources: cli.EnvVars("CI_COMMIT_MESSAGE"),
|
||||
Name: "commit-message",
|
||||
Usage: "Set the metadata environment variable \"CI_COMMIT_MESSAGE\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_COMMIT_AUTHOR_NAME"},
|
||||
Sources: cli.EnvVars("CI_COMMIT_AUTHOR"),
|
||||
Name: "commit-author-name",
|
||||
Usage: "Set the metadata environment variable \"CI_COMMIT_AUTHOR\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_COMMIT_AUTHOR_AVATAR"},
|
||||
Sources: cli.EnvVars("CI_COMMIT_AUTHOR_AVATAR"),
|
||||
Name: "commit-author-avatar",
|
||||
Usage: "Set the metadata environment variable \"CI_COMMIT_AUTHOR_AVATAR\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_COMMIT_AUTHOR_EMAIL"},
|
||||
Sources: cli.EnvVars("CI_COMMIT_AUTHOR_EMAIL"),
|
||||
Name: "commit-author-email",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
EnvVars: []string{"CI_PREV_PIPELINE_NUMBER"},
|
||||
Name: "prev-pipeline-number",
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
EnvVars: []string{"CI_PREV_PIPELINE_CREATED"},
|
||||
Name: "prev-pipeline-created",
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
EnvVars: []string{"CI_PREV_PIPELINE_STARTED"},
|
||||
Name: "prev-pipeline-started",
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
EnvVars: []string{"CI_PREV_PIPELINE_FINISHED"},
|
||||
Name: "prev-pipeline-finished",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PREV_PIPELINE_STATUS"},
|
||||
Name: "prev-pipeline-status",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PREV_PIPELINE_EVENT"},
|
||||
Name: "prev-pipeline-event",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PREV_PIPELINE_URL"},
|
||||
Name: "prev-pipeline-url",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PREV_COMMIT_SHA"},
|
||||
Name: "prev-commit-sha",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PREV_COMMIT_REF"},
|
||||
Name: "prev-commit-ref",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PREV_COMMIT_REFSPEC"},
|
||||
Name: "prev-commit-refspec",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PREV_COMMIT_BRANCH"},
|
||||
Name: "prev-commit-branch",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PREV_COMMIT_MESSAGE"},
|
||||
Name: "prev-commit-message",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PREV_COMMIT_AUTHOR_NAME"},
|
||||
Name: "prev-commit-author-name",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PREV_COMMIT_AUTHOR_AVATAR"},
|
||||
Name: "prev-commit-author-avatar",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PREV_COMMIT_AUTHOR_EMAIL"},
|
||||
Name: "prev-commit-author-email",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
EnvVars: []string{"CI_WORKFLOW_NAME"},
|
||||
Name: "workflow-name",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
EnvVars: []string{"CI_WORKFLOW_NUMBER"},
|
||||
Name: "workflow-number",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
EnvVars: []string{"CI_STEP_NAME"},
|
||||
Name: "step-name",
|
||||
Usage: "Set the metadata environment variable \"CI_COMMIT_AUTHOR_EMAIL\".",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
EnvVars: []string{"CI_ENV"},
|
||||
Sources: cli.EnvVars("CI_COMMIT_PULL_REQUEST_LABELS"),
|
||||
Name: "commit-pull-labels",
|
||||
Usage: "Set the metadata environment variable \"CI_COMMIT_PULL_REQUEST_LABELS\".",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Sources: cli.EnvVars("CI_COMMIT_PRERELEASE"),
|
||||
Name: "commit-release-is-pre",
|
||||
Usage: "Set the metadata environment variable \"CI_COMMIT_PRERELEASE\".",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Sources: cli.EnvVars("CI_PREV_PIPELINE_NUMBER"),
|
||||
Name: "prev-pipeline-number",
|
||||
Usage: "Set the metadata environment variable \"CI_PREV_PIPELINE_NUMBER\".",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Sources: cli.EnvVars("CI_PREV_PIPELINE_CREATED"),
|
||||
Name: "prev-pipeline-created",
|
||||
Usage: "Set the metadata environment variable \"CI_PREV_PIPELINE_CREATED\".",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Sources: cli.EnvVars("CI_PREV_PIPELINE_STARTED"),
|
||||
Name: "prev-pipeline-started",
|
||||
Usage: "Set the metadata environment variable \"CI_PREV_PIPELINE_STARTED\".",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Sources: cli.EnvVars("CI_PREV_PIPELINE_FINISHED"),
|
||||
Name: "prev-pipeline-finished",
|
||||
Usage: "Set the metadata environment variable \"CI_PREV_PIPELINE_FINISHED\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_PREV_PIPELINE_STATUS"),
|
||||
Name: "prev-pipeline-status",
|
||||
Usage: "Set the metadata environment variable \"CI_PREV_PIPELINE_STATUS\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_PREV_PIPELINE_EVENT"),
|
||||
Name: "prev-pipeline-event",
|
||||
Usage: "Set the metadata environment variable \"CI_PREV_PIPELINE_EVENT\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_PREV_PIPELINE_FORGE_URL"),
|
||||
Name: "prev-pipeline-url",
|
||||
Usage: "Set the metadata environment variable \"CI_PREV_PIPELINE_FORGE_URL\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_PREV_PIPELINE_DEPLOY_TARGET"),
|
||||
Name: "prev-pipeline-deploy-to",
|
||||
Usage: "Set the metadata environment variable \"CI_PREV_PIPELINE_DEPLOY_TARGET\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_PREV_PIPELINE_DEPLOY_TASK"),
|
||||
Name: "prev-pipeline-deploy-task",
|
||||
Usage: "Set the metadata environment variable \"CI_PREV_PIPELINE_DEPLOY_TASK\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_PREV_COMMIT_SHA"),
|
||||
Name: "prev-commit-sha",
|
||||
Usage: "Set the metadata environment variable \"CI_PREV_COMMIT_SHA\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_PREV_COMMIT_REF"),
|
||||
Name: "prev-commit-ref",
|
||||
Usage: "Set the metadata environment variable \"CI_PREV_COMMIT_REF\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_PREV_COMMIT_REFSPEC"),
|
||||
Name: "prev-commit-refspec",
|
||||
Usage: "Set the metadata environment variable \"CI_PREV_COMMIT_REFSPEC\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_PREV_COMMIT_BRANCH"),
|
||||
Name: "prev-commit-branch",
|
||||
Usage: "Set the metadata environment variable \"CI_PREV_COMMIT_BRANCH\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_PREV_COMMIT_MESSAGE"),
|
||||
Name: "prev-commit-message",
|
||||
Usage: "Set the metadata environment variable \"CI_PREV_COMMIT_MESSAGE\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_PREV_COMMIT_AUTHOR"),
|
||||
Name: "prev-commit-author-name",
|
||||
Usage: "Set the metadata environment variable \"CI_PREV_COMMIT_AUTHOR\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_PREV_COMMIT_AUTHOR_AVATAR"),
|
||||
Name: "prev-commit-author-avatar",
|
||||
Usage: "Set the metadata environment variable \"CI_PREV_COMMIT_AUTHOR_AVATAR\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_PREV_COMMIT_AUTHOR_EMAIL"),
|
||||
Name: "prev-commit-author-email",
|
||||
Usage: "Set the metadata environment variable \"CI_PREV_COMMIT_AUTHOR_EMAIL\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_WORKFLOW_NAME"),
|
||||
Name: "workflow-name",
|
||||
Usage: "Set the metadata environment variable \"CI_WORKFLOW_NAME\".",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Sources: cli.EnvVars("CI_WORKFLOW_NUMBER"),
|
||||
Name: "workflow-number",
|
||||
Usage: "Set the metadata environment variable \"CI_WORKFLOW_NUMBER\".",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Sources: cli.EnvVars("CI_ENV"),
|
||||
Name: "env",
|
||||
Usage: "Set the metadata environment variable \"CI_ENV\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_FORGE_TYPE"},
|
||||
Sources: cli.EnvVars("CI_FORGE_TYPE"),
|
||||
Name: "forge-type",
|
||||
Usage: "Set the metadata environment variable \"CI_FORGE_TYPE\".",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_FORGE_URL"},
|
||||
Sources: cli.EnvVars("CI_FORGE_URL"),
|
||||
Name: "forge-url",
|
||||
Usage: "Set the metadata environment variable \"CI_FORGE_URL\".",
|
||||
},
|
||||
}
|
||||
|
|
|
@ -15,105 +15,147 @@
|
|||
package exec
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"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"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/version"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/metadata"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml/matrix"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/version"
|
||||
)
|
||||
|
||||
// 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, w *metadata.Workflow) (*metadata.Metadata, error) {
|
||||
m := &metadata.Metadata{}
|
||||
|
||||
if c.IsSet("metadata-file") {
|
||||
metadataFile, err := os.Open(c.String("metadata-file"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer metadataFile.Close()
|
||||
|
||||
if err := json.NewDecoder(metadataFile).Decode(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
platform := c.String("system-platform")
|
||||
if platform == "" {
|
||||
platform = runtime.GOOS + "/" + runtime.GOARCH
|
||||
}
|
||||
|
||||
fullRepoName := c.String("repo-name")
|
||||
repoOwner := ""
|
||||
repoName := ""
|
||||
if idx := strings.LastIndex(fullRepoName, "/"); idx != -1 {
|
||||
repoOwner = fullRepoName[:idx]
|
||||
repoName = fullRepoName[idx+1:]
|
||||
metadataFileAndOverrideOrDefault(c, "repo-name", func(fullRepoName string) {
|
||||
if idx := strings.LastIndex(fullRepoName, "/"); idx != -1 {
|
||||
m.Repo.Owner = fullRepoName[:idx]
|
||||
m.Repo.Name = fullRepoName[idx+1:]
|
||||
}
|
||||
}, c.String)
|
||||
|
||||
var err error
|
||||
metadataFileAndOverrideOrDefault(c, "pipeline-changed-files", func(changedFilesRaw string) {
|
||||
var changedFiles []string
|
||||
if len(changedFilesRaw) != 0 && changedFilesRaw[0] == '[' {
|
||||
if jsonErr := json.Unmarshal([]byte(changedFilesRaw), &changedFiles); jsonErr != nil {
|
||||
err = fmt.Errorf("pipeline-changed-files detected json but could not parse it: %w", jsonErr)
|
||||
}
|
||||
} else {
|
||||
for _, file := range strings.Split(changedFilesRaw, ",") {
|
||||
changedFiles = append(changedFiles, strings.TrimSpace(file))
|
||||
}
|
||||
}
|
||||
m.Curr.Commit.ChangedFiles = changedFiles
|
||||
}, c.String)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return metadata.Metadata{
|
||||
Repo: metadata.Repo{
|
||||
Name: repoName,
|
||||
Owner: repoOwner,
|
||||
RemoteID: c.String("repo-remote-id"),
|
||||
ForgeURL: c.String("repo-url"),
|
||||
CloneURL: c.String("repo-clone-url"),
|
||||
CloneSSHURL: c.String("repo-clone-ssh-url"),
|
||||
Private: c.Bool("repo-private"),
|
||||
Trusted: c.Bool("repo-trusted"),
|
||||
},
|
||||
Curr: metadata.Pipeline{
|
||||
Number: c.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"),
|
||||
DeployTo: c.String("pipeline-deploy-to"),
|
||||
DeployTask: c.String("pipeline-deploy-task"),
|
||||
Commit: metadata.Commit{
|
||||
Sha: c.String("commit-sha"),
|
||||
Ref: c.String("commit-ref"),
|
||||
Refspec: c.String("commit-refspec"),
|
||||
Branch: c.String("commit-branch"),
|
||||
Message: c.String("commit-message"),
|
||||
Author: metadata.Author{
|
||||
Name: c.String("commit-author-name"),
|
||||
Email: c.String("commit-author-email"),
|
||||
Avatar: c.String("commit-author-avatar"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Prev: metadata.Pipeline{
|
||||
Number: c.Int64("prev-pipeline-number"),
|
||||
Created: c.Int64("prev-pipeline-created"),
|
||||
Started: c.Int64("prev-pipeline-started"),
|
||||
Finished: c.Int64("prev-pipeline-finished"),
|
||||
Status: c.String("prev-pipeline-status"),
|
||||
Event: c.String("prev-pipeline-event"),
|
||||
ForgeURL: c.String("prev-pipeline-url"),
|
||||
Commit: metadata.Commit{
|
||||
Sha: c.String("prev-commit-sha"),
|
||||
Ref: c.String("prev-commit-ref"),
|
||||
Refspec: c.String("prev-commit-refspec"),
|
||||
Branch: c.String("prev-commit-branch"),
|
||||
Message: c.String("prev-commit-message"),
|
||||
Author: metadata.Author{
|
||||
Name: c.String("prev-commit-author-name"),
|
||||
Email: c.String("prev-commit-author-email"),
|
||||
Avatar: c.String("prev-commit-author-avatar"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Workflow: metadata.Workflow{
|
||||
Name: c.String("workflow-name"),
|
||||
Number: c.Int("workflow-number"),
|
||||
Matrix: axis,
|
||||
},
|
||||
Step: metadata.Step{
|
||||
Name: c.String("step-name"),
|
||||
Number: c.Int("step-number"),
|
||||
},
|
||||
Sys: metadata.System{
|
||||
Name: c.String("system-name"),
|
||||
URL: c.String("system-url"),
|
||||
Platform: platform,
|
||||
Version: version.Version,
|
||||
},
|
||||
Forge: metadata.Forge{
|
||||
Type: c.String("forge-type"),
|
||||
URL: c.String("forge-url"),
|
||||
},
|
||||
// Repo
|
||||
metadataFileAndOverrideOrDefault(c, "repo-remote-id", func(s string) { m.Repo.RemoteID = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "repo-url", func(s string) { m.Repo.ForgeURL = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "repo-default-branch", func(s string) { m.Repo.Branch = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "repo-clone-url", func(s string) { m.Repo.CloneURL = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "repo-clone-ssh-url", func(s string) { m.Repo.CloneSSHURL = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "repo-private", func(b bool) { m.Repo.Private = b }, c.Bool)
|
||||
metadataFileAndOverrideOrDefault(c, "repo-trusted-network", func(b bool) { m.Repo.Trusted.Network = b }, c.Bool)
|
||||
metadataFileAndOverrideOrDefault(c, "repo-trusted-security", func(b bool) { m.Repo.Trusted.Security = b }, c.Bool)
|
||||
metadataFileAndOverrideOrDefault(c, "repo-trusted-volumes", func(b bool) { m.Repo.Trusted.Volumes = b }, c.Bool)
|
||||
|
||||
// Current Pipeline
|
||||
metadataFileAndOverrideOrDefault(c, "pipeline-number", func(i int64) { m.Curr.Number = i }, c.Int)
|
||||
metadataFileAndOverrideOrDefault(c, "pipeline-parent", func(i int64) { m.Curr.Parent = i }, c.Int)
|
||||
metadataFileAndOverrideOrDefault(c, "pipeline-created", func(i int64) { m.Curr.Created = i }, c.Int)
|
||||
metadataFileAndOverrideOrDefault(c, "pipeline-started", func(i int64) { m.Curr.Started = i }, c.Int)
|
||||
metadataFileAndOverrideOrDefault(c, "pipeline-finished", func(i int64) { m.Curr.Finished = i }, c.Int)
|
||||
metadataFileAndOverrideOrDefault(c, "pipeline-status", func(s string) { m.Curr.Status = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "pipeline-event", func(s string) { m.Curr.Event = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "pipeline-url", func(s string) { m.Curr.ForgeURL = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "pipeline-deploy-to", func(s string) { m.Curr.DeployTo = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "pipeline-deploy-task", func(s string) { m.Curr.DeployTask = s }, c.String)
|
||||
|
||||
// Current Pipeline Commit
|
||||
metadataFileAndOverrideOrDefault(c, "commit-sha", func(s string) { m.Curr.Commit.Sha = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "commit-ref", func(s string) { m.Curr.Commit.Ref = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "commit-refspec", func(s string) { m.Curr.Commit.Refspec = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "commit-branch", func(s string) { m.Curr.Commit.Branch = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "commit-message", func(s string) { m.Curr.Commit.Message = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "commit-author-name", func(s string) { m.Curr.Commit.Author.Name = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "commit-author-email", func(s string) { m.Curr.Commit.Author.Email = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "commit-author-avatar", func(s string) { m.Curr.Commit.Author.Avatar = s }, c.String)
|
||||
|
||||
metadataFileAndOverrideOrDefault(c, "commit-pull-labels", func(sl []string) { m.Curr.Commit.PullRequestLabels = sl }, c.StringSlice)
|
||||
metadataFileAndOverrideOrDefault(c, "commit-release-is-pre", func(b bool) { m.Curr.Commit.IsPrerelease = b }, c.Bool)
|
||||
|
||||
// Previous Pipeline
|
||||
metadataFileAndOverrideOrDefault(c, "prev-pipeline-number", func(i int64) { m.Prev.Number = i }, c.Int)
|
||||
metadataFileAndOverrideOrDefault(c, "prev-pipeline-created", func(i int64) { m.Prev.Created = i }, c.Int)
|
||||
metadataFileAndOverrideOrDefault(c, "prev-pipeline-started", func(i int64) { m.Prev.Started = i }, c.Int)
|
||||
metadataFileAndOverrideOrDefault(c, "prev-pipeline-finished", func(i int64) { m.Prev.Finished = i }, c.Int)
|
||||
metadataFileAndOverrideOrDefault(c, "prev-pipeline-status", func(s string) { m.Prev.Status = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "prev-pipeline-event", func(s string) { m.Prev.Event = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "prev-pipeline-url", func(s string) { m.Prev.ForgeURL = s }, c.String)
|
||||
|
||||
// Previous Pipeline Commit
|
||||
metadataFileAndOverrideOrDefault(c, "prev-commit-sha", func(s string) { m.Prev.Commit.Sha = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "prev-commit-ref", func(s string) { m.Prev.Commit.Ref = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "prev-commit-refspec", func(s string) { m.Prev.Commit.Refspec = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "prev-commit-branch", func(s string) { m.Prev.Commit.Branch = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "prev-commit-message", func(s string) { m.Prev.Commit.Message = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "prev-commit-author-name", func(s string) { m.Prev.Commit.Author.Name = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "prev-commit-author-email", func(s string) { m.Prev.Commit.Author.Email = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "prev-commit-author-avatar", func(s string) { m.Prev.Commit.Author.Avatar = s }, c.String)
|
||||
|
||||
// Workflow
|
||||
metadataFileAndOverrideOrDefault(c, "workflow-name", func(s string) { m.Workflow.Name = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "workflow-number", func(i int64) { m.Workflow.Number = int(i) }, c.Int)
|
||||
m.Workflow.Matrix = axis
|
||||
|
||||
// System
|
||||
metadataFileAndOverrideOrDefault(c, "system-name", func(s string) { m.Sys.Name = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "system-url", func(s string) { m.Sys.URL = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "system-host", func(s string) { m.Sys.Host = s }, c.String)
|
||||
m.Sys.Platform = platform
|
||||
m.Sys.Version = version.Version
|
||||
|
||||
// Forge
|
||||
metadataFileAndOverrideOrDefault(c, "forge-type", func(s string) { m.Forge.Type = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "forge-url", func(s string) { m.Forge.URL = s }, c.String)
|
||||
|
||||
if w != nil {
|
||||
m.Workflow = *w
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// metadataFileAndOverrideOrDefault will either use the flag default or if metadata file is set only overload if explicit set.
|
||||
func metadataFileAndOverrideOrDefault[T any](c *cli.Command, flag string, setter func(T), getter func(string) T) {
|
||||
if !c.IsSet("metadata-file") || c.IsSet(flag) {
|
||||
setter(getter(flag))
|
||||
}
|
||||
}
|
||||
|
|
142
cli/exec/metadata_test.go
Normal file
142
cli/exec/metadata_test.go
Normal file
|
@ -0,0 +1,142 @@
|
|||
// Copyright 2024 Woodpecker Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package exec
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/metadata"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml/matrix"
|
||||
)
|
||||
|
||||
func TestMetadataFromContext(t *testing.T) {
|
||||
sampleMetadata := &metadata.Metadata{
|
||||
Repo: metadata.Repo{Owner: "test-user", Name: "test-repo"},
|
||||
Curr: metadata.Pipeline{Number: 5},
|
||||
}
|
||||
|
||||
runCommand := func(flags []cli.Flag, fn func(c *cli.Command)) {
|
||||
c := &cli.Command{
|
||||
Flags: flags,
|
||||
Action: func(_ context.Context, c *cli.Command) error {
|
||||
fn(c)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
assert.NoError(t, c.Run(context.Background(), []string{"woodpecker-cli"}))
|
||||
}
|
||||
|
||||
t.Run("LoadFromFile", func(t *testing.T) {
|
||||
tempFileName := createTempFile(t, sampleMetadata)
|
||||
|
||||
flags := []cli.Flag{
|
||||
&cli.StringFlag{Name: "metadata-file"},
|
||||
}
|
||||
|
||||
runCommand(flags, func(c *cli.Command) {
|
||||
_ = c.Set("metadata-file", tempFileName)
|
||||
|
||||
m, err := metadataFromContext(context.Background(), c, nil, nil)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "test-repo", m.Repo.Name)
|
||||
assert.Equal(t, int64(5), m.Curr.Number)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("OverrideFromFlags", func(t *testing.T) {
|
||||
tempFileName := createTempFile(t, sampleMetadata)
|
||||
|
||||
flags := []cli.Flag{
|
||||
&cli.StringFlag{Name: "metadata-file"},
|
||||
&cli.StringFlag{Name: "repo-name"},
|
||||
&cli.IntFlag{Name: "pipeline-number"},
|
||||
}
|
||||
|
||||
runCommand(flags, func(c *cli.Command) {
|
||||
_ = c.Set("metadata-file", tempFileName)
|
||||
_ = c.Set("repo-name", "aUser/override-repo")
|
||||
_ = c.Set("pipeline-number", "10")
|
||||
|
||||
m, err := metadataFromContext(context.Background(), c, nil, nil)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "override-repo", m.Repo.Name)
|
||||
assert.Equal(t, int64(10), m.Curr.Number)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("InvalidFile", func(t *testing.T) {
|
||||
tempFile, err := os.CreateTemp("", "invalid.json")
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { os.Remove(tempFile.Name()) })
|
||||
|
||||
_, err = tempFile.Write([]byte("invalid json"))
|
||||
require.NoError(t, err)
|
||||
|
||||
flags := []cli.Flag{
|
||||
&cli.StringFlag{Name: "metadata-file"},
|
||||
}
|
||||
|
||||
runCommand(flags, func(c *cli.Command) {
|
||||
_ = c.Set("metadata-file", tempFile.Name())
|
||||
|
||||
_, err = metadataFromContext(context.Background(), c, nil, nil)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("DefaultValues", func(t *testing.T) {
|
||||
flags := []cli.Flag{
|
||||
&cli.StringFlag{Name: "repo-name", Value: "test/default-repo"},
|
||||
&cli.IntFlag{Name: "pipeline-number", Value: 1},
|
||||
}
|
||||
|
||||
runCommand(flags, func(c *cli.Command) {
|
||||
m, err := metadataFromContext(context.Background(), c, nil, nil)
|
||||
require.NoError(t, err)
|
||||
if assert.NotNil(t, m) {
|
||||
assert.Equal(t, "test", m.Repo.Owner)
|
||||
assert.Equal(t, "default-repo", m.Repo.Name)
|
||||
assert.Equal(t, int64(1), m.Curr.Number)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("MatrixAxis", func(t *testing.T) {
|
||||
runCommand([]cli.Flag{}, func(c *cli.Command) {
|
||||
axis := matrix.Axis{"go": "1.16", "os": "linux"}
|
||||
m, err := metadataFromContext(context.Background(), c, axis, nil)
|
||||
require.NoError(t, err)
|
||||
assert.EqualValues(t, map[string]string{"go": "1.16", "os": "linux"}, m.Workflow.Matrix)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func createTempFile(t *testing.T, content any) string {
|
||||
t.Helper()
|
||||
tempFile, err := os.CreateTemp("", "metadata.json")
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { os.Remove(tempFile.Name()) })
|
||||
|
||||
err = json.NewEncoder(tempFile).Encode(content)
|
||||
require.NoError(t, err)
|
||||
return tempFile.Name()
|
||||
}
|
|
@ -15,13 +15,14 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
)
|
||||
|
||||
// Command exports the info command.
|
||||
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,18 +33,18 @@ 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
|
||||
}
|
||||
|
||||
if config.ServerURL == "" || config.Token == "" {
|
||||
log.Info().Msg("The woodpecker-cli is not yet set up. Please run `woodpecker-cli setup` or provide the required environment variables / flags.")
|
||||
log.Info().Msg("woodpecker-cli is not set up, run `woodpecker-cli setup` or provide required environment variables/flags")
|
||||
return errors.New("woodpecker-cli is not configured")
|
||||
}
|
||||
|
||||
|
@ -62,7 +63,7 @@ func Load(c *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
log.Debug().Any("config", config).Msg("Loaded config")
|
||||
log.Debug().Any("config", config).Msg("loaded config")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -92,16 +93,16 @@ func Get(ctx *cli.Context, _configPath string) (*Config, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
log.Debug().Str("configPath", configPath).Msg("Checking for config file")
|
||||
log.Debug().Str("configPath", configPath).Msg("checking for config file")
|
||||
|
||||
content, err := os.ReadFile(configPath)
|
||||
switch {
|
||||
case err != nil && !os.IsNotExist(err):
|
||||
log.Debug().Err(err).Msg("Failed to read the config file")
|
||||
log.Debug().Err(err).Msg("failed to read the config file")
|
||||
return nil, err
|
||||
|
||||
case err != nil && os.IsNotExist(err):
|
||||
log.Debug().Msg("The config file does not exist")
|
||||
log.Debug().Msg("config file does not exist")
|
||||
|
||||
default:
|
||||
configFromFile := &Config{}
|
||||
|
@ -109,33 +110,33 @@ func Get(ctx *cli.Context, _configPath string) (*Config, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.MergeIfNotSet(configFromFile)
|
||||
log.Debug().Msg("Loaded config from file")
|
||||
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
|
||||
log.Warn().Msg("keyring is not supported on this platform")
|
||||
return conf, nil
|
||||
}
|
||||
if errors.Is(err, keyring.ErrNotFound) {
|
||||
log.Warn().Msg("Token not found in keyring")
|
||||
return c, nil
|
||||
log.Warn().Msg("token not found in keyring")
|
||||
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
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
|
@ -25,15 +26,15 @@ import (
|
|||
|
||||
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"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
// 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")
|
||||
|
@ -63,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,
|
||||
},
|
||||
|
@ -161,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)
|
||||
}
|
||||
|
|
|
@ -15,17 +15,19 @@
|
|||
package lint
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"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/pipeline/frontend/yaml"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/linter"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml/linter"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/shared/constant"
|
||||
)
|
||||
|
||||
// Command exports the info command.
|
||||
|
@ -34,13 +36,31 @@ 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 set empty, there is no",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Sources: cli.EnvVars("WOODPECKER_PLUGINS_TRUSTED_CLONE"),
|
||||
Name: "plugins-trusted-clone",
|
||||
Usage: "plugins that are trusted to handle Git credentials in cloning steps",
|
||||
Value: constant.TrustedClonePlugins,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Sources: cli.EnvVars("WOODPECKER_LINT_STRICT"),
|
||||
Name: "strict",
|
||||
Usage: "treat warnings as errors",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -50,7 +70,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("")
|
||||
|
@ -68,7 +88,7 @@ func lintDir(c *cli.Context, dir string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func lintFile(_ *cli.Context, file string) error {
|
||||
func lintFile(_ context.Context, c *cli.Command, file string) error {
|
||||
fi, err := os.Open(file)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -82,7 +102,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
|
||||
}
|
||||
|
@ -90,13 +110,21 @@ 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(linter.TrustedConfiguration{
|
||||
Network: true,
|
||||
Volumes: true,
|
||||
Security: true,
|
||||
}),
|
||||
linter.PrivilegedPlugins(c.StringSlice("plugins-privileged")),
|
||||
linter.WithTrustedClonePlugins(c.StringSlice("plugins-trusted-clone")),
|
||||
).Lint([]*linter.WorkflowConfig{config})
|
||||
if err != nil {
|
||||
str, err := FormatLintError(config.File, err)
|
||||
str, err := FormatLintError(config.File, err, c.Bool("strict"))
|
||||
|
||||
if str != "" {
|
||||
fmt.Print(str)
|
||||
|
|
|
@ -7,10 +7,10 @@ import (
|
|||
|
||||
term_env "github.com/muesli/termenv"
|
||||
|
||||
pipeline_errors "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors"
|
||||
pipeline_errors "go.woodpecker-ci.org/woodpecker/v3/pipeline/errors"
|
||||
)
|
||||
|
||||
func FormatLintError(file string, err error) (string, error) {
|
||||
func FormatLintError(file string, err error, strict bool) (string, error) {
|
||||
if err == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ func FormatLintError(file string, err error) (string, error) {
|
|||
for _, err := range linterErrors {
|
||||
line := " "
|
||||
|
||||
if err.IsWarning {
|
||||
if !strict && err.IsWarning {
|
||||
line = fmt.Sprintf("%s ⚠️ ", line)
|
||||
amountWarnings++
|
||||
} else {
|
||||
|
|
|
@ -15,16 +15,18 @@
|
|||
package org
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/org/registry"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/org/registry"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/org/secret"
|
||||
)
|
||||
|
||||
// Command exports the org command set.
|
||||
var Command = &cli.Command{
|
||||
Name: "org",
|
||||
Usage: "manage organizations",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
registry.Command,
|
||||
secret.Command,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -17,25 +17,25 @@ package registry
|
|||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
// Command exports the registry command set.
|
||||
var Command = &cli.Command{
|
||||
Name: "registry",
|
||||
Usage: "manage organization registries",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
registryCreateCmd,
|
||||
registryDeleteCmd,
|
||||
registryUpdateCmd,
|
||||
registryInfoCmd,
|
||||
registryListCmd,
|
||||
registryShowCmd,
|
||||
registryUpdateCmd,
|
||||
},
|
||||
}
|
||||
|
||||
func parseTargetArgs(client woodpecker.Client, c *cli.Context) (orgID int64, err error) {
|
||||
func parseTargetArgs(client woodpecker.Client, c *cli.Command) (orgID int64, err error) {
|
||||
orgIDOrName := c.String("organization")
|
||||
if orgIDOrName == "" {
|
||||
orgIDOrName = c.Args().First()
|
||||
|
|
|
@ -15,19 +15,20 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var registryCreateCmd = &cli.Command{
|
||||
Name: "add",
|
||||
Usage: "adds a registry",
|
||||
Usage: "add a registry",
|
||||
ArgsUsage: "[org-id|org-full-name]",
|
||||
Action: registryCreate,
|
||||
Flags: []cli.Flag{
|
||||
|
@ -48,14 +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")
|
||||
)
|
||||
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,13 +15,15 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var registryListCmd = &cli.Command{
|
||||
|
@ -35,10 +37,10 @@ var registryListCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func registryList(c *cli.Context) error {
|
||||
func registryList(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
|
||||
}
|
||||
|
@ -48,7 +50,9 @@ func registryList(c *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
list, err := client.OrgRegistryList(orgID)
|
||||
opt := woodpecker.RegistryListOptions{}
|
||||
|
||||
list, err := client.OrgRegistryList(orgID, opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,10 +15,12 @@
|
|||
package registry
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"context"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
)
|
||||
|
||||
var registryDeleteCmd = &cli.Command{
|
||||
|
@ -36,10 +38,10 @@ var registryDeleteCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func registryDelete(c *cli.Context) error {
|
||||
func registryDelete(ctx context.Context, c *cli.Command) error {
|
||||
hostname := c.String("hostname")
|
||||
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,14 +15,15 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var registryUpdateCmd = &cli.Command{
|
||||
|
@ -48,14 +49,14 @@ 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")
|
||||
)
|
||||
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,20 +15,21 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
)
|
||||
|
||||
var registryInfoCmd = &cli.Command{
|
||||
Name: "info",
|
||||
Usage: "display registry info",
|
||||
var registryShowCmd = &cli.Command{
|
||||
Name: "show",
|
||||
Usage: "show registry information",
|
||||
ArgsUsage: "[org-id|org-full-name]",
|
||||
Action: registryInfo,
|
||||
Action: registryShow,
|
||||
Flags: []cli.Flag{
|
||||
common.OrgFlag,
|
||||
&cli.StringFlag{
|
||||
|
@ -40,13 +41,13 @@ var registryInfoCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func registryInfo(c *cli.Context) error {
|
||||
func registryShow(ctx context.Context, c *cli.Command) error {
|
||||
var (
|
||||
hostname = c.String("hostname")
|
||||
format = c.String("format") + "\n"
|
||||
)
|
||||
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
60
cli/org/secret/secret.go
Normal file
60
cli/org/secret/secret.go
Normal file
|
@ -0,0 +1,60 @@
|
|||
// 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 secret
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
// Command exports the secret command.
|
||||
var Command = &cli.Command{
|
||||
Name: "secret",
|
||||
Usage: "manage secrets",
|
||||
Commands: []*cli.Command{
|
||||
secretCreateCmd,
|
||||
secretDeleteCmd,
|
||||
secretListCmd,
|
||||
secretShowCmd,
|
||||
secretUpdateCmd,
|
||||
},
|
||||
}
|
||||
|
||||
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
|
||||
}
|
|
@ -15,28 +15,24 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var secretCreateCmd = &cli.Command{
|
||||
Name: "add",
|
||||
Usage: "adds a secret",
|
||||
Usage: "add a secret",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretCreate,
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "global",
|
||||
Usage: "global secret",
|
||||
},
|
||||
common.OrgFlag,
|
||||
common.RepoFlag,
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "secret name",
|
||||
|
@ -56,8 +52,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
|
||||
}
|
||||
|
@ -80,22 +76,12 @@ func secretCreate(c *cli.Context) error {
|
|||
secret.Value = string(out)
|
||||
}
|
||||
|
||||
global, orgID, repoID, err := parseTargetArgs(client, c)
|
||||
orgID, err := parseTargetArgs(client, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if global {
|
||||
_, err = client.GlobalSecretCreate(secret)
|
||||
return err
|
||||
}
|
||||
|
||||
if orgID != -1 {
|
||||
_, err = client.OrgSecretCreate(orgID, secret)
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = client.SecretCreate(repoID, secret)
|
||||
_, err = client.OrgSecretCreate(orgID, secret)
|
||||
return err
|
||||
}
|
||||
|
87
cli/org/secret/secret_list.go
Normal file
87
cli/org/secret/secret_list.go
Normal file
|
@ -0,0 +1,87 @@
|
|||
// 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 secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"html/template"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var secretListCmd = &cli.Command{
|
||||
Name: "ls",
|
||||
Usage: "list secrets",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretList,
|
||||
Flags: []cli.Flag{
|
||||
common.OrgFlag,
|
||||
common.FormatFlag(tmplSecretList, true),
|
||||
},
|
||||
}
|
||||
|
||||
func secretList(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
|
||||
}
|
||||
|
||||
opt := woodpecker.SecretListOptions{}
|
||||
|
||||
list, err := client.OrgSecretList(orgID, opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpl, err := template.New("_").Funcs(secretFuncMap).Parse(format)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, secret := range list {
|
||||
if err := tmpl.Execute(os.Stdout, secret); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Template for secret list items.
|
||||
var tmplSecretList = "\x1b[33m{{ .Name }} \x1b[0m" + `
|
||||
Events: {{ list .Events }}
|
||||
{{- if .Images }}
|
||||
Images: {{ list .Images }}
|
||||
{{- else }}
|
||||
Images: <any>
|
||||
{{- end }}
|
||||
`
|
||||
|
||||
var secretFuncMap = template.FuncMap{
|
||||
"list": func(s []string) string {
|
||||
return strings.Join(s, ", ")
|
||||
},
|
||||
}
|
54
cli/org/secret/secret_rm.go
Normal file
54
cli/org/secret/secret_rm.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
// 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 secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
)
|
||||
|
||||
var secretDeleteCmd = &cli.Command{
|
||||
Name: "rm",
|
||||
Usage: "remove a secret",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretDelete,
|
||||
Flags: []cli.Flag{
|
||||
common.OrgFlag,
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "secret name",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func secretDelete(ctx context.Context, c *cli.Command) error {
|
||||
secretName := c.String("name")
|
||||
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
orgID, err := parseTargetArgs(client, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return client.OrgSecretDelete(orgID, secretName)
|
||||
}
|
83
cli/org/secret/secret_set.go
Normal file
83
cli/org/secret/secret_set.go
Normal file
|
@ -0,0 +1,83 @@
|
|||
// 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 secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var secretUpdateCmd = &cli.Command{
|
||||
Name: "update",
|
||||
Usage: "update a secret",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretUpdate,
|
||||
Flags: []cli.Flag{
|
||||
common.OrgFlag,
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "secret name",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "value",
|
||||
Usage: "secret value",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "event",
|
||||
Usage: "limit secret to these event",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "image",
|
||||
Usage: "limit secret to these image",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func secretUpdate(ctx context.Context, c *cli.Command) error {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secret := &woodpecker.Secret{
|
||||
Name: strings.ToLower(c.String("name")),
|
||||
Value: c.String("value"),
|
||||
Images: c.StringSlice("image"),
|
||||
Events: c.StringSlice("event"),
|
||||
}
|
||||
if strings.HasPrefix(secret.Value, "@") {
|
||||
path := strings.TrimPrefix(secret.Value, "@")
|
||||
out, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
secret.Value = string(out)
|
||||
}
|
||||
|
||||
orgID, err := parseTargetArgs(client, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = client.OrgSecretUpdate(orgID, secret)
|
||||
return err
|
||||
}
|
74
cli/org/secret/secret_show.go
Normal file
74
cli/org/secret/secret_show.go
Normal file
|
@ -0,0 +1,74 @@
|
|||
// 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 secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"os"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
)
|
||||
|
||||
var secretShowCmd = &cli.Command{
|
||||
Name: "show",
|
||||
Usage: "show secret information",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretShow,
|
||||
Flags: []cli.Flag{
|
||||
common.OrgFlag,
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "secret name",
|
||||
},
|
||||
common.FormatFlag(tmplSecretList, true),
|
||||
},
|
||||
}
|
||||
|
||||
func secretShow(ctx context.Context, c *cli.Command) error {
|
||||
var (
|
||||
secretName = c.String("name")
|
||||
format = c.String("format") + "\n"
|
||||
)
|
||||
|
||||
if secretName == "" {
|
||||
return fmt.Errorf("secret name is missing")
|
||||
}
|
||||
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
orgID, err := parseTargetArgs(client, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secret, err := client.OrgSecret(orgID, secretName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpl, err := template.New("_").Funcs(secretFuncMap).Parse(format)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tmpl.Execute(os.Stdout, secret)
|
||||
}
|
|
@ -9,7 +9,7 @@ import (
|
|||
"text/tabwriter"
|
||||
"unicode"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/go-viper/mapstructure/v2"
|
||||
)
|
||||
|
||||
// NewTable creates a new Table.
|
||||
|
@ -147,12 +147,12 @@ func (o *Table) Write(columns []string, obj any) error {
|
|||
colName := strings.ToLower(col)
|
||||
if alias, ok := o.fieldAlias[colName]; ok {
|
||||
if fn, ok := o.fieldMapping[alias]; ok {
|
||||
out = append(out, fn(obj))
|
||||
out = append(out, sanitizeString(fn(obj)))
|
||||
continue
|
||||
}
|
||||
}
|
||||
if fn, ok := o.fieldMapping[colName]; ok {
|
||||
out = append(out, fn(obj))
|
||||
out = append(out, sanitizeString(fn(obj)))
|
||||
continue
|
||||
}
|
||||
if value, ok := dataL[strings.ReplaceAll(colName, "_", "")]; ok {
|
||||
|
@ -165,10 +165,10 @@ func (o *Table) Write(columns []string, obj any) error {
|
|||
continue
|
||||
}
|
||||
if s, ok := value.(string); ok {
|
||||
out = append(out, NA(s))
|
||||
out = append(out, NA(sanitizeString(s)))
|
||||
continue
|
||||
}
|
||||
out = append(out, fmt.Sprintf("%v", value))
|
||||
out = append(out, sanitizeString(value))
|
||||
}
|
||||
}
|
||||
_, _ = fmt.Fprintln(o.w, strings.Join(out, "\t"))
|
||||
|
@ -201,3 +201,9 @@ func fieldName(name string) string {
|
|||
}
|
||||
return string(out)
|
||||
}
|
||||
|
||||
func sanitizeString(value any) string {
|
||||
str := fmt.Sprintf("%v", value)
|
||||
replacer := strings.NewReplacer("\n", " ", "\r", " ")
|
||||
return strings.TrimSpace(replacer.Replace(str))
|
||||
}
|
||||
|
|
|
@ -15,12 +15,13 @@
|
|||
package pipeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
)
|
||||
|
||||
var pipelineApproveCmd = &cli.Command{
|
||||
|
@ -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
|
||||
}
|
||||
|
|
|
@ -15,13 +15,14 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var pipelineCreateCmd = &cli.Command{
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -73,5 +74,5 @@ func pipelineCreate(c *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
return pipelineOutput(c, []woodpecker.Pipeline{*pipeline})
|
||||
return pipelineOutput(c, []*woodpecker.Pipeline{pipeline})
|
||||
}
|
||||
|
|
|
@ -15,12 +15,13 @@
|
|||
package pipeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
)
|
||||
|
||||
var pipelineDeclineCmd = &cli.Command{
|
||||
|
@ -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
|
||||
}
|
||||
|
|
|
@ -15,16 +15,17 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
// Command exports the deploy command.
|
||||
|
@ -52,13 +53,13 @@ var Command = &cli.Command{
|
|||
&cli.StringSliceFlag{
|
||||
Name: "param",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "custom parameters to be injected into the step environment. Format: KEY=value",
|
||||
Usage: "custom parameters to inject into the step environment. Format: KEY=value",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -79,14 +80,14 @@ func deploy(c *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
branch = repo.DefaultBranch
|
||||
branch = repo.Branch
|
||||
}
|
||||
|
||||
pipelineArg := c.Args().Get(1)
|
||||
var number int64
|
||||
if pipelineArg == "last" {
|
||||
// Fetch the pipeline number from the last pipeline
|
||||
pipelines, err := client.PipelineList(repoID)
|
||||
pipelines, err := client.PipelineList(repoID, woodpecker.PipelineListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -120,9 +121,12 @@ func deploy(c *cli.Context) error {
|
|||
return fmt.Errorf("please specify the target environment (i.e. production)")
|
||||
}
|
||||
|
||||
params := internal.ParseKeyPair(c.StringSlice("param"))
|
||||
opt := woodpecker.DeployOptions{
|
||||
DeployTo: env,
|
||||
Params: internal.ParseKeyPair(c.StringSlice("param")),
|
||||
}
|
||||
|
||||
deploy, err := client.Deploy(repoID, number, env, params)
|
||||
deploy, err := client.Deploy(repoID, number, opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
|
@ -15,12 +15,13 @@
|
|||
package pipeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
)
|
||||
|
||||
var pipelineKillCmd = &cli.Command{
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -47,7 +48,7 @@ func pipelineKill(c *cli.Context) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
err = client.PipelineKill(repoID, number)
|
||||
err = client.PipelineDelete(repoID, number)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,16 +15,18 @@
|
|||
package pipeline
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"context"
|
||||
|
||||
"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"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var pipelineLastCmd = &cli.Command{
|
||||
Name: "last",
|
||||
Usage: "show latest pipeline details",
|
||||
Usage: "show latest pipeline information",
|
||||
ArgsUsage: "<repo-id|repo-full-name>",
|
||||
Action: pipelineLast,
|
||||
Flags: append(common.OutputFlags("table"), []cli.Flag{
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -47,10 +49,14 @@ func pipelineLast(c *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
pipeline, err := client.PipelineLast(repoID, c.String("branch"))
|
||||
opt := woodpecker.PipelineLastOptions{
|
||||
Branch: c.String("branch"),
|
||||
}
|
||||
|
||||
pipeline, err := client.PipelineLast(repoID, opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return pipelineOutput(c, []woodpecker.Pipeline{*pipeline})
|
||||
return pipelineOutput(c, []*woodpecker.Pipeline{pipeline})
|
||||
}
|
||||
|
|
|
@ -15,88 +15,114 @@
|
|||
package pipeline
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
shared_utils "go.woodpecker-ci.org/woodpecker/v3/shared/utils"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
//nolint:mnd
|
||||
var pipelineListCmd = &cli.Command{
|
||||
Name: "ls",
|
||||
Usage: "show pipeline history",
|
||||
ArgsUsage: "<repo-id|repo-full-name>",
|
||||
Action: List,
|
||||
Flags: append(common.OutputFlags("table"), []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "branch",
|
||||
Usage: "branch filter",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "event",
|
||||
Usage: "event filter",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "status",
|
||||
Usage: "status filter",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "limit",
|
||||
Usage: "limit the list size",
|
||||
Value: 25,
|
||||
},
|
||||
}...),
|
||||
func buildPipelineListCmd() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "ls",
|
||||
Usage: "show pipeline history",
|
||||
ArgsUsage: "<repo-id|repo-full-name>",
|
||||
Action: List,
|
||||
Flags: append(common.OutputFlags("table"), []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "branch",
|
||||
Usage: "branch filter",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "event",
|
||||
Usage: "event filter",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "status",
|
||||
Usage: "status filter",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "limit",
|
||||
Usage: "limit the list size",
|
||||
Value: 25,
|
||||
},
|
||||
&cli.TimestampFlag{
|
||||
Name: "before",
|
||||
Usage: "only return pipelines before this date (RFC3339)",
|
||||
Config: cli.TimestampConfig{
|
||||
Layouts: []string{
|
||||
time.RFC3339,
|
||||
},
|
||||
},
|
||||
},
|
||||
&cli.TimestampFlag{
|
||||
Name: "after",
|
||||
Usage: "only return pipelines after this date (RFC3339)",
|
||||
Config: cli.TimestampConfig{
|
||||
Layouts: []string{
|
||||
time.RFC3339,
|
||||
},
|
||||
},
|
||||
},
|
||||
}...),
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
pipelines, err := pipelineList(c, client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return pipelineOutput(c, resources)
|
||||
return pipelineOutput(c, pipelines)
|
||||
}
|
||||
|
||||
func pipelineList(c *cli.Context, client woodpecker.Client) ([]woodpecker.Pipeline, error) {
|
||||
resources := make([]woodpecker.Pipeline, 0)
|
||||
|
||||
func pipelineList(c *cli.Command, client woodpecker.Client) ([]*woodpecker.Pipeline, error) {
|
||||
repoIDOrFullName := c.Args().First()
|
||||
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
|
||||
if err != nil {
|
||||
return resources, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pipelines, err := client.PipelineList(repoID)
|
||||
if err != nil {
|
||||
return resources, err
|
||||
opt := woodpecker.PipelineListOptions{}
|
||||
|
||||
if before := c.Timestamp("before"); !before.IsZero() {
|
||||
opt.Before = before
|
||||
}
|
||||
if after := c.Timestamp("after"); !after.IsZero() {
|
||||
opt.After = after
|
||||
}
|
||||
|
||||
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 {
|
||||
if count >= limit {
|
||||
break
|
||||
}
|
||||
if branch != "" && pipeline.Branch != branch {
|
||||
continue
|
||||
}
|
||||
if event != "" && pipeline.Event != event {
|
||||
continue
|
||||
}
|
||||
if status != "" && pipeline.Status != status {
|
||||
continue
|
||||
}
|
||||
resources = append(resources, *pipeline)
|
||||
count++
|
||||
pipelines, err := shared_utils.Paginate(func(page int) ([]*woodpecker.Pipeline, error) {
|
||||
return client.PipelineList(repoID,
|
||||
woodpecker.PipelineListOptions{
|
||||
ListOptions: woodpecker.ListOptions{
|
||||
Page: page,
|
||||
},
|
||||
Before: opt.Before,
|
||||
After: opt.After,
|
||||
Branch: branch,
|
||||
Events: []string{event},
|
||||
Status: status,
|
||||
},
|
||||
)
|
||||
}, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resources, nil
|
||||
return pipelines, nil
|
||||
}
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker/mocks"
|
||||
)
|
||||
|
||||
func TestPipelineList(t *testing.T) {
|
||||
|
@ -21,7 +22,7 @@ func TestPipelineList(t *testing.T) {
|
|||
pipelines []*woodpecker.Pipeline
|
||||
pipelineErr error
|
||||
args []string
|
||||
expected []woodpecker.Pipeline
|
||||
expected []*woodpecker.Pipeline
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
|
@ -33,53 +34,12 @@ func TestPipelineList(t *testing.T) {
|
|||
{ID: 3, Branch: "main", Event: "push", Status: "failure"},
|
||||
},
|
||||
args: []string{"ls", "repo/name"},
|
||||
expected: []woodpecker.Pipeline{
|
||||
expected: []*woodpecker.Pipeline{
|
||||
{ID: 1, Branch: "main", Event: "push", Status: "success"},
|
||||
{ID: 2, Branch: "develop", Event: "pull_request", Status: "running"},
|
||||
{ID: 3, Branch: "main", Event: "push", Status: "failure"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "filter by branch",
|
||||
repoID: 1,
|
||||
pipelines: []*woodpecker.Pipeline{
|
||||
{ID: 1, Branch: "main", Event: "push", Status: "success"},
|
||||
{ID: 2, Branch: "develop", Event: "pull_request", Status: "running"},
|
||||
{ID: 3, Branch: "main", Event: "push", Status: "failure"},
|
||||
},
|
||||
args: []string{"ls", "--branch", "main", "repo/name"},
|
||||
expected: []woodpecker.Pipeline{
|
||||
{ID: 1, Branch: "main", Event: "push", Status: "success"},
|
||||
{ID: 3, Branch: "main", Event: "push", Status: "failure"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "filter by event",
|
||||
repoID: 1,
|
||||
pipelines: []*woodpecker.Pipeline{
|
||||
{ID: 1, Branch: "main", Event: "push", Status: "success"},
|
||||
{ID: 2, Branch: "develop", Event: "pull_request", Status: "running"},
|
||||
{ID: 3, Branch: "main", Event: "push", Status: "failure"},
|
||||
},
|
||||
args: []string{"ls", "--event", "push", "repo/name"},
|
||||
expected: []woodpecker.Pipeline{
|
||||
{ID: 1, Branch: "main", Event: "push", Status: "success"},
|
||||
{ID: 3, Branch: "main", Event: "push", Status: "failure"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "filter by status",
|
||||
repoID: 1,
|
||||
pipelines: []*woodpecker.Pipeline{
|
||||
{ID: 1, Branch: "main", Event: "push", Status: "success"},
|
||||
{ID: 2, Branch: "develop", Event: "pull_request", Status: "running"},
|
||||
{ID: 3, Branch: "main", Event: "push", Status: "failure"},
|
||||
},
|
||||
args: []string{"ls", "--status", "success", "repo/name"},
|
||||
expected: []woodpecker.Pipeline{
|
||||
{ID: 1, Branch: "main", Event: "push", Status: "success"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "limit results",
|
||||
repoID: 1,
|
||||
|
@ -89,7 +49,7 @@ func TestPipelineList(t *testing.T) {
|
|||
{ID: 3, Branch: "main", Event: "push", Status: "failure"},
|
||||
},
|
||||
args: []string{"ls", "--limit", "2", "repo/name"},
|
||||
expected: []woodpecker.Pipeline{
|
||||
expected: []*woodpecker.Pipeline{
|
||||
{ID: 1, Branch: "main", Event: "push", Status: "success"},
|
||||
{ID: 2, Branch: "develop", Event: "pull_request", Status: "running"},
|
||||
},
|
||||
|
@ -106,14 +66,20 @@ func TestPipelineList(t *testing.T) {
|
|||
for _, tt := range testtases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mockClient := mocks.NewClient(t)
|
||||
mockClient.On("PipelineList", mock.Anything).Return(tt.pipelines, tt.pipelineErr)
|
||||
mockClient.On("PipelineList", mock.Anything, mock.Anything).Return(func(_ int64, opt woodpecker.PipelineListOptions) ([]*woodpecker.Pipeline, error) {
|
||||
if tt.pipelineErr != nil {
|
||||
return nil, tt.pipelineErr
|
||||
}
|
||||
if opt.Page == 1 {
|
||||
return tt.pipelines, nil
|
||||
}
|
||||
return []*woodpecker.Pipeline{}, nil
|
||||
}).Maybe()
|
||||
mockClient.On("RepoLookup", mock.Anything).Return(&woodpecker.Repo{ID: tt.repoID}, nil)
|
||||
|
||||
app := &cli.App{Writer: io.Discard}
|
||||
c := cli.NewContext(app, nil, nil)
|
||||
|
||||
command := pipelineListCmd
|
||||
command.Action = func(c *cli.Context) error {
|
||||
command := buildPipelineListCmd()
|
||||
command.Writer = io.Discard
|
||||
command.Action = func(_ context.Context, c *cli.Command) error {
|
||||
pipelines, err := pipelineList(c, mockClient)
|
||||
if tt.wantErr != nil {
|
||||
assert.EqualError(t, err, tt.wantErr.Error())
|
||||
|
@ -126,7 +92,7 @@ func TestPipelineList(t *testing.T) {
|
|||
return nil
|
||||
}
|
||||
|
||||
_ = command.Run(c, tt.args...)
|
||||
_ = command.Run(context.Background(), tt.args)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,14 +15,15 @@
|
|||
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,
|
||||
logShowCmd,
|
||||
},
|
||||
}
|
|
@ -15,55 +15,64 @@
|
|||
package log
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
)
|
||||
|
||||
var logPurgeCmd = &cli.Command{
|
||||
Name: "purge",
|
||||
Usage: "purge a log",
|
||||
ArgsUsage: "<repo-id|repo-full-name> <pipeline> [step]",
|
||||
ArgsUsage: "<repo-id|repo-full-name> <pipeline> [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
|
||||
}
|
112
cli/pipeline/log/log_show.go
Normal file
112
cli/pipeline/log/log_show.go
Normal file
|
@ -0,0 +1,112 @@
|
|||
// 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 log
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"text/template"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var logShowCmd = &cli.Command{
|
||||
Name: "show",
|
||||
Usage: "show pipeline logs",
|
||||
ArgsUsage: "<repo-id|repo-full-name> <pipeline> [step-number|step-name]",
|
||||
Action: logShow,
|
||||
}
|
||||
|
||||
func logShow(ctx context.Context, c *cli.Command) error {
|
||||
repoIDOrFullName := c.Args().First()
|
||||
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 fmt.Errorf("invalid repo '%s': %w ", repoIDOrFullName, err)
|
||||
}
|
||||
|
||||
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 pipelineLog(client, repoID, number)
|
||||
}
|
||||
|
||||
step, err := internal.ParseStep(client, repoID, number, stepArg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid step '%s': %w", stepArg, err)
|
||||
}
|
||||
return stepLog(client, repoID, number, step)
|
||||
}
|
||||
|
||||
func pipelineLog(client woodpecker.Client, repoID, number int64) error {
|
||||
pipeline, err := client.Pipeline(repoID, number)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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 := stepLog(client, repoID, number, step.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func stepLog(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.Println(string(log.Data))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// template for pipeline ps information.
|
||||
var tmplPipelineLogs = "\x1b[33m{{ .workflow.Name }} > {{ .step.Name }} (#{{ .step.PID }}):\x1b[0m"
|
|
@ -1,66 +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 pipeline
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
)
|
||||
|
||||
var pipelineLogsCmd = &cli.Command{
|
||||
Name: "logs",
|
||||
Usage: "show pipeline logs",
|
||||
ArgsUsage: "<repo-id|repo-full-name> [pipeline] [stepID]",
|
||||
Action: pipelineLogs,
|
||||
}
|
||||
|
||||
func pipelineLogs(c *cli.Context) error {
|
||||
repoIDOrFullName := c.Args().First()
|
||||
client, err := internal.NewClient(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
numberArgIndex := 1
|
||||
number, err := strconv.ParseInt(c.Args().Get(numberArgIndex), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stepArgIndex := 2
|
||||
step, err := strconv.ParseInt(c.Args().Get(stepArgIndex), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logs, err := client.StepLogEntries(repoID, number, step)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, log := range logs {
|
||||
fmt.Print(string(log.Data))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -20,33 +20,37 @@ 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"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/output"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/pipeline/deploy"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/pipeline/log"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
// Command exports the pipeline command set.
|
||||
var Command = &cli.Command{
|
||||
Name: "pipeline",
|
||||
Usage: "manage pipelines",
|
||||
Subcommands: []*cli.Command{
|
||||
pipelineListCmd,
|
||||
pipelineLastCmd,
|
||||
pipelineLogsCmd,
|
||||
pipelineInfoCmd,
|
||||
pipelineStopCmd,
|
||||
pipelineStartCmd,
|
||||
Commands: []*cli.Command{
|
||||
pipelineApproveCmd,
|
||||
pipelineDeclineCmd,
|
||||
pipelineQueueCmd,
|
||||
pipelineKillCmd,
|
||||
pipelinePsCmd,
|
||||
pipelineCreateCmd,
|
||||
pipelineDeclineCmd,
|
||||
deploy.Command,
|
||||
pipelineKillCmd,
|
||||
pipelineLastCmd,
|
||||
buildPipelineListCmd(),
|
||||
log.Command,
|
||||
pipelinePsCmd,
|
||||
pipelinePurgeCmd,
|
||||
pipelineQueueCmd,
|
||||
pipelineShowCmd,
|
||||
pipelineStartCmd,
|
||||
pipelineStopCmd,
|
||||
},
|
||||
}
|
||||
|
||||
func pipelineOutput(c *cli.Context, resources []woodpecker.Pipeline, fd ...io.Writer) error {
|
||||
func pipelineOutput(c *cli.Command, pipelines []*woodpecker.Pipeline, fd ...io.Writer) error {
|
||||
outFmt, outOpt := output.ParseOutputOptions(c.String("output"))
|
||||
noHeader := c.Bool("output-no-headers")
|
||||
|
||||
|
@ -70,7 +74,7 @@ func pipelineOutput(c *cli.Context, resources []woodpecker.Pipeline, fd ...io.Wr
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tmpl.Execute(out, resources); err != nil {
|
||||
if err := tmpl.Execute(out, pipelines); err != nil {
|
||||
return err
|
||||
}
|
||||
case "table":
|
||||
|
@ -85,7 +89,7 @@ func pipelineOutput(c *cli.Context, resources []woodpecker.Pipeline, fd ...io.Wr
|
|||
if !noHeader {
|
||||
table.WriteHeader(cols)
|
||||
}
|
||||
for _, resource := range resources {
|
||||
for _, resource := range pipelines {
|
||||
if err := table.Write(cols, resource); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -2,14 +2,15 @@ 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"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
func TestPipelineOutput(t *testing.T) {
|
||||
|
@ -22,7 +23,7 @@ func TestPipelineOutput(t *testing.T) {
|
|||
{
|
||||
name: "table output with default columns",
|
||||
args: []string{},
|
||||
expected: "NUMBER STATUS EVENT BRANCH MESSAGE AUTHOR\n1 success push main message John Doe\n",
|
||||
expected: "NUMBER STATUS EVENT BRANCH MESSAGE AUTHOR\n1 success push main message multiline 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 message John Doe\n",
|
||||
expected: "1 success push main message multiline John Doe\n",
|
||||
},
|
||||
{
|
||||
name: "go-template output",
|
||||
|
@ -46,41 +47,40 @@ func TestPipelineOutput(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
pipelines := []woodpecker.Pipeline{
|
||||
pipelines := []*woodpecker.Pipeline{
|
||||
{
|
||||
Number: 1,
|
||||
Status: "success",
|
||||
Event: "push",
|
||||
Branch: "main",
|
||||
Message: "message",
|
||||
Author: "John Doe",
|
||||
Message: "message\nmultiline",
|
||||
Author: "John Doe\n",
|
||||
},
|
||||
}
|
||||
|
||||
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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,33 +15,36 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var pipelinePsCmd = &cli.Command{
|
||||
Name: "ps",
|
||||
Usage: "show pipeline steps",
|
||||
ArgsUsage: "<repo-id|repo-full-name> [pipeline]",
|
||||
ArgsUsage: "<repo-id|repo-full-name> <pipeline>",
|
||||
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)
|
||||
|
@ -49,7 +52,7 @@ func pipelinePs(c *cli.Context) error {
|
|||
|
||||
if pipelineArg == "last" || len(pipelineArg) == 0 {
|
||||
// Fetch the pipeline number from the last pipeline
|
||||
pipeline, err := client.PipelineLast(repoID, "")
|
||||
pipeline, err := client.PipelineLast(repoID, woodpecker.PipelineLastOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -58,7 +61,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 +75,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 +86,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 }}
|
||||
`
|
||||
|
|
164
cli/pipeline/purge.go
Normal file
164
cli/pipeline/purge.go
Normal file
|
@ -0,0 +1,164 @@
|
|||
// 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"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
shared_utils "go.woodpecker-ci.org/woodpecker/v3/shared/utils"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
//nolint:mnd
|
||||
var pipelinePurgeCmd = &cli.Command{
|
||||
Name: "purge",
|
||||
Usage: "purge pipelines",
|
||||
ArgsUsage: "<repo-id|repo-full-name>",
|
||||
Action: Purge,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "older-than",
|
||||
Usage: "remove pipelines older than the specified time limit",
|
||||
Required: true,
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "keep-min",
|
||||
Usage: "minimum number of pipelines to keep",
|
||||
Value: 10,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "dry-run",
|
||||
Usage: "disable non-read api calls",
|
||||
Value: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func Purge(ctx context.Context, c *cli.Command) error {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return pipelinePurge(c, client)
|
||||
}
|
||||
|
||||
func pipelinePurge(c *cli.Command, client woodpecker.Client) (err error) {
|
||||
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 fmt.Errorf("invalid repo '%s': %w", repoIDOrFullName, err)
|
||||
}
|
||||
|
||||
olderThan := c.String("older-than")
|
||||
keepMin := c.Int("keep-min")
|
||||
dryRun := c.Bool("dry-run")
|
||||
|
||||
duration, err := time.ParseDuration(olderThan)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var pipelinesKeep []*woodpecker.Pipeline
|
||||
|
||||
if keepMin > 0 {
|
||||
pipelinesKeep, err = fetchPipelinesToKeep(client, repoID, int(keepMin))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
pipelines, err := fetchPipelines(client, repoID, duration)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create a map of pipeline IDs to keep
|
||||
keepMap := make(map[int64]struct{})
|
||||
for _, p := range pipelinesKeep {
|
||||
keepMap[p.Number] = struct{}{}
|
||||
}
|
||||
|
||||
// Filter pipelines to only include those not in keepMap
|
||||
var pipelinesToPurge []*woodpecker.Pipeline
|
||||
for _, p := range pipelines {
|
||||
if _, exists := keepMap[p.Number]; !exists {
|
||||
pipelinesToPurge = append(pipelinesToPurge, p)
|
||||
}
|
||||
}
|
||||
|
||||
msgPrefix := ""
|
||||
if dryRun {
|
||||
msgPrefix = "DRY-RUN: "
|
||||
}
|
||||
|
||||
for i, p := range pipelinesToPurge {
|
||||
// cspell:words spurge
|
||||
log.Debug().Msgf("%spurge %v/%v pipelines from repo '%v' (pipeline %v)", msgPrefix, i+1, len(pipelinesToPurge), repoIDOrFullName, p.Number)
|
||||
if dryRun {
|
||||
continue
|
||||
}
|
||||
|
||||
err := client.PipelineDelete(repoID, p.Number)
|
||||
if err != nil {
|
||||
var clientErr *woodpecker.ClientError
|
||||
if errors.As(err, &clientErr) && clientErr.StatusCode == http.StatusUnprocessableEntity {
|
||||
log.Error().Err(err).Msgf("failed to delete pipeline %d", p.Number)
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func fetchPipelinesToKeep(client woodpecker.Client, repoID int64, keepMin int) ([]*woodpecker.Pipeline, error) {
|
||||
if keepMin <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return shared_utils.Paginate(func(page int) ([]*woodpecker.Pipeline, error) {
|
||||
return client.PipelineList(repoID,
|
||||
woodpecker.PipelineListOptions{
|
||||
ListOptions: woodpecker.ListOptions{
|
||||
Page: page,
|
||||
},
|
||||
},
|
||||
)
|
||||
}, keepMin)
|
||||
}
|
||||
|
||||
func fetchPipelines(client woodpecker.Client, repoID int64, duration time.Duration) ([]*woodpecker.Pipeline, error) {
|
||||
return shared_utils.Paginate(func(page int) ([]*woodpecker.Pipeline, error) {
|
||||
return client.PipelineList(repoID,
|
||||
woodpecker.PipelineListOptions{
|
||||
ListOptions: woodpecker.ListOptions{
|
||||
Page: page,
|
||||
},
|
||||
Before: time.Now().Add(-duration),
|
||||
},
|
||||
)
|
||||
}, -1)
|
||||
}
|
126
cli/pipeline/purge_test.go
Normal file
126
cli/pipeline/purge_test.go
Normal file
|
@ -0,0 +1,126 @@
|
|||
package pipeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker/mocks"
|
||||
)
|
||||
|
||||
func TestPipelinePurge(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
repoID int64
|
||||
args []string
|
||||
pipelinesKeep []*woodpecker.Pipeline
|
||||
pipelines []*woodpecker.Pipeline
|
||||
mockDeleteError error
|
||||
wantDelete int
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "success with no pipelines to purge",
|
||||
repoID: 1,
|
||||
args: []string{"purge", "--older-than", "1h", "repo/name"},
|
||||
pipelinesKeep: []*woodpecker.Pipeline{
|
||||
{Number: 1},
|
||||
},
|
||||
pipelines: []*woodpecker.Pipeline{},
|
||||
},
|
||||
{
|
||||
name: "success with pipelines to purge",
|
||||
repoID: 1,
|
||||
args: []string{"purge", "--older-than", "1h", "repo/name"},
|
||||
pipelinesKeep: []*woodpecker.Pipeline{
|
||||
{Number: 1},
|
||||
},
|
||||
pipelines: []*woodpecker.Pipeline{
|
||||
{Number: 1},
|
||||
{Number: 2},
|
||||
{Number: 3},
|
||||
},
|
||||
wantDelete: 2,
|
||||
},
|
||||
{
|
||||
name: "error on invalid duration",
|
||||
repoID: 1,
|
||||
args: []string{"purge", "--older-than", "invalid", "repo/name"},
|
||||
wantErr: errors.New("time: invalid duration \"invalid\""),
|
||||
},
|
||||
{
|
||||
name: "continue on 422 error",
|
||||
repoID: 1,
|
||||
args: []string{"purge", "--older-than", "1h", "repo/name"},
|
||||
pipelinesKeep: []*woodpecker.Pipeline{
|
||||
{Number: 1},
|
||||
},
|
||||
pipelines: []*woodpecker.Pipeline{
|
||||
{Number: 1},
|
||||
{Number: 2},
|
||||
{Number: 3},
|
||||
},
|
||||
wantDelete: 2,
|
||||
mockDeleteError: &woodpecker.ClientError{
|
||||
StatusCode: 422,
|
||||
Message: "test error",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mockClient := mocks.NewClient(t)
|
||||
mockClient.On("RepoLookup", mock.Anything).Maybe().Return(&woodpecker.Repo{ID: tt.repoID}, nil)
|
||||
|
||||
mockClient.On("PipelineList", mock.Anything, mock.Anything).Return(func(_ int64, opt woodpecker.PipelineListOptions) ([]*woodpecker.Pipeline, error) {
|
||||
// Return keep pipelines for first call
|
||||
if opt.Before.IsZero() {
|
||||
if opt.Page == 1 {
|
||||
return tt.pipelinesKeep, nil
|
||||
}
|
||||
return []*woodpecker.Pipeline{}, nil
|
||||
}
|
||||
|
||||
// Return pipelines to purge for calls with Before filter
|
||||
if !opt.Before.IsZero() {
|
||||
if opt.Page == 1 {
|
||||
return tt.pipelines, nil
|
||||
}
|
||||
return []*woodpecker.Pipeline{}, nil
|
||||
}
|
||||
|
||||
return []*woodpecker.Pipeline{}, nil
|
||||
}).Maybe()
|
||||
|
||||
if tt.mockDeleteError != nil {
|
||||
mockClient.On("PipelineDelete", tt.repoID, mock.Anything).Return(tt.mockDeleteError)
|
||||
} else if tt.wantDelete > 0 {
|
||||
mockClient.On("PipelineDelete", tt.repoID, mock.Anything).Return(nil).Times(tt.wantDelete)
|
||||
}
|
||||
|
||||
command := pipelinePurgeCmd
|
||||
command.Writer = io.Discard
|
||||
command.Action = func(_ context.Context, c *cli.Command) error {
|
||||
err := pipelinePurge(c, mockClient)
|
||||
|
||||
if tt.wantErr != nil {
|
||||
assert.EqualError(t, err, tt.wantErr.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
_ = command.Run(context.Background(), tt.args)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -15,14 +15,15 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
)
|
||||
|
||||
var pipelineQueueCmd = &cli.Command{
|
||||
|
@ -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
|
||||
}
|
||||
|
|
|
@ -15,26 +15,27 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var pipelineInfoCmd = &cli.Command{
|
||||
Name: "info",
|
||||
Usage: "show pipeline details",
|
||||
var pipelineShowCmd = &cli.Command{
|
||||
Name: "show",
|
||||
Usage: "show pipeline information",
|
||||
ArgsUsage: "<repo-id|repo-full-name> [pipeline]",
|
||||
Action: pipelineInfo,
|
||||
Action: pipelineShow,
|
||||
Flags: common.OutputFlags("table"),
|
||||
}
|
||||
|
||||
func pipelineInfo(c *cli.Context) error {
|
||||
func pipelineShow(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
|
||||
}
|
||||
|
@ -47,7 +48,7 @@ func pipelineInfo(c *cli.Context) error {
|
|||
var number int64
|
||||
if pipelineArg == "last" || len(pipelineArg) == 0 {
|
||||
// Fetch the pipeline number from the last pipeline
|
||||
pipeline, err := client.PipelineLast(repoID, "")
|
||||
pipeline, err := client.PipelineLast(repoID, woodpecker.PipelineLastOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -64,5 +65,5 @@ func pipelineInfo(c *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
return pipelineOutput(c, []woodpecker.Pipeline{*pipeline})
|
||||
return pipelineOutput(c, []*woodpecker.Pipeline{pipeline})
|
||||
}
|
|
@ -15,13 +15,15 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var pipelineStartCmd = &cli.Command{
|
||||
|
@ -33,14 +35,14 @@ var pipelineStartCmd = &cli.Command{
|
|||
&cli.StringSliceFlag{
|
||||
Name: "param",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "custom parameters to be injected into the step environment. Format: KEY=value",
|
||||
Usage: "custom parameters to inject into the step environment. Format: KEY=value",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -53,7 +55,7 @@ func pipelineStart(c *cli.Context) (err error) {
|
|||
var number int64
|
||||
if pipelineArg == "last" {
|
||||
// Fetch the pipeline number from the last pipeline
|
||||
pipeline, err := client.PipelineLast(repoID, "")
|
||||
pipeline, err := client.PipelineLast(repoID, woodpecker.PipelineLastOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -68,9 +70,11 @@ func pipelineStart(c *cli.Context) (err error) {
|
|||
}
|
||||
}
|
||||
|
||||
params := internal.ParseKeyPair(c.StringSlice("param"))
|
||||
opt := woodpecker.PipelineStartOptions{
|
||||
Params: internal.ParseKeyPair(c.StringSlice("param")),
|
||||
}
|
||||
|
||||
pipeline, err := client.PipelineStart(repoID, number, params)
|
||||
pipeline, err := client.PipelineStart(repoID, number, opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,12 +15,13 @@
|
|||
package pipeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
)
|
||||
|
||||
var pipelineStopCmd = &cli.Command{
|
||||
|
@ -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
|
||||
}
|
||||
|
|
|
@ -15,18 +15,18 @@
|
|||
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,
|
||||
cronInfoCmd,
|
||||
cronListCmd,
|
||||
cronShowCmd,
|
||||
cronUpdateCmd,
|
||||
},
|
||||
}
|
|
@ -15,14 +15,15 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var cronCreateCmd = &cli.Command{
|
||||
|
@ -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,
|
||||
}
|
|
@ -15,13 +15,15 @@
|
|||
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"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var cronListCmd = &cli.Command{
|
||||
|
@ -35,7 +37,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 +45,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
|
||||
}
|
||||
|
@ -51,7 +53,8 @@ func cronList(c *cli.Context) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
list, err := client.CronList(repoID)
|
||||
opt := woodpecker.CronListOptions{}
|
||||
list, err := client.CronList(repoID, opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue