mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-02-12 17:35:15 +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",
|
"en_us",
|
||||||
// code
|
// code
|
||||||
"go",
|
"go",
|
||||||
"node",
|
"node"
|
||||||
// package names
|
|
||||||
"npm"
|
|
||||||
],
|
],
|
||||||
"words": [
|
"words": [
|
||||||
"abool",
|
"abool",
|
||||||
|
"addgroup",
|
||||||
|
"adduser",
|
||||||
"anbraten",
|
"anbraten",
|
||||||
"antfu",
|
"antfu",
|
||||||
"apimachinery",
|
"apimachinery",
|
||||||
|
"appleboy",
|
||||||
|
"Archlinux",
|
||||||
"autoincr",
|
"autoincr",
|
||||||
|
"automerge",
|
||||||
"autoscaler",
|
"autoscaler",
|
||||||
|
"backporting",
|
||||||
|
"backports",
|
||||||
"binutils",
|
"binutils",
|
||||||
"bitbucketdatacenter",
|
"bitbucketdatacenter",
|
||||||
"Boguslawski",
|
"Boguslawski",
|
||||||
"bradrydzewski",
|
"bradrydzewski",
|
||||||
"BUILDPLATFORM",
|
"BUILDPLATFORM",
|
||||||
"buildx",
|
"buildx",
|
||||||
|
"caddyfile",
|
||||||
"ccmenu",
|
"ccmenu",
|
||||||
"certmagic",
|
"certmagic",
|
||||||
"charmbracelet",
|
"charmbracelet",
|
||||||
|
"cicd",
|
||||||
"ciphertext",
|
"ciphertext",
|
||||||
|
"Cloudron",
|
||||||
"Codeberg",
|
"Codeberg",
|
||||||
"compatiblelicenses",
|
"compatiblelicenses",
|
||||||
"corepack",
|
"corepack",
|
||||||
"cpuset",
|
"cpuset",
|
||||||
"creativecommons",
|
"creativecommons",
|
||||||
"Curr",
|
"Curr",
|
||||||
|
"CERTDIR",
|
||||||
"datacenter",
|
"datacenter",
|
||||||
"DATASOURCE",
|
"DATASOURCE",
|
||||||
"Debugf",
|
"Debugf",
|
||||||
"desaturate",
|
"desaturate",
|
||||||
"devx",
|
"devx",
|
||||||
|
"dind",
|
||||||
|
"Dockle",
|
||||||
"doublestar",
|
"doublestar",
|
||||||
|
"emojify",
|
||||||
"envsubst",
|
"envsubst",
|
||||||
"errgroup",
|
"errgroup",
|
||||||
"estree",
|
"estree",
|
||||||
|
@ -46,64 +58,90 @@
|
||||||
"excalidraw",
|
"excalidraw",
|
||||||
"favicons",
|
"favicons",
|
||||||
"Fediverse",
|
"Fediverse",
|
||||||
|
"Feishu",
|
||||||
"Fogas",
|
"Fogas",
|
||||||
"forbidigo",
|
"forbidigo",
|
||||||
"Forgejo",
|
"Forgejo",
|
||||||
"fsnotify",
|
"fsnotify",
|
||||||
|
"Geeklab",
|
||||||
"Georgiana",
|
"Georgiana",
|
||||||
"gitea",
|
"gitea",
|
||||||
|
"gitmodules",
|
||||||
"GOARCH",
|
"GOARCH",
|
||||||
"GOBIN",
|
"GOBIN",
|
||||||
"gocritic",
|
"gocritic",
|
||||||
"GODEBUG",
|
"GODEBUG",
|
||||||
|
"godoc",
|
||||||
|
"Gogs",
|
||||||
"golangci",
|
"golangci",
|
||||||
"gomod",
|
"gomod",
|
||||||
"gonic",
|
"gonic",
|
||||||
"GOPATH",
|
"GOPATH",
|
||||||
|
"Gource",
|
||||||
|
"handlebargh",
|
||||||
"HEALTHCHECK",
|
"HEALTHCHECK",
|
||||||
"healthz",
|
"healthz",
|
||||||
"Hetzner",
|
"Hetzner",
|
||||||
|
"HETZNERCLOUD",
|
||||||
|
"homelab",
|
||||||
"HTMLURL",
|
"HTMLURL",
|
||||||
"HTTPFS",
|
"HTTPFS",
|
||||||
"httpsig",
|
"httpsign",
|
||||||
"HTTPURL",
|
"HTTPURL",
|
||||||
"httputil",
|
"httputil",
|
||||||
"ianvs",
|
"ianvs",
|
||||||
"iconify",
|
"iconify",
|
||||||
|
"inetutils",
|
||||||
|
"Infima",
|
||||||
"Infof",
|
"Infof",
|
||||||
"Informatyka",
|
"Informatyka",
|
||||||
"intlify",
|
"intlify",
|
||||||
"Ionescu",
|
"Ionescu",
|
||||||
|
"Jetpack",
|
||||||
"Kaniko",
|
"Kaniko",
|
||||||
"Keyfunc",
|
"Keyfunc",
|
||||||
"kyvg",
|
"kyvg",
|
||||||
"LASTEXITCODE",
|
"LASTEXITCODE",
|
||||||
"Laszlo",
|
"Laszlo",
|
||||||
"laszlocph",
|
"laszlocph",
|
||||||
|
"letsencrypt",
|
||||||
|
"loadbalancer",
|
||||||
"logfile",
|
"logfile",
|
||||||
"loglevel",
|
"loglevel",
|
||||||
"LONGBLOB",
|
"LONGBLOB",
|
||||||
"LONGTEXT",
|
"LONGTEXT",
|
||||||
|
"lonix1",
|
||||||
"mapstructure",
|
"mapstructure",
|
||||||
"markdownlint",
|
"markdownlint",
|
||||||
|
"mdbook",
|
||||||
"memswap",
|
"memswap",
|
||||||
"Metas",
|
"Metas",
|
||||||
"mhmxs",
|
"mhmxs",
|
||||||
"moby",
|
"moby",
|
||||||
"Msgf",
|
"Msgf",
|
||||||
|
"mstruebing",
|
||||||
"multiarch",
|
"multiarch",
|
||||||
"multierr",
|
"multierr",
|
||||||
"netdns",
|
"netdns",
|
||||||
"Netrc",
|
"Netrc",
|
||||||
|
"Nextcloud",
|
||||||
"nfpm",
|
"nfpm",
|
||||||
"nixos",
|
"nixos",
|
||||||
|
"nixpkgs",
|
||||||
"nocolor",
|
"nocolor",
|
||||||
"nolint",
|
"nolint",
|
||||||
"norunningpipelines",
|
"norunningpipelines",
|
||||||
"nosniff",
|
"nosniff",
|
||||||
|
"ntfy",
|
||||||
"octocat",
|
"octocat",
|
||||||
|
"openapi",
|
||||||
|
"opensource",
|
||||||
|
"Pacman",
|
||||||
|
"picus",
|
||||||
"Pinia",
|
"Pinia",
|
||||||
"pkce",
|
"pkce",
|
||||||
|
"pnpx",
|
||||||
|
"Polyform",
|
||||||
"posix",
|
"posix",
|
||||||
"ppid",
|
"ppid",
|
||||||
"Println",
|
"Println",
|
||||||
|
@ -123,19 +161,26 @@
|
||||||
"repology",
|
"repology",
|
||||||
"reslimit",
|
"reslimit",
|
||||||
"Reviewdog",
|
"Reviewdog",
|
||||||
|
"Rieter",
|
||||||
"riscv",
|
"riscv",
|
||||||
"rundll32",
|
"rundll32",
|
||||||
"Rydzewski",
|
"Rydzewski",
|
||||||
"seccomp",
|
"seccomp",
|
||||||
"secprofile",
|
"secprofile",
|
||||||
"securecookie",
|
"securecookie",
|
||||||
|
"selfhosted",
|
||||||
"sess",
|
"sess",
|
||||||
"shellescape",
|
"shellescape",
|
||||||
|
"sigstore",
|
||||||
|
"Sonatype",
|
||||||
"SSHURL",
|
"SSHURL",
|
||||||
|
"sslmode",
|
||||||
"stepbuilder",
|
"stepbuilder",
|
||||||
"stretchr",
|
"stretchr",
|
||||||
|
"structs",
|
||||||
"sublicensable",
|
"sublicensable",
|
||||||
"swaggo",
|
"swaggo",
|
||||||
|
"syscalls",
|
||||||
"TARGETARCH",
|
"TARGETARCH",
|
||||||
"TARGETOS",
|
"TARGETOS",
|
||||||
"techknowlogick",
|
"techknowlogick",
|
||||||
|
@ -143,38 +188,49 @@
|
||||||
"threadcreate",
|
"threadcreate",
|
||||||
"tink",
|
"tink",
|
||||||
"tinycolor",
|
"tinycolor",
|
||||||
|
"tmole",
|
||||||
"tmpfs",
|
"tmpfs",
|
||||||
"tmpl",
|
"tmpl",
|
||||||
"tolerations",
|
"tolerations",
|
||||||
|
"Traefik",
|
||||||
"tseslint",
|
"tseslint",
|
||||||
"ttlcache",
|
"ttlcache",
|
||||||
|
"TUNEIT",
|
||||||
|
"Tunnelmole",
|
||||||
"typecheck",
|
"typecheck",
|
||||||
"Typeflag",
|
"Typeflag",
|
||||||
"unplugin",
|
"unplugin",
|
||||||
"Upsert",
|
"Upsert",
|
||||||
"urfave",
|
"urfave",
|
||||||
|
"usecase",
|
||||||
"varchar",
|
"varchar",
|
||||||
"varz",
|
"varz",
|
||||||
|
"Vieter",
|
||||||
|
"virtualisation",
|
||||||
|
"visualisation",
|
||||||
|
"vite",
|
||||||
"vueuse",
|
"vueuse",
|
||||||
"waivable",
|
"waivable",
|
||||||
"Warnf",
|
"Warnf",
|
||||||
|
"webhookd",
|
||||||
"Weblate",
|
"Weblate",
|
||||||
"windi",
|
"windi",
|
||||||
"windicss",
|
"windicss",
|
||||||
"woodpeckerci",
|
"woodpeckerci",
|
||||||
"WORKDIR",
|
"WORKDIR",
|
||||||
"Wrapf",
|
"Wrapf",
|
||||||
|
"x-enum-varnames",
|
||||||
"xlink",
|
"xlink",
|
||||||
"xlog",
|
"xlog",
|
||||||
"xorm",
|
"xorm",
|
||||||
"xormigrate",
|
"xormigrate",
|
||||||
"xyaml",
|
"xyaml",
|
||||||
"yamls",
|
"yamls",
|
||||||
|
"Yuno",
|
||||||
"zerolog",
|
"zerolog",
|
||||||
"zerologger"
|
"zerologger"
|
||||||
],
|
],
|
||||||
"ignorePaths": [
|
"ignorePaths": [
|
||||||
"**/node_modules/**/*",
|
|
||||||
"*.excalidraw",
|
"*.excalidraw",
|
||||||
"*.svg",
|
"*.svg",
|
||||||
"*_test.go",
|
"*_test.go",
|
||||||
|
@ -185,19 +241,26 @@
|
||||||
".vscode/extensions.json",
|
".vscode/extensions.json",
|
||||||
"CHANGELOG.md",
|
"CHANGELOG.md",
|
||||||
"Makefile",
|
"Makefile",
|
||||||
"flake.lock",
|
|
||||||
"flake.nix",
|
"flake.nix",
|
||||||
"go.mod",
|
"go.mod",
|
||||||
"go.sum",
|
"**/*.pb.go",
|
||||||
"pipeline/rpc/proto/woodpecker.pb.go",
|
|
||||||
"pnpm-lock.yaml",
|
|
||||||
"server/store/datastore/migration/**/*",
|
"server/store/datastore/migration/**/*",
|
||||||
"web/components.d.ts",
|
"web/components.d.ts",
|
||||||
"web/src/assets/locales/**/*",
|
"web/src/assets/locales/**/*",
|
||||||
"**/fixtures/**",
|
"**/fixtures/**",
|
||||||
"**/testdata/**",
|
"**/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
|
// TODO: remove the following
|
||||||
"docs/"
|
"docs/**/*.js",
|
||||||
|
"docs/**/*.ts"
|
||||||
],
|
],
|
||||||
// Exclude imports, because they are also strings.
|
// Exclude imports, because they are also strings.
|
||||||
"ignoreRegExpList": [
|
"ignoreRegExpList": [
|
||||||
|
@ -210,7 +273,9 @@
|
||||||
// ignore nolint directive
|
// ignore nolint directive
|
||||||
"//\\s*nolint:.*",
|
"//\\s*nolint:.*",
|
||||||
// ignore docker image names
|
// ignore docker image names
|
||||||
"\\s*docker\\.io/.*"
|
"\\s*docker\\.io/.*",
|
||||||
|
// ignore inline svg in css
|
||||||
|
"\\s*url\\(\"data:image/svg\\+xml.*"
|
||||||
],
|
],
|
||||||
"enableFiletypes": ["dockercompose"]
|
"enableFiletypes": ["dockercompose"]
|
||||||
}
|
}
|
||||||
|
|
5
.ecrc
5
.ecrc
|
@ -1,14 +1,15 @@
|
||||||
{
|
{
|
||||||
"Exclude": [
|
"Exclude": [
|
||||||
".git",
|
".git",
|
||||||
"go.mod", "go.sum",
|
"go.mod",
|
||||||
|
"go.sum",
|
||||||
"vendor",
|
"vendor",
|
||||||
"fixtures",
|
"fixtures",
|
||||||
"LICENSE",
|
"LICENSE",
|
||||||
"node_modules",
|
"node_modules",
|
||||||
"server/store/datastore/migration/test-files/sqlite.db",
|
"server/store/datastore/migration/test-files/sqlite.db",
|
||||||
"server/store/datastore/feed.go",
|
"server/store/datastore/feed.go",
|
||||||
"cmd/server/docs/docs.go",
|
"cmd/server/openapi/docs.go",
|
||||||
"_test.go",
|
"_test.go",
|
||||||
"Makefile"
|
"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",
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
"extends": ["github>woodpecker-ci/renovate-config"],
|
"extends": ["github>woodpecker-ci/renovate-config"],
|
||||||
|
"automergeType": "pr",
|
||||||
"customManagers": [
|
"customManagers": [
|
||||||
{
|
{
|
||||||
"customType": "regex",
|
"customType": "regex",
|
||||||
"fileMatch": ["shared/constant/constant.go"],
|
"fileMatch": ["shared/constant/constant.go"],
|
||||||
"matchStrings": [
|
"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}}"
|
"versioningTemplate": "{{#if versioning}}{{{versioning}}}{{else}}semver{{/if}}"
|
||||||
}
|
}
|
||||||
|
@ -29,8 +30,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"groupName": "golang-lang",
|
"groupName": "golang-lang",
|
||||||
"matchPackagePatterns": ["^golang$", "xgo"],
|
"matchUpdateTypes": ["minor", "patch"],
|
||||||
"matchUpdateTypes": ["minor", "patch"]
|
"matchPackageNames": ["/^golang$/", "/xgo/"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"groupName": "golang-packages",
|
"groupName": "golang-packages",
|
||||||
|
@ -60,9 +61,10 @@
|
||||||
"matchFileNames": ["docs/**/package.json"]
|
"matchFileNames": ["docs/**/package.json"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"description": "Extract version from xgo container tags",
|
||||||
"matchDatasources": ["docker"],
|
"matchDatasources": ["docker"],
|
||||||
"matchPackagePatterns": ["xgo"],
|
"versioning": "regex:^go-(?<major>\\d+)\\.(?<minor>\\d+)\\.x$",
|
||||||
"versioning": "regex:^go-(?<major>\\d+)?(\\.(?<minor>\\d+))?(\\.(?<patch>\\d+))$"
|
"matchPackageNames": ["/techknowlogick/xgo/"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -51,4 +51,7 @@ docs/venv
|
||||||
|
|
||||||
### Generated by CI ###
|
### Generated by CI ###
|
||||||
docs/docs/40-cli.md
|
docs/docs/40-cli.md
|
||||||
|
docs/openapi.json
|
||||||
|
|
||||||
|
# Removed once v3.0.x is minimum version to be touched
|
||||||
docs/swagger.json
|
docs/swagger.json
|
||||||
|
|
|
@ -112,9 +112,10 @@ vscode:
|
||||||
- 'EditorConfig.EditorConfig'
|
- 'EditorConfig.EditorConfig'
|
||||||
- 'dbaeumer.vscode-eslint'
|
- 'dbaeumer.vscode-eslint'
|
||||||
- 'esbenp.prettier-vscode'
|
- 'esbenp.prettier-vscode'
|
||||||
- 'voorjaar.windicss-intellisense'
|
- 'bradlc.vscode-tailwindcss'
|
||||||
- 'Vue.volar'
|
- 'Vue.volar'
|
||||||
- 'redhat.vscode-yaml'
|
- 'redhat.vscode-yaml'
|
||||||
- 'davidanson.vscode-markdownlint'
|
- 'davidanson.vscode-markdownlint'
|
||||||
- 'streetsidesoftware.code-spell-checker'
|
- 'streetsidesoftware.code-spell-checker'
|
||||||
|
- 'stivo.tailwind-fold'
|
||||||
# cSpell:enable
|
# 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-hooks-apply
|
||||||
- id: check-useless-excludes
|
- id: check-useless-excludes
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.6.0
|
rev: v5.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- repo: https://github.com/golangci/golangci-lint
|
- repo: https://github.com/golangci/golangci-lint
|
||||||
rev: v1.59.1
|
rev: v1.63.4
|
||||||
hooks:
|
hooks:
|
||||||
- id: golangci-lint
|
- id: golangci-lint
|
||||||
- repo: https://github.com/igorshubovych/markdownlint-cli
|
- repo: https://github.com/igorshubovych/markdownlint-cli
|
||||||
rev: v0.41.0
|
rev: v0.43.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: markdownlint
|
- id: markdownlint
|
||||||
exclude: '^(docs/versioned_docs/.*|CHANGELOG.md)$'
|
exclude: '^(docs/versioned_docs/.*|CHANGELOG.md)$'
|
||||||
|
@ -24,11 +24,11 @@ repos:
|
||||||
- id: checkmake
|
- id: checkmake
|
||||||
exclude: '^docker/Dockerfile.make$' # actually a Dockerfile and not a makefile
|
exclude: '^docker/Dockerfile.make$' # actually a Dockerfile and not a makefile
|
||||||
- repo: https://github.com/hadolint/hadolint
|
- repo: https://github.com/hadolint/hadolint
|
||||||
rev: v2.13.0-beta
|
rev: v2.13.1-beta
|
||||||
hooks:
|
hooks:
|
||||||
- id: hadolint
|
- id: hadolint
|
||||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
- repo: https://github.com/rbubley/mirrors-prettier
|
||||||
rev: v4.0.0-alpha.8
|
rev: v3.4.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: prettier
|
- id: prettier
|
||||||
- repo: https://github.com/adrienverge/yamllint.git
|
- repo: https://github.com/adrienverge/yamllint.git
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
build/
|
build/
|
||||||
docs/versioned_docs/
|
|
||||||
docs/.docusaurus/
|
|
||||||
docs/pnpm-lock.yaml
|
|
||||||
dist/
|
dist/
|
||||||
CHANGELOG.md
|
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
|
# to prevent conflicts with different prettier version
|
||||||
web/
|
web/
|
||||||
|
docs/
|
||||||
|
|
5
.vscode/extensions.json
vendored
5
.vscode/extensions.json
vendored
|
@ -5,10 +5,11 @@
|
||||||
"EditorConfig.EditorConfig",
|
"EditorConfig.EditorConfig",
|
||||||
"dbaeumer.vscode-eslint",
|
"dbaeumer.vscode-eslint",
|
||||||
"esbenp.prettier-vscode",
|
"esbenp.prettier-vscode",
|
||||||
"voorjaar.windicss-intellisense",
|
"bradlc.vscode-tailwindcss",
|
||||||
"Vue.volar",
|
"Vue.volar",
|
||||||
"redhat.vscode-yaml",
|
"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.
|
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
||||||
"unwantedRecommendations": []
|
"unwantedRecommendations": []
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
when:
|
when:
|
||||||
event: tag
|
- event: tag
|
||||||
|
- event: pull_request
|
||||||
|
branch: ${CI_REPO_DEFAULT_BRANCH}
|
||||||
|
path:
|
||||||
|
- Makefile
|
||||||
|
- .woodpecker/binaries.yaml
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
- &golang_image 'docker.io/golang:1.22'
|
- &golang_image 'docker.io/golang:1.23'
|
||||||
- &node_image 'docker.io/node:22-alpine'
|
- &node_image 'docker.io/node:23-alpine'
|
||||||
- &xgo_image 'docker.io/techknowlogick/xgo:go-1.22.x'
|
- &xgo_image 'docker.io/techknowlogick/xgo:go-1.23.x'
|
||||||
|
|
||||||
# cspell:words bindata netgo TARGZ
|
# cspell:words bindata netgo
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
build-web:
|
build-web:
|
||||||
|
@ -35,7 +40,7 @@ steps:
|
||||||
environment:
|
environment:
|
||||||
PLATFORMS: linux|arm64/v8;linux|amd64;windows|amd64
|
PLATFORMS: linux|arm64/v8;linux|amd64;windows|amd64
|
||||||
TAGS: bindata sqlite sqlite_unlock_notify netgo
|
TAGS: bindata sqlite sqlite_unlock_notify netgo
|
||||||
TARGZ: '1'
|
ARCHIVE_IT: '1'
|
||||||
|
|
||||||
build-tarball:
|
build-tarball:
|
||||||
depends_on:
|
depends_on:
|
||||||
|
@ -50,6 +55,8 @@ steps:
|
||||||
- vendor
|
- vendor
|
||||||
image: *golang_image
|
image: *golang_image
|
||||||
commands:
|
commands:
|
||||||
|
- apt update
|
||||||
|
- apt install -y zip
|
||||||
- make release-agent
|
- make release-agent
|
||||||
|
|
||||||
build-cli:
|
build-cli:
|
||||||
|
@ -57,6 +64,8 @@ steps:
|
||||||
- vendor
|
- vendor
|
||||||
image: *golang_image
|
image: *golang_image
|
||||||
commands:
|
commands:
|
||||||
|
- apt update
|
||||||
|
- apt install -y zip
|
||||||
- make release-cli
|
- make release-cli
|
||||||
|
|
||||||
build-deb-rpm:
|
build-deb-rpm:
|
||||||
|
@ -90,13 +99,16 @@ steps:
|
||||||
release:
|
release:
|
||||||
depends_on:
|
depends_on:
|
||||||
- checksums
|
- checksums
|
||||||
image: woodpeckerci/plugin-release:0.1.0
|
image: woodpeckerci/plugin-release:0.2.2
|
||||||
settings:
|
settings:
|
||||||
api_key:
|
api_key:
|
||||||
from_secret: github_token
|
from_secret: github_token
|
||||||
files:
|
files:
|
||||||
- dist/*.tar.gz
|
- dist/*.tar.gz
|
||||||
|
- dist/*.zip
|
||||||
- dist/*.deb
|
- dist/*.deb
|
||||||
- dist/*.rpm
|
- dist/*.rpm
|
||||||
- dist/checksums.txt
|
- dist/checksums.txt
|
||||||
title: ${CI_COMMIT_TAG##v}
|
title: ${CI_COMMIT_TAG##v}
|
||||||
|
when:
|
||||||
|
event: tag
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
variables:
|
variables:
|
||||||
- &golang_image 'docker.io/golang:1.22'
|
- &golang_image 'docker.io/golang:1.23'
|
||||||
- &node_image 'docker.io/node:22-alpine'
|
- &node_image 'docker.io/node:23-alpine'
|
||||||
- &xgo_image 'docker.io/techknowlogick/xgo:go-1.22.x'
|
- &xgo_image 'docker.io/techknowlogick/xgo:go-1.23.x'
|
||||||
- &buildx_plugin 'docker.io/woodpeckerci/plugin-docker-buildx:4.0.0'
|
- &buildx_plugin 'docker.io/woodpeckerci/plugin-docker-buildx:5.1.0'
|
||||||
- &platforms_release 'linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/386,linux/amd64,linux/ppc64le,linux/riscv64,linux/s390x,freebsd/arm64,freebsd/amd64,openbsd/arm64,openbsd/amd64'
|
- &platforms_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_server 'linux/arm/v7,linux/arm64/v8,linux/amd64,linux/ppc64le,linux/riscv64'
|
||||||
- &platforms_preview 'linux/amd64'
|
- &platforms_preview 'linux/amd64'
|
||||||
- &platforms_alpine 'linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/amd64,linux/ppc64le'
|
- &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}'
|
- &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
|
# vars used on push / tag events only
|
||||||
- publish_logins: &publish_logins # Default DockerHub login
|
- publish_logins: &publish_logins # Default DockerHub login
|
||||||
|
@ -41,9 +41,6 @@ variables:
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- event: [pull_request, tag]
|
- event: [pull_request, tag]
|
||||||
- event: push
|
|
||||||
branch:
|
|
||||||
- renovate/*
|
|
||||||
- event: push
|
- event: push
|
||||||
branch: ${CI_REPO_DEFAULT_BRANCH}
|
branch: ${CI_REPO_DEFAULT_BRANCH}
|
||||||
path: *when_path
|
path: *when_path
|
||||||
|
@ -61,7 +58,6 @@ steps:
|
||||||
path: *when_path
|
path: *when_path
|
||||||
- branch:
|
- branch:
|
||||||
- ${CI_REPO_DEFAULT_BRANCH}
|
- ${CI_REPO_DEFAULT_BRANCH}
|
||||||
- renovate/*
|
|
||||||
event: [push, tag]
|
event: [push, tag]
|
||||||
path: *when_path
|
path: *when_path
|
||||||
|
|
||||||
|
@ -82,7 +78,6 @@ steps:
|
||||||
path: *when_path
|
path: *when_path
|
||||||
- branch:
|
- branch:
|
||||||
- ${CI_REPO_DEFAULT_BRANCH}
|
- ${CI_REPO_DEFAULT_BRANCH}
|
||||||
- renovate/*
|
|
||||||
event: [push, tag]
|
event: [push, tag]
|
||||||
path: *when_path
|
path: *when_path
|
||||||
|
|
||||||
|
@ -104,9 +99,6 @@ steps:
|
||||||
evaluate: 'CI_COMMIT_PULL_REQUEST_LABELS contains "build_pr_images"'
|
evaluate: 'CI_COMMIT_PULL_REQUEST_LABELS contains "build_pr_images"'
|
||||||
- event: pull_request
|
- event: pull_request
|
||||||
path: *when_path
|
path: *when_path
|
||||||
- event: push
|
|
||||||
path: *when_path
|
|
||||||
branch: renovate/*
|
|
||||||
|
|
||||||
cross-compile-server:
|
cross-compile-server:
|
||||||
depends_on:
|
depends_on:
|
||||||
|
@ -127,31 +119,19 @@ steps:
|
||||||
event: [push, tag]
|
event: [push, tag]
|
||||||
path: *when_path
|
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:
|
publish-server-alpine-preview:
|
||||||
depends_on:
|
depends_on:
|
||||||
- cross-compile-server-preview
|
- cross-compile-server-preview
|
||||||
image: *buildx_plugin
|
image: *buildx_plugin
|
||||||
settings:
|
settings:
|
||||||
repo: woodpeckerci/woodpecker-server
|
repo: woodpeckerci/woodpecker-server
|
||||||
dockerfile: docker/Dockerfile.server.alpine.multiarch
|
dockerfile: docker/Dockerfile.server.alpine.multiarch.rootless
|
||||||
platforms: *platforms_preview
|
platforms: *platforms_preview
|
||||||
tag: pull_${CI_COMMIT_PULL_REQUEST}-alpine
|
tag: pull_${CI_COMMIT_PULL_REQUEST}-alpine
|
||||||
logins: *publish_logins
|
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:
|
build-server-dryrun:
|
||||||
depends_on:
|
depends_on:
|
||||||
|
@ -162,16 +142,13 @@ steps:
|
||||||
settings:
|
settings:
|
||||||
dry_run: true
|
dry_run: true
|
||||||
repo: woodpeckerci/woodpecker-server
|
repo: woodpeckerci/woodpecker-server
|
||||||
dockerfile: docker/Dockerfile.server.multiarch
|
dockerfile: docker/Dockerfile.server.multiarch.rootless
|
||||||
platforms: *platforms_preview
|
platforms: *platforms_preview
|
||||||
tag: pull_${CI_COMMIT_PULL_REQUEST}
|
tag: pull_${CI_COMMIT_PULL_REQUEST}
|
||||||
when: &when-dryrun
|
when: &when-dryrun
|
||||||
- evaluate: 'not (CI_COMMIT_PULL_REQUEST_LABELS contains "build_pr_images")'
|
- evaluate: 'not (CI_COMMIT_PULL_REQUEST_LABELS contains "build_pr_images")'
|
||||||
event: pull_request
|
event: pull_request
|
||||||
path: *when_path
|
path: *when_path
|
||||||
- event: push
|
|
||||||
path: *when_path
|
|
||||||
branch: renovate/*
|
|
||||||
|
|
||||||
publish-next-server:
|
publish-next-server:
|
||||||
depends_on:
|
depends_on:
|
||||||
|
@ -179,7 +156,7 @@ steps:
|
||||||
image: *buildx_plugin
|
image: *buildx_plugin
|
||||||
settings:
|
settings:
|
||||||
repo: *publish_repos_server
|
repo: *publish_repos_server
|
||||||
dockerfile: docker/Dockerfile.server.multiarch
|
dockerfile: docker/Dockerfile.server.multiarch.rootless
|
||||||
platforms: *platforms_server
|
platforms: *platforms_server
|
||||||
tag: [next, 'next-${CI_COMMIT_SHA:0:10}']
|
tag: [next, 'next-${CI_COMMIT_SHA:0:10}']
|
||||||
logins: *publish_logins
|
logins: *publish_logins
|
||||||
|
@ -194,7 +171,7 @@ steps:
|
||||||
image: *buildx_plugin
|
image: *buildx_plugin
|
||||||
settings:
|
settings:
|
||||||
repo: *publish_repos_server
|
repo: *publish_repos_server
|
||||||
dockerfile: docker/Dockerfile.server.alpine.multiarch
|
dockerfile: docker/Dockerfile.server.alpine.multiarch.rootless
|
||||||
platforms: *platforms_alpine
|
platforms: *platforms_alpine
|
||||||
tag: [next-alpine, 'next-${CI_COMMIT_SHA:0:10}-alpine']
|
tag: [next-alpine, 'next-${CI_COMMIT_SHA:0:10}-alpine']
|
||||||
logins: *publish_logins
|
logins: *publish_logins
|
||||||
|
@ -206,10 +183,9 @@ steps:
|
||||||
image: *buildx_plugin
|
image: *buildx_plugin
|
||||||
settings:
|
settings:
|
||||||
repo: *publish_repos_server
|
repo: *publish_repos_server
|
||||||
dockerfile: docker/Dockerfile.server.multiarch
|
dockerfile: docker/Dockerfile.server.multiarch.rootless
|
||||||
platforms: *platforms_server
|
platforms: *platforms_server
|
||||||
# remove 'latest' on older version branches to avoid accidental downgrade
|
tag: ['${CI_COMMIT_TAG%%.*}', '${CI_COMMIT_TAG%.*}-alpine', '${CI_COMMIT_TAG}']
|
||||||
tag: [latest, '${CI_COMMIT_TAG}']
|
|
||||||
logins: *publish_logins
|
logins: *publish_logins
|
||||||
when: &when-release
|
when: &when-release
|
||||||
event: tag
|
event: tag
|
||||||
|
@ -220,10 +196,9 @@ steps:
|
||||||
image: *buildx_plugin
|
image: *buildx_plugin
|
||||||
settings:
|
settings:
|
||||||
repo: *publish_repos_server
|
repo: *publish_repos_server
|
||||||
dockerfile: docker/Dockerfile.server.alpine.multiarch
|
dockerfile: docker/Dockerfile.server.alpine.multiarch.rootless
|
||||||
platforms: *platforms_alpine
|
platforms: *platforms_alpine
|
||||||
# remove 'latest-alpine' on older version branches to avoid accidental downgrade
|
tag: ['${CI_COMMIT_TAG%%.*}-alpine', '${CI_COMMIT_TAG%.*}-alpine', '${CI_COMMIT_TAG}-alpine']
|
||||||
tag: [latest-alpine, '${CI_COMMIT_TAG}-alpine']
|
|
||||||
logins: *publish_logins
|
logins: *publish_logins
|
||||||
when: *when-release
|
when: *when-release
|
||||||
|
|
||||||
|
@ -231,15 +206,15 @@ steps:
|
||||||
# A g e n t #
|
# A g e n t #
|
||||||
#############
|
#############
|
||||||
|
|
||||||
publish-agent-preview:
|
publish-agent-preview-alpine:
|
||||||
depends_on:
|
depends_on:
|
||||||
- vendor
|
- vendor
|
||||||
image: *buildx_plugin
|
image: *buildx_plugin
|
||||||
settings:
|
settings:
|
||||||
repo: woodpeckerci/woodpecker-agent
|
repo: woodpeckerci/woodpecker-agent
|
||||||
dockerfile: docker/Dockerfile.agent.multiarch
|
dockerfile: docker/Dockerfile.agent.alpine.multiarch
|
||||||
platforms: *platforms_preview
|
platforms: *platforms_preview
|
||||||
tag: pull_${CI_COMMIT_PULL_REQUEST}
|
tag: pull_${CI_COMMIT_PULL_REQUEST}-alpine
|
||||||
build_args: *build_args
|
build_args: *build_args
|
||||||
logins: *publish_logins
|
logins: *publish_logins
|
||||||
when: *when-preview
|
when: *when-preview
|
||||||
|
@ -303,8 +278,7 @@ steps:
|
||||||
repo: *publish_repos_agent
|
repo: *publish_repos_agent
|
||||||
dockerfile: docker/Dockerfile.agent.multiarch
|
dockerfile: docker/Dockerfile.agent.multiarch
|
||||||
platforms: *platforms_release
|
platforms: *platforms_release
|
||||||
# remove 'latest' on older version branches to avoid accidental downgrade
|
tag: ['${CI_COMMIT_TAG%%.*}', '${CI_COMMIT_TAG%.*}', '${CI_COMMIT_TAG}']
|
||||||
tag: [latest, '${CI_COMMIT_TAG}']
|
|
||||||
logins: *publish_logins
|
logins: *publish_logins
|
||||||
build_args: *build_args
|
build_args: *build_args
|
||||||
when: *when-release
|
when: *when-release
|
||||||
|
@ -320,8 +294,7 @@ steps:
|
||||||
repo: *publish_repos_agent
|
repo: *publish_repos_agent
|
||||||
dockerfile: docker/Dockerfile.agent.alpine.multiarch
|
dockerfile: docker/Dockerfile.agent.alpine.multiarch
|
||||||
platforms: *platforms_alpine
|
platforms: *platforms_alpine
|
||||||
# remove 'latest-alpine' on older version branches to avoid accidental downgrade
|
tag: ['${CI_COMMIT_TAG%%.*}-alpine', '${CI_COMMIT_TAG%.*}-alpine', '${CI_COMMIT_TAG}-alpine']
|
||||||
tag: [latest-alpine, '${CI_COMMIT_TAG}-alpine']
|
|
||||||
logins: *publish_logins
|
logins: *publish_logins
|
||||||
build_args: *build_args
|
build_args: *build_args
|
||||||
when: *when-release
|
when: *when-release
|
||||||
|
@ -330,19 +303,6 @@ steps:
|
||||||
# C L I #
|
# 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:
|
build-cli-dryrun:
|
||||||
depends_on:
|
depends_on:
|
||||||
- vendor
|
- vendor
|
||||||
|
@ -350,7 +310,7 @@ steps:
|
||||||
settings:
|
settings:
|
||||||
dry_run: true
|
dry_run: true
|
||||||
repo: woodpeckerci/woodpecker-cli
|
repo: woodpeckerci/woodpecker-cli
|
||||||
dockerfile: docker/Dockerfile.cli.multiarch
|
dockerfile: docker/Dockerfile.cli.multiarch.rootless
|
||||||
platforms: *platforms_preview
|
platforms: *platforms_preview
|
||||||
tag: pull_${CI_COMMIT_PULL_REQUEST}
|
tag: pull_${CI_COMMIT_PULL_REQUEST}
|
||||||
build_args: *build_args
|
build_args: *build_args
|
||||||
|
@ -365,7 +325,7 @@ steps:
|
||||||
image: *buildx_plugin
|
image: *buildx_plugin
|
||||||
settings:
|
settings:
|
||||||
repo: *publish_repos_cli
|
repo: *publish_repos_cli
|
||||||
dockerfile: docker/Dockerfile.cli.multiarch
|
dockerfile: docker/Dockerfile.cli.multiarch.rootless
|
||||||
platforms: *platforms_release
|
platforms: *platforms_release
|
||||||
tag: [next, 'next-${CI_COMMIT_SHA:0:10}']
|
tag: [next, 'next-${CI_COMMIT_SHA:0:10}']
|
||||||
logins: *publish_logins
|
logins: *publish_logins
|
||||||
|
@ -381,7 +341,7 @@ steps:
|
||||||
image: *buildx_plugin
|
image: *buildx_plugin
|
||||||
settings:
|
settings:
|
||||||
repo: *publish_repos_cli
|
repo: *publish_repos_cli
|
||||||
dockerfile: docker/Dockerfile.cli.alpine.multiarch
|
dockerfile: docker/Dockerfile.cli.alpine.multiarch.rootless
|
||||||
platforms: *platforms_alpine
|
platforms: *platforms_alpine
|
||||||
tag: [next-alpine, 'next-${CI_COMMIT_SHA:0:10}-alpine']
|
tag: [next-alpine, 'next-${CI_COMMIT_SHA:0:10}-alpine']
|
||||||
logins: *publish_logins
|
logins: *publish_logins
|
||||||
|
@ -397,10 +357,9 @@ steps:
|
||||||
image: *buildx_plugin
|
image: *buildx_plugin
|
||||||
settings:
|
settings:
|
||||||
repo: *publish_repos_cli
|
repo: *publish_repos_cli
|
||||||
dockerfile: docker/Dockerfile.cli.multiarch
|
dockerfile: docker/Dockerfile.cli.multiarch.rootless
|
||||||
platforms: *platforms_release
|
platforms: *platforms_release
|
||||||
# remove 'latest' on older version branches to avoid accidental downgrade
|
tag: ['${CI_COMMIT_TAG%%.*}', '${CI_COMMIT_TAG%.*}', '${CI_COMMIT_TAG}']
|
||||||
tag: [latest, '${CI_COMMIT_TAG}']
|
|
||||||
logins: *publish_logins
|
logins: *publish_logins
|
||||||
build_args: *build_args
|
build_args: *build_args
|
||||||
when: *when-release
|
when: *when-release
|
||||||
|
@ -414,10 +373,9 @@ steps:
|
||||||
image: *buildx_plugin
|
image: *buildx_plugin
|
||||||
settings:
|
settings:
|
||||||
repo: *publish_repos_cli
|
repo: *publish_repos_cli
|
||||||
dockerfile: docker/Dockerfile.cli.alpine.multiarch
|
dockerfile: docker/Dockerfile.cli.alpine.multiarch.rootless
|
||||||
platforms: *platforms_alpine
|
platforms: *platforms_alpine
|
||||||
# remove 'latest-alpine' on older version branches to avoid accidental downgrade
|
tag: ['${CI_COMMIT_TAG%%.*}-alpine', '${CI_COMMIT_TAG%.*}-alpine', '${CI_COMMIT_TAG}-alpine']
|
||||||
tag: [latest-alpine, '${CI_COMMIT_TAG}-alpine']
|
|
||||||
logins: *publish_logins
|
logins: *publish_logins
|
||||||
build_args: *build_args
|
build_args: *build_args
|
||||||
when: *when-release
|
when: *when-release
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
variables:
|
variables:
|
||||||
- &golang_image 'docker.io/golang:1.22'
|
- &golang_image 'docker.io/golang:1.23'
|
||||||
- &node_image 'docker.io/node:21-alpine'
|
- &node_image 'docker.io/node:23-alpine'
|
||||||
- &alpine_image 'docker.io/alpine:3.19'
|
- &alpine_image 'docker.io/alpine:3.21'
|
||||||
- path: &when_path
|
- path: &when_path
|
||||||
- 'docs/**'
|
- 'docs/**'
|
||||||
- '.woodpecker/docs.yaml'
|
- '.woodpecker/docs.yaml'
|
||||||
|
@ -31,13 +31,22 @@ when:
|
||||||
- <<: *docker_path
|
- <<: *docker_path
|
||||||
branch:
|
branch:
|
||||||
- ${CI_REPO_DEFAULT_BRANCH}
|
- ${CI_REPO_DEFAULT_BRANCH}
|
||||||
- renovate/*
|
|
||||||
- event: pull_request_closed
|
- event: pull_request_closed
|
||||||
path: *when_path
|
path: *when_path
|
||||||
- event: manual
|
- event: manual
|
||||||
evaluate: 'TASK == "docs"'
|
evaluate: 'TASK == "docs"'
|
||||||
|
|
||||||
steps:
|
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:
|
build-cli:
|
||||||
image: *golang_image
|
image: *golang_image
|
||||||
commands:
|
commands:
|
||||||
|
@ -60,7 +69,7 @@ steps:
|
||||||
- event: manual
|
- event: manual
|
||||||
|
|
||||||
deploy-preview:
|
deploy-preview:
|
||||||
image: docker.io/woodpeckerci/plugin-surge-preview:1.3.0
|
image: docker.io/woodpeckerci/plugin-surge-preview:1.3.3
|
||||||
settings:
|
settings:
|
||||||
path: 'docs/build/'
|
path: 'docs/build/'
|
||||||
surge_token:
|
surge_token:
|
||||||
|
@ -69,13 +78,14 @@ steps:
|
||||||
from_secret: GITHUB_TOKEN_SURGE
|
from_secret: GITHUB_TOKEN_SURGE
|
||||||
failure: ignore
|
failure: ignore
|
||||||
when:
|
when:
|
||||||
event: [pull_request, pull_request_closed]
|
- event: [pull_request, pull_request_closed]
|
||||||
path: *when_path
|
path: *when_path
|
||||||
|
|
||||||
deploy-prepare:
|
deploy-prepare:
|
||||||
image: *alpine_image
|
image: *alpine_image
|
||||||
secrets:
|
environment:
|
||||||
- BOT_PRIVATE_KEY
|
BOT_PRIVATE_KEY:
|
||||||
|
from_secret: BOT_PRIVATE_KEY
|
||||||
commands:
|
commands:
|
||||||
- apk add openssh-client git
|
- apk add openssh-client git
|
||||||
- mkdir -p $HOME/.ssh
|
- mkdir -p $HOME/.ssh
|
||||||
|
@ -127,8 +137,9 @@ steps:
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
image: *alpine_image
|
image: *alpine_image
|
||||||
secrets:
|
environment:
|
||||||
- BOT_PRIVATE_KEY
|
BOT_PRIVATE_KEY:
|
||||||
|
from_secret: BOT_PRIVATE_KEY
|
||||||
commands:
|
commands:
|
||||||
- apk add openssh-client rsync git
|
- apk add openssh-client rsync git
|
||||||
- mkdir -p $HOME/.ssh
|
- 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:
|
steps:
|
||||||
release-helper:
|
- name: release-helper
|
||||||
image: woodpeckerci/plugin-ready-release-go:1.1.2
|
image: docker.io/woodpeckerci/plugin-ready-release-go:3.1.1
|
||||||
pull: true
|
|
||||||
settings:
|
settings:
|
||||||
release_branch: ${CI_REPO_DEFAULT_BRANCH}
|
release_branch: ${CI_COMMIT_BRANCH}
|
||||||
forge_type: github
|
forge_type: github
|
||||||
git_email: woodpecker-bot@obermui.de
|
git_email: woodpecker-bot@obermui.de
|
||||||
github_token:
|
github_token:
|
||||||
from_secret: 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:
|
when:
|
||||||
- event: [pull_request, cron]
|
- event: [pull_request]
|
||||||
- event: push
|
- event: push
|
||||||
branch:
|
branch:
|
||||||
- ${CI_REPO_DEFAULT_BRANCH}
|
- ${CI_REPO_DEFAULT_BRANCH}
|
||||||
- renovate/*
|
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
- &trivy_plugin docker.io/woodpeckerci/plugin-trivy:1.1.0
|
- &trivy_plugin docker.io/woodpeckerci/plugin-trivy:1.3.0
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
backend:
|
backend:
|
||||||
depends_on: []
|
depends_on: []
|
||||||
image: *trivy_plugin
|
image: *trivy_plugin
|
||||||
settings:
|
settings:
|
||||||
|
server: server
|
||||||
skip-dirs: web/,docs/
|
skip-dirs: web/,docs/
|
||||||
|
|
||||||
docs:
|
docs:
|
||||||
depends_on: []
|
depends_on: []
|
||||||
image: *trivy_plugin
|
image: *trivy_plugin
|
||||||
settings:
|
settings:
|
||||||
|
server: server
|
||||||
skip-dirs: node_modules/,plugins/woodpecker-plugins/node_modules/
|
skip-dirs: node_modules/,plugins/woodpecker-plugins/node_modules/
|
||||||
dir: docs/
|
dir: docs/
|
||||||
|
|
||||||
|
@ -26,5 +27,15 @@ steps:
|
||||||
depends_on: []
|
depends_on: []
|
||||||
image: *trivy_plugin
|
image: *trivy_plugin
|
||||||
settings:
|
settings:
|
||||||
|
server: server
|
||||||
skip-dirs: node_modules/
|
skip-dirs: node_modules/
|
||||||
dir: web/
|
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:
|
when:
|
||||||
- event: pull_request
|
- event: pull_request
|
||||||
- event: push
|
|
||||||
branch: renovate/*
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: lint-editorconfig
|
- name: lint-editorconfig
|
||||||
image: docker.io/mstruebing/editorconfig-checker:v3.0.3
|
image: docker.io/woodpeckerci/plugin-editorconfig-checker:0.2.0
|
||||||
depends_on: []
|
depends_on: []
|
||||||
when:
|
when:
|
||||||
- event: pull_request
|
- event: pull_request
|
||||||
- event: push
|
|
||||||
branch: renovate/*
|
|
||||||
|
|
||||||
- name: spellcheck
|
- name: spellcheck
|
||||||
image: docker.io/node:22-alpine
|
image: docker.io/node:23-alpine
|
||||||
depends_on: []
|
depends_on: []
|
||||||
commands:
|
commands:
|
||||||
- corepack enable
|
- 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
|
- tree --gitignore -I 012_columns_rename_procs_to_steps.go -I versioned_docs -I '*opensource.svg'| pnpx cspell lint --no-progress stdin
|
||||||
|
|
||||||
- name: prettier
|
- name: prettier
|
||||||
image: docker.io/woodpeckerci/plugin-prettier:0.1.0
|
image: docker.io/woodpeckerci/plugin-prettier:next
|
||||||
|
pull: true
|
||||||
depends_on: []
|
depends_on: []
|
||||||
settings:
|
settings:
|
||||||
version: 3.2.5
|
version: 3.3.3
|
||||||
|
plugins:
|
||||||
- name: links
|
- 'prettier-plugin-tailwindcss'
|
||||||
image: docker.io/lycheeverse/lychee:0.15.1
|
- '@ianvs/prettier-plugin-sort-imports'
|
||||||
depends_on: []
|
|
||||||
commands:
|
|
||||||
- lychee pipeline/frontend/yaml/linter/schema/schema.json
|
|
||||||
- lychee --exclude localhost docs/docs/
|
|
||||||
- lychee --exclude localhost docs/src/pages/
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
variables:
|
variables:
|
||||||
- &golang_image 'docker.io/golang:1.22'
|
- &golang_image 'docker.io/golang:1.23'
|
||||||
- &when
|
- &when
|
||||||
- path: &when_path # related config files
|
- path: &when_path # related config files
|
||||||
- '.woodpecker/test.yaml'
|
- '.woodpecker/test.yaml'
|
||||||
|
@ -10,14 +10,9 @@ variables:
|
||||||
# schema changes
|
# schema changes
|
||||||
- 'pipeline/schema/**'
|
- 'pipeline/schema/**'
|
||||||
event: pull_request
|
event: pull_request
|
||||||
- event: push
|
|
||||||
branch: renovate/*
|
|
||||||
path: *when_path
|
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- event: pull_request
|
- event: pull_request
|
||||||
- event: push
|
|
||||||
branch: renovate/*
|
|
||||||
- event: push
|
- event: push
|
||||||
branch: ${CI_REPO_DEFAULT_BRANCH}
|
branch: ${CI_REPO_DEFAULT_BRANCH}
|
||||||
path: *when_path
|
path: *when_path
|
||||||
|
@ -37,9 +32,11 @@ steps:
|
||||||
- vendor
|
- vendor
|
||||||
image: *golang_image
|
image: *golang_image
|
||||||
commands:
|
commands:
|
||||||
- go run go.woodpecker-ci.org/woodpecker/v2/cmd/cli lint
|
- go run go.woodpecker-ci.org/woodpecker/v3/cmd/cli lint
|
||||||
environment:
|
environment:
|
||||||
WOODPECKER_DISABLE_UPDATE_CHECK: true
|
WOODPECKER_DISABLE_UPDATE_CHECK: true
|
||||||
|
WOODPECKER_LINT_STRICT: true
|
||||||
|
WOODPECKER_PLUGINS_PRIVILEGED: 'docker.io/woodpeckerci/plugin-docker-buildx'
|
||||||
when:
|
when:
|
||||||
- event: pull_request
|
- event: pull_request
|
||||||
path:
|
path:
|
||||||
|
@ -61,14 +58,14 @@ steps:
|
||||||
- make lint
|
- make lint
|
||||||
when: *when
|
when: *when
|
||||||
|
|
||||||
check-swagger:
|
check-openapi:
|
||||||
depends_on:
|
depends_on:
|
||||||
- vendor
|
- vendor
|
||||||
image: *golang_image
|
image: *golang_image
|
||||||
commands:
|
commands:
|
||||||
- 'make generate-swagger'
|
- 'make generate-openapi'
|
||||||
- 'DIFF=$(git diff | head)'
|
- '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
|
when: *when
|
||||||
|
|
||||||
lint-license-header:
|
lint-license-header:
|
||||||
|
@ -128,7 +125,7 @@ steps:
|
||||||
- test
|
- test
|
||||||
- sqlite
|
- sqlite
|
||||||
pull: true
|
pull: true
|
||||||
image: docker.io/woodpeckerci/plugin-codecov:2.1.2
|
image: docker.io/woodpeckerci/plugin-codecov:2.1.6
|
||||||
settings:
|
settings:
|
||||||
files:
|
files:
|
||||||
- agent-coverage.out
|
- agent-coverage.out
|
||||||
|
@ -144,7 +141,7 @@ steps:
|
||||||
|
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
image: docker.io/postgres:16
|
image: docker.io/postgres:17
|
||||||
ports: ['5432']
|
ports: ['5432']
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: postgres
|
POSTGRES_USER: postgres
|
||||||
|
@ -152,7 +149,7 @@ services:
|
||||||
when: *when
|
when: *when
|
||||||
|
|
||||||
mysql:
|
mysql:
|
||||||
image: docker.io/mysql:8.2.0
|
image: docker.io/mysql:9.1.0
|
||||||
ports: ['3306']
|
ports: ['3306']
|
||||||
environment:
|
environment:
|
||||||
MYSQL_DATABASE: test
|
MYSQL_DATABASE: test
|
||||||
|
|
|
@ -3,10 +3,9 @@ when:
|
||||||
- event: push
|
- event: push
|
||||||
branch:
|
branch:
|
||||||
- release/*
|
- release/*
|
||||||
- renovate/*
|
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
- &node_image 'docker.io/node:22-alpine'
|
- &node_image 'docker.io/node:23-alpine'
|
||||||
- &when
|
- &when
|
||||||
path:
|
path:
|
||||||
# related config files
|
# related config files
|
||||||
|
@ -25,6 +24,18 @@ steps:
|
||||||
- pnpm install --frozen-lockfile
|
- pnpm install --frozen-lockfile
|
||||||
when: *when
|
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:
|
lint:
|
||||||
depends_on:
|
depends_on:
|
||||||
- install-dependencies
|
- install-dependencies
|
||||||
|
@ -58,6 +69,7 @@ steps:
|
||||||
test:
|
test:
|
||||||
depends_on:
|
depends_on:
|
||||||
- install-dependencies
|
- install-dependencies
|
||||||
|
- format-check # wait for it else test artifacts are falsely detected as wrong
|
||||||
image: *node_image
|
image: *node_image
|
||||||
directory: web/
|
directory: web/
|
||||||
commands:
|
commands:
|
||||||
|
|
|
@ -6,6 +6,7 @@ ignore-from-file:
|
||||||
- .gitignore
|
- .gitignore
|
||||||
- server/store/datastore/migration/test-files/.gitignore
|
- server/store/datastore/migration/test-files/.gitignore
|
||||||
- web/.gitignore
|
- web/.gitignore
|
||||||
|
- web/.yamlignore
|
||||||
|
|
||||||
rules:
|
rules:
|
||||||
line-length: disable
|
line-length: disable
|
||||||
|
|
485
CHANGELOG.md
485
CHANGELOG.md
|
@ -1,5 +1,490 @@
|
||||||
# Changelog
|
# 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
|
## [2.6.0](https://github.com/woodpecker-ci/woodpecker/releases/tag/v2.6.0) - 2024-06-13
|
||||||
|
|
||||||
### ❤️ Thanks to all contributors! ❤️
|
### ❤️ Thanks to all contributors! ❤️
|
||||||
|
|
101
Makefile
101
Makefile
|
@ -30,7 +30,7 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
TAGS ?=
|
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
|
STATIC_BUILD ?= true
|
||||||
ifeq ($(STATIC_BUILD),true)
|
ifeq ($(STATIC_BUILD),true)
|
||||||
LDFLAGS := -s -w -extldflags "-static" $(LDFLAGS)
|
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" )
|
HAS_GO = $(shell hash go > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
|
||||||
ifeq ($(HAS_GO),GO)
|
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)
|
CGO_CFLAGS ?= $(shell go env CGO_CFLAGS)
|
||||||
endif
|
endif
|
||||||
CGO_CFLAGS ?=
|
CGO_CFLAGS ?=
|
||||||
|
@ -108,15 +109,15 @@ clean: ## Clean build artifacts
|
||||||
clean-all: clean ## Clean all artifacts
|
clean-all: clean ## Clean all artifacts
|
||||||
rm -rf ${DIST_DIR} web/dist docs/build docs/node_modules web/node_modules
|
rm -rf ${DIST_DIR} web/dist docs/build docs/node_modules web/node_modules
|
||||||
# delete generated
|
# delete generated
|
||||||
rm -rf docs/docs/40-cli.md docs/swagger.json
|
rm -rf docs/docs/40-cli.md docs/openapi.json
|
||||||
|
|
||||||
.PHONY: generate
|
.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 ./...
|
CGO_ENABLED=0 go generate ./...
|
||||||
|
|
||||||
generate-swagger: install-tools ## Run swagger code generation
|
generate-openapi: install-tools ## Run openapi code generation and format it
|
||||||
swag init -g server/api/ -g cmd/server/swagger.go --outputTypes go -output cmd/server/docs
|
go run github.com/swaggo/swag/cmd/swag fmt
|
||||||
CGO_ENABLED=0 go generate cmd/server/swagger.go
|
CGO_ENABLED=0 go generate cmd/server/openapi.go
|
||||||
|
|
||||||
generate-license-header: install-tools
|
generate-license-header: install-tools
|
||||||
addlicense -c "Woodpecker Authors" -ignore "vendor/**" **/*.go
|
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 \
|
hash gofumpt > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||||
go install mvdan.cc/gofumpt@latest; \
|
go install mvdan.cc/gofumpt@latest; \
|
||||||
fi ; \
|
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 \
|
hash addlicense > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||||
go install github.com/google/addlicense@latest; \
|
go install github.com/google/addlicense@latest; \
|
||||||
fi ; \
|
fi ; \
|
||||||
|
@ -163,20 +161,20 @@ lint-ui: ui-dependencies ## Lint UI code
|
||||||
(cd web/; pnpm lint --quiet)
|
(cd web/; pnpm lint --quiet)
|
||||||
|
|
||||||
test-agent: ## Test agent code
|
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
|
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
|
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
|
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 -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/v2/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
|
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
|
test-ui: ui-dependencies ## Test UI code
|
||||||
(cd web/; pnpm run lint)
|
(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
|
build-ui: ## Build UI
|
||||||
(cd web/; pnpm install --frozen-lockfile; pnpm build)
|
(cd web/; pnpm install --frozen-lockfile; pnpm build)
|
||||||
|
|
||||||
build-server: build-ui generate-swagger ## Build 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/v2/cmd/server
|
CGO_ENABLED=${CGO_ENABLED} GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -tags '$(TAGS)' -ldflags '${LDFLAGS}' -o ${DIST_DIR}/woodpecker-server${BIN_SUFFIX} go.woodpecker-ci.org/woodpecker/v3/cmd/server
|
||||||
|
|
||||||
build-agent: ## Build agent
|
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
|
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
|
build-tarball: ## Build tar archive
|
||||||
mkdir -p ${DIST_DIR} && tar chzvf ${DIST_DIR}/woodpecker-src.tar.gz \
|
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 orgi:$(TARGETARCH)"
|
||||||
@echo "arch (xgo):$(TARGETARCH_XGO)"
|
@echo "arch (xgo):$(TARGETARCH_XGO)"
|
||||||
@echo "arch (buildx):$(TARGETARCH_BUILDX)"
|
@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 .
|
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); \
|
mkdir -p ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX); \
|
||||||
mv -vf /build/woodpecker-server* ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX); \
|
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); \
|
[ -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); \
|
mv -v ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_XGO)/woodpecker-server* ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX); \
|
||||||
fi
|
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
|
release-server: ## Create server binaries for release
|
||||||
# compile
|
# 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 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
|
release-agent: ## Create agent binaries for release
|
||||||
# compile
|
# 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=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/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/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/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/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/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/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/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/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/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/v3/cmd/agent
|
||||||
# tar binary files
|
# 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_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_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_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_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
|
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
|
release-cli: ## Create cli binaries for release
|
||||||
# compile
|
# 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=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/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/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/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/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/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/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/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/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/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/v3/cmd/cli
|
||||||
# tar binary files
|
# 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_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_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_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_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
|
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
|
release-checksums: ## Create checksums for all release files
|
||||||
# generate shas for tar files
|
# generate shas for tar files
|
||||||
|
@ -321,6 +340,6 @@ spellcheck:
|
||||||
.PHONY: docs
|
.PHONY: docs
|
||||||
docs: ## Generate docs (currently only for the cli)
|
docs: ## Generate docs (currently only for the cli)
|
||||||
CGO_ENABLED=0 go generate cmd/cli/app.go
|
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
|
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">
|
<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">
|
<img src="https://img.shields.io/matrix/woodpecker:matrix.org?label=matrix" alt="Matrix space">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://goreportcard.com/report/go.woodpecker-ci.org/woodpecker/v2" title="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/v2" alt="Go Report Card">
|
<img src="https://goreportcard.com/badge/go.woodpecker-ci.org/woodpecker/v3" alt="Go Report Card">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://pkg.go.dev/go.woodpecker-ci.org/woodpecker/v2" title="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/v2" alt="go reference">
|
<img src="https://pkg.go.dev/badge/go.woodpecker-ci.org/woodpecker/v3" alt="go reference">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/woodpecker-ci/woodpecker/releases/latest" title="GitHub release">
|
<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">
|
<img src="https://img.shields.io/github/v/release/woodpecker-ci/woodpecker?sort=semver" alt="GitHub release">
|
||||||
|
@ -43,55 +43,48 @@
|
||||||
</p>
|
</p>
|
||||||
<br/>
|
<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>
|
<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/">
|
## Plugins
|
||||||
<img src="https://translate.woodpecker-ci.org/widgets/woodpecker-ci/-/ui/multi-blue.svg" alt="Translation status" />
|
|
||||||
</a>
|
|
||||||
|
|
||||||
## 👋 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.
|
[![Star History Chart](https://api.star-history.com/svg?repos=woodpecker-ci/woodpecker&type=Date)](https://star-history.com/#woodpecker-ci/woodpecker&Date)
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
## License
|
## 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"
|
"github.com/rs/zerolog"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline"
|
"go.woodpecker-ci.org/woodpecker/v3/pipeline"
|
||||||
backend "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
|
backend "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/log"
|
"go.woodpecker-ci.org/woodpecker/v3/pipeline/log"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
|
"go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc"
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Store not more than 1mb in a log-line as 4mb is the limit of a grpc message
|
|
||||||
// and log-lines needs to be parsed by the browsers later on.
|
|
||||||
maxLogLineLength = 1024 * 1024 // 1mb
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *Runner) createLogger(_logger zerolog.Logger, uploads *sync.WaitGroup, workflow *rpc.Workflow) pipeline.Logger {
|
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().
|
logger := _logger.With().
|
||||||
Str("image", step.Image).
|
Str("image", step.Image).
|
||||||
Str("workflow_id", workflow.ID).
|
|
||||||
Logger()
|
Logger()
|
||||||
|
|
||||||
uploads.Add(1)
|
uploads.Add(1)
|
||||||
|
@ -51,7 +44,7 @@ func (r *Runner) createLogger(_logger zerolog.Logger, uploads *sync.WaitGroup, w
|
||||||
logger.Debug().Msg("log stream opened")
|
logger.Debug().Msg("log stream opened")
|
||||||
|
|
||||||
logStream := log.NewLineWriter(r.client, step.UUID, secrets...)
|
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")
|
logger.Error().Err(err).Msg("copy limited logStream part")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,9 +20,11 @@ import (
|
||||||
|
|
||||||
"google.golang.org/grpc"
|
"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 {
|
type AuthClient struct {
|
||||||
client proto.WoodpeckerAuthClient
|
client proto.WoodpeckerAuthClient
|
||||||
conn *grpc.ClientConn
|
conn *grpc.ClientConn
|
||||||
|
@ -39,8 +41,8 @@ func NewAuthGrpcClient(conn *grpc.ClientConn, agentToken string, agentID int64)
|
||||||
return client
|
return client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AuthClient) Auth() (string, int64, error) {
|
func (c *AuthClient) Auth(ctx context.Context) (string, int64, error) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) //nolint:mnd
|
ctx, cancel := context.WithTimeout(ctx, authClientTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
req := &proto.AuthRequest{
|
req := &proto.AuthRequest{
|
||||||
|
|
|
@ -30,15 +30,12 @@ type AuthInterceptor struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAuthInterceptor returns a new auth interceptor.
|
// NewAuthInterceptor returns a new auth interceptor.
|
||||||
func NewAuthInterceptor(
|
func NewAuthInterceptor(ctx context.Context, authClient *AuthClient, refreshDuration time.Duration) (*AuthInterceptor, error) {
|
||||||
authClient *AuthClient,
|
|
||||||
refreshDuration time.Duration,
|
|
||||||
) (*AuthInterceptor, error) {
|
|
||||||
interceptor := &AuthInterceptor{
|
interceptor := &AuthInterceptor{
|
||||||
authClient: authClient,
|
authClient: authClient,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := interceptor.scheduleRefreshToken(refreshDuration)
|
err := interceptor.scheduleRefreshToken(ctx, refreshDuration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -78,21 +75,26 @@ func (interceptor *AuthInterceptor) attachToken(ctx context.Context) context.Con
|
||||||
return metadata.AppendToOutgoingContext(ctx, "token", interceptor.accessToken)
|
return metadata.AppendToOutgoingContext(ctx, "token", interceptor.accessToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (interceptor *AuthInterceptor) scheduleRefreshToken(refreshDuration time.Duration) error {
|
func (interceptor *AuthInterceptor) scheduleRefreshToken(ctx context.Context, refreshInterval time.Duration) error {
|
||||||
err := interceptor.refreshToken()
|
err := interceptor.refreshToken(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
wait := refreshDuration
|
wait := refreshInterval
|
||||||
|
|
||||||
for {
|
for {
|
||||||
time.Sleep(wait)
|
select {
|
||||||
err := interceptor.refreshToken()
|
case <-ctx.Done():
|
||||||
if err != nil {
|
return
|
||||||
wait = time.Second
|
case <-time.After(wait):
|
||||||
} else {
|
err := interceptor.refreshToken(ctx)
|
||||||
wait = refreshDuration
|
if err != nil {
|
||||||
|
wait = time.Second
|
||||||
|
} else {
|
||||||
|
wait = refreshInterval
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -100,8 +102,8 @@ func (interceptor *AuthInterceptor) scheduleRefreshToken(refreshDuration time.Du
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (interceptor *AuthInterceptor) refreshToken() error {
|
func (interceptor *AuthInterceptor) refreshToken(ctx context.Context) error {
|
||||||
accessToken, _, err := interceptor.authClient.Auth()
|
accessToken, _, err := interceptor.authClient.Auth(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,44 +17,57 @@ package rpc
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cenkalti/backoff/v4"
|
"github.com/cenkalti/backoff/v5"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
|
grpcproto "google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
backend "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
|
backend "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
|
"go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc/proto"
|
"go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Set grpc version on compile time to compare against server version response.
|
const (
|
||||||
const ClientGrpcVersion int32 = proto.Version
|
// 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 {
|
type client struct {
|
||||||
client proto.WoodpeckerClient
|
client proto.WoodpeckerClient
|
||||||
conn *grpc.ClientConn
|
conn *grpc.ClientConn
|
||||||
|
logs chan *proto.LogEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGrpcClient returns a new grpc Client.
|
// 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 := new(client)
|
||||||
client.client = proto.NewWoodpeckerClient(conn)
|
client.client = proto.NewWoodpeckerClient(conn)
|
||||||
client.conn = conn
|
client.conn = conn
|
||||||
|
client.logs = make(chan *proto.LogEntry, 10) // max memory use: 10 lines * 1 MiB
|
||||||
|
go client.processLogs(ctx)
|
||||||
return client
|
return client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) Close() error {
|
func (c *client) Close() error {
|
||||||
|
close(c.logs)
|
||||||
return c.conn.Close()
|
return c.conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) newBackOff() backoff.BackOff {
|
func (c *client) newBackOff() backoff.BackOff {
|
||||||
b := backoff.NewExponentialBackOff()
|
b := backoff.NewExponentialBackOff()
|
||||||
b.MaxElapsedTime = 0
|
|
||||||
b.MaxInterval = 10 * time.Second //nolint:mnd
|
b.MaxInterval = 10 * time.Second //nolint:mnd
|
||||||
b.InitialInterval = 10 * time.Millisecond //nolint:mnd
|
b.InitialInterval = 10 * time.Millisecond //nolint:mnd
|
||||||
return b
|
return b
|
||||||
|
@ -73,13 +86,13 @@ func (c *client) Version(ctx context.Context) (*rpc.Version, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next returns the next workflow in the queue.
|
// 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 res *proto.NextResponse
|
||||||
var err error
|
var err error
|
||||||
retry := c.newBackOff()
|
retry := c.newBackOff()
|
||||||
req := new(proto.NextRequest)
|
req := new(proto.NextRequest)
|
||||||
req.Filter = new(proto.Filter)
|
req.Filter = new(proto.Filter)
|
||||||
req.Filter.Labels = f.Labels
|
req.Filter.Labels = filter.Labels
|
||||||
for {
|
for {
|
||||||
res, err = c.client.Next(ctx, req)
|
res, err = c.client.Next(ctx, req)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -90,8 +103,10 @@ func (c *client) Next(ctx context.Context, f rpc.Filter) (*rpc.Workflow, error)
|
||||||
case codes.Canceled:
|
case codes.Canceled:
|
||||||
if ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
// expected as context was canceled
|
// expected as context was canceled
|
||||||
|
log.Debug().Err(err).Msgf("grpc error: next(): context canceled")
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
log.Error().Err(err).Msgf("grpc error: next(): code: %v", status.Code(err))
|
||||||
return nil, err
|
return nil, err
|
||||||
case
|
case
|
||||||
codes.Aborted,
|
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
|
// https://github.com/woodpecker-ci/woodpecker/issues/717#issuecomment-1049365104
|
||||||
log.Trace().Err(err).Msg("grpc: to many keepalive pings without sending data")
|
log.Trace().Err(err).Msg("grpc: to many keepalive pings without sending data")
|
||||||
} else {
|
} 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:
|
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 {
|
select {
|
||||||
|
@ -143,9 +159,15 @@ func (c *client) Wait(ctx context.Context, workflowID string) (err error) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Error().Err(err).Msgf("grpc error: wait(): code: %v", status.Code(err))
|
|
||||||
|
|
||||||
switch 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
|
case
|
||||||
codes.Aborted,
|
codes.Aborted,
|
||||||
codes.DataLoss,
|
codes.DataLoss,
|
||||||
|
@ -153,7 +175,9 @@ func (c *client) Wait(ctx context.Context, workflowID string) (err error) {
|
||||||
codes.Internal,
|
codes.Internal,
|
||||||
codes.Unavailable:
|
codes.Unavailable:
|
||||||
// non-fatal errors
|
// non-fatal errors
|
||||||
|
log.Warn().Err(err).Msgf("grpc error: wait(): code: %v", status.Code(err))
|
||||||
default:
|
default:
|
||||||
|
log.Error().Err(err).Msgf("grpc error: wait(): code: %v", status.Code(err))
|
||||||
return 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))
|
log.Error().Err(err).Msgf("grpc error: init(): code: %v", status.Code(err))
|
||||||
|
|
||||||
switch 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
|
case
|
||||||
codes.Aborted,
|
codes.Aborted,
|
||||||
codes.DataLoss,
|
codes.DataLoss,
|
||||||
|
@ -191,7 +223,9 @@ func (c *client) Init(ctx context.Context, workflowID string, state rpc.Workflow
|
||||||
codes.Internal,
|
codes.Internal,
|
||||||
codes.Unavailable:
|
codes.Unavailable:
|
||||||
// non-fatal errors
|
// non-fatal errors
|
||||||
|
log.Warn().Err(err).Msgf("grpc error: init(): code: %v", status.Code(err))
|
||||||
default:
|
default:
|
||||||
|
log.Error().Err(err).Msgf("grpc error: init(): code: %v", status.Code(err))
|
||||||
return 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))
|
log.Error().Err(err).Msgf("grpc error: done(): code: %v", status.Code(err))
|
||||||
|
|
||||||
switch 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
|
case
|
||||||
codes.Aborted,
|
codes.Aborted,
|
||||||
codes.DataLoss,
|
codes.DataLoss,
|
||||||
|
@ -229,7 +271,9 @@ func (c *client) Done(ctx context.Context, workflowID string, state rpc.Workflow
|
||||||
codes.Internal,
|
codes.Internal,
|
||||||
codes.Unavailable:
|
codes.Unavailable:
|
||||||
// non-fatal errors
|
// non-fatal errors
|
||||||
|
log.Warn().Err(err).Msgf("grpc error: done(): code: %v", status.Code(err))
|
||||||
default:
|
default:
|
||||||
|
log.Error().Err(err).Msgf("grpc error: done(): code: %v", status.Code(err))
|
||||||
return 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))
|
log.Error().Err(err).Msgf("grpc error: extend(): code: %v", status.Code(err))
|
||||||
|
|
||||||
switch 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
|
case
|
||||||
codes.Aborted,
|
codes.Aborted,
|
||||||
codes.DataLoss,
|
codes.DataLoss,
|
||||||
|
@ -263,7 +315,9 @@ func (c *client) Extend(ctx context.Context, workflowID string) (err error) {
|
||||||
codes.Internal,
|
codes.Internal,
|
||||||
codes.Unavailable:
|
codes.Unavailable:
|
||||||
// non-fatal errors
|
// non-fatal errors
|
||||||
|
log.Warn().Err(err).Msgf("grpc error: extend(): code: %v", status.Code(err))
|
||||||
default:
|
default:
|
||||||
|
log.Error().Err(err).Msgf("grpc error: extend(): code: %v", status.Code(err))
|
||||||
return 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))
|
log.Error().Err(err).Msgf("grpc error: update(): code: %v", status.Code(err))
|
||||||
|
|
||||||
switch 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
|
case
|
||||||
codes.Aborted,
|
codes.Aborted,
|
||||||
codes.DataLoss,
|
codes.DataLoss,
|
||||||
|
@ -304,7 +366,9 @@ func (c *client) Update(ctx context.Context, workflowID string, state rpc.StepSt
|
||||||
codes.Internal,
|
codes.Internal,
|
||||||
codes.Unavailable:
|
codes.Unavailable:
|
||||||
// non-fatal errors
|
// non-fatal errors
|
||||||
|
log.Warn().Err(err).Msgf("grpc error: update(): code: %v", status.Code(err))
|
||||||
default:
|
default:
|
||||||
|
log.Error().Err(err).Msgf("grpc error: update(): code: %v", status.Code(err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,25 +381,82 @@ func (c *client) Update(ctx context.Context, workflowID string, state rpc.StepSt
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log writes the step log entry.
|
// EnqueueLog queues the log entry to be written in a batch later.
|
||||||
func (c *client) Log(ctx context.Context, logEntry *rpc.LogEntry) (err error) {
|
func (c *client) EnqueueLog(logEntry *rpc.LogEntry) {
|
||||||
retry := c.newBackOff()
|
c.logs <- &proto.LogEntry{
|
||||||
req := new(proto.LogRequest)
|
StepUuid: logEntry.StepUUID,
|
||||||
req.LogEntry = new(proto.LogEntry)
|
Data: logEntry.Data,
|
||||||
req.LogEntry.StepUuid = logEntry.StepUUID
|
Line: int32(logEntry.Line),
|
||||||
req.LogEntry.Data = logEntry.Data
|
Time: logEntry.Time,
|
||||||
req.LogEntry.Line = int32(logEntry.Line)
|
Type: int32(logEntry.Type),
|
||||||
req.LogEntry.Time = logEntry.Time
|
}
|
||||||
req.LogEntry.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 {
|
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 {
|
if err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Error().Err(err).Msgf("grpc error: log(): code: %v", status.Code(err))
|
|
||||||
|
|
||||||
switch 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
|
case
|
||||||
codes.Aborted,
|
codes.Aborted,
|
||||||
codes.DataLoss,
|
codes.DataLoss,
|
||||||
|
@ -343,7 +464,9 @@ func (c *client) Log(ctx context.Context, logEntry *rpc.LogEntry) (err error) {
|
||||||
codes.Internal,
|
codes.Internal,
|
||||||
codes.Unavailable:
|
codes.Unavailable:
|
||||||
// non-fatal errors
|
// non-fatal errors
|
||||||
|
log.Warn().Err(err).Msgf("grpc error: log(): code: %v", status.Code(err))
|
||||||
default:
|
default:
|
||||||
|
log.Error().Err(err).Msgf("grpc error: log(): code: %v", status.Code(err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,12 +479,15 @@ func (c *client) Log(ctx context.Context, logEntry *rpc.LogEntry) (err error) {
|
||||||
return nil
|
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 := new(proto.RegisterAgentRequest)
|
||||||
req.Platform = platform
|
req.Info = &proto.AgentInfo{
|
||||||
req.Backend = backend
|
Platform: info.Platform,
|
||||||
req.Version = version
|
Backend: info.Backend,
|
||||||
req.Capacity = int32(capacity)
|
Version: info.Version,
|
||||||
|
Capacity: int32(info.Capacity),
|
||||||
|
CustomLabels: info.CustomLabels,
|
||||||
|
}
|
||||||
|
|
||||||
res, err := c.client.RegisterAgent(ctx, req)
|
res, err := c.client.RegisterAgent(ctx, req)
|
||||||
return res.GetAgentId(), err
|
return res.GetAgentId(), err
|
||||||
|
@ -383,6 +509,14 @@ func (c *client) ReportHealth(ctx context.Context) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
switch 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: report_health(): context canceled")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
log.Error().Err(err).Msgf("grpc error: report_health(): code: %v", status.Code(err))
|
||||||
|
return err
|
||||||
case
|
case
|
||||||
codes.Aborted,
|
codes.Aborted,
|
||||||
codes.DataLoss,
|
codes.DataLoss,
|
||||||
|
@ -390,7 +524,9 @@ func (c *client) ReportHealth(ctx context.Context) (err error) {
|
||||||
codes.Internal,
|
codes.Internal,
|
||||||
codes.Unavailable:
|
codes.Unavailable:
|
||||||
// non-fatal errors
|
// non-fatal errors
|
||||||
|
log.Warn().Err(err).Msgf("grpc error: report_health(): code: %v", status.Code(err))
|
||||||
default:
|
default:
|
||||||
|
log.Error().Err(err).Msgf("grpc error: report_health(): code: %v", status.Code(err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,10 +25,11 @@ import (
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline"
|
"go.woodpecker-ci.org/woodpecker/v3/pipeline"
|
||||||
backend "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
|
backend "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
|
"go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/shared/utils"
|
"go.woodpecker-ci.org/woodpecker/v3/shared/constant"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v3/shared/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Runner struct {
|
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")
|
log.Debug().Msg("request next execution")
|
||||||
|
|
||||||
meta, _ := metadata.FromOutgoingContext(runnerCtx)
|
meta, _ := metadata.FromOutgoingContext(runnerCtx)
|
||||||
|
@ -118,7 +119,7 @@ func (r *Runner) Run(runnerCtx context.Context) error { //nolint:contextcheck
|
||||||
logger.Debug().Msg("pipeline done")
|
logger.Debug().Msg("pipeline done")
|
||||||
return
|
return
|
||||||
|
|
||||||
case <-time.After(time.Minute):
|
case <-time.After(constant.TaskTimeout / 3):
|
||||||
logger.Debug().Msg("pipeline lease renewed")
|
logger.Debug().Msg("pipeline lease renewed")
|
||||||
if err := r.client.Extend(workflowCtx, workflow.ID); err != nil {
|
if err := r.client.Extend(workflowCtx, workflow.ID); err != nil {
|
||||||
log.Error().Err(err).Msg("extending pipeline deadline failed")
|
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).
|
Str("error", state.Error).
|
||||||
Msg("updating workflow status")
|
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")
|
logger.Error().Err(err).Msg("updating workflow status failed")
|
||||||
} else {
|
} else {
|
||||||
logger.Debug().Msg("updating workflow status complete")
|
logger.Debug().Msg("updating workflow status complete")
|
||||||
|
|
|
@ -23,8 +23,8 @@ import (
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline"
|
"go.woodpecker-ci.org/woodpecker/v3/pipeline"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
|
"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 {
|
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
|
// 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_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_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_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
|
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
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,16 +15,22 @@
|
||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
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.
|
// Command exports the admin command set.
|
||||||
var Command = &cli.Command{
|
var Command = &cli.Command{
|
||||||
Name: "admin",
|
Name: "admin",
|
||||||
Usage: "administer server settings",
|
Usage: "manage server settings",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
|
loglevel.Command,
|
||||||
registry.Command,
|
registry.Command,
|
||||||
|
secret.Command,
|
||||||
|
user.Command,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,24 +15,26 @@
|
||||||
package loglevel
|
package loglevel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"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/v3/cli/internal"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Command exports the log-level command used to change the servers log-level.
|
// Command exports the log-level command used to change the servers log-level.
|
||||||
var Command = &cli.Command{
|
var Command = &cli.Command{
|
||||||
Name: "log-level",
|
Name: "log-level",
|
||||||
ArgsUsage: "[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,
|
Action: logLevel,
|
||||||
}
|
}
|
||||||
|
|
||||||
func logLevel(c *cli.Context) error {
|
func logLevel(ctx context.Context, c *cli.Command) error {
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
return nil
|
||||||
}
|
}
|
|
@ -15,18 +15,18 @@
|
||||||
package registry
|
package registry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Command exports the registry command set.
|
// Command exports the registry command set.
|
||||||
var Command = &cli.Command{
|
var Command = &cli.Command{
|
||||||
Name: "registry",
|
Name: "registry",
|
||||||
Usage: "manage global registries",
|
Usage: "manage global registries",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
registryCreateCmd,
|
registryCreateCmd,
|
||||||
registryDeleteCmd,
|
registryDeleteCmd,
|
||||||
registryUpdateCmd,
|
|
||||||
registryInfoCmd,
|
|
||||||
registryListCmd,
|
registryListCmd,
|
||||||
|
registryShowCmd,
|
||||||
|
registryUpdateCmd,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,18 +15,19 @@
|
||||||
package registry
|
package registry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"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/v2/woodpecker-go/woodpecker"
|
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||||
)
|
)
|
||||||
|
|
||||||
var registryCreateCmd = &cli.Command{
|
var registryCreateCmd = &cli.Command{
|
||||||
Name: "add",
|
Name: "add",
|
||||||
Usage: "adds a registry",
|
Usage: "add a registry",
|
||||||
Action: registryCreate,
|
Action: registryCreate,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&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 (
|
var (
|
||||||
hostname = c.String("hostname")
|
hostname = c.String("hostname")
|
||||||
username = c.String("username")
|
username = c.String("username")
|
||||||
password = c.String("password")
|
password = c.String("password")
|
||||||
)
|
)
|
||||||
|
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,13 +15,15 @@
|
||||||
package registry
|
package registry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"html/template"
|
"html/template"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||||
"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 registryListCmd = &cli.Command{
|
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"
|
format := c.String("format") + "\n"
|
||||||
|
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
list, err := client.GlobalRegistryList()
|
opt := woodpecker.RegistryListOptions{}
|
||||||
|
|
||||||
|
list, err := client.GlobalRegistryList(opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,11 @@
|
||||||
package registry
|
package registry
|
||||||
|
|
||||||
import (
|
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{
|
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")
|
hostname := c.String("hostname")
|
||||||
|
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,14 +15,15 @@
|
||||||
package registry
|
package registry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||||
)
|
)
|
||||||
|
|
||||||
var registryUpdateCmd = &cli.Command{
|
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 (
|
var (
|
||||||
hostname = c.String("hostname")
|
hostname = c.String("hostname")
|
||||||
username = c.String("username")
|
username = c.String("username")
|
||||||
password = c.String("password")
|
password = c.String("password")
|
||||||
)
|
)
|
||||||
|
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,19 +15,20 @@
|
||||||
package registry
|
package registry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"html/template"
|
"html/template"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
var registryInfoCmd = &cli.Command{
|
var registryShowCmd = &cli.Command{
|
||||||
Name: "info",
|
Name: "show",
|
||||||
Usage: "display registry info",
|
Usage: "show registry information",
|
||||||
Action: registryInfo,
|
Action: registryShow,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "hostname",
|
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 (
|
var (
|
||||||
hostname = c.String("hostname")
|
hostname = c.String("hostname")
|
||||||
format = c.String("format") + "\n"
|
format = c.String("format") + "\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
// Copyright 2021 Woodpecker Authors
|
// Copyright 2023 Woodpecker Authors
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
// You may obtain a copy of the License at
|
// 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
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
// 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
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package migration
|
package secret
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"src.techknowlogick.com/xormigrate"
|
"github.com/urfave/cli/v3"
|
||||||
"xorm.io/xorm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var alterTableReposDropCounter = xormigrate.Migration{
|
// Command exports the secret command.
|
||||||
ID: "alter-table-drop-counter",
|
var Command = &cli.Command{
|
||||||
MigrateSession: func(sess *xorm.Session) error {
|
Name: "secret",
|
||||||
return dropTableColumns(sess, "repos", "repo_counter")
|
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
|
package secret
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"html/template"
|
"html/template"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||||
)
|
)
|
||||||
|
|
||||||
var secretListCmd = &cli.Command{
|
var secretListCmd = &cli.Command{
|
||||||
|
@ -32,48 +33,25 @@ var secretListCmd = &cli.Command{
|
||||||
ArgsUsage: "[repo-id|repo-full-name]",
|
ArgsUsage: "[repo-id|repo-full-name]",
|
||||||
Action: secretList,
|
Action: secretList,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "global",
|
|
||||||
Usage: "global secret",
|
|
||||||
},
|
|
||||||
common.OrgFlag,
|
|
||||||
common.RepoFlag,
|
|
||||||
common.FormatFlag(tmplSecretList, true),
|
common.FormatFlag(tmplSecretList, true),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func secretList(c *cli.Context) error {
|
func secretList(ctx context.Context, c *cli.Command) error {
|
||||||
format := c.String("format") + "\n"
|
format := c.String("format") + "\n"
|
||||||
|
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
global, orgID, repoID, err := parseTargetArgs(client, c)
|
opt := woodpecker.SecretListOptions{}
|
||||||
|
|
||||||
|
list, err := client.GlobalSecretList(opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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)
|
tmpl, err := template.New("_").Funcs(secretFuncMap).Parse(format)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
package user
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Command exports the user command set.
|
// Command exports the user command set.
|
||||||
var Command = &cli.Command{
|
var Command = &cli.Command{
|
||||||
Name: "user",
|
Name: "user",
|
||||||
Usage: "manage users",
|
Usage: "manage users",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
userListCmd,
|
|
||||||
userInfoCmd,
|
|
||||||
userAddCmd,
|
userAddCmd,
|
||||||
|
userListCmd,
|
||||||
userRemoveCmd,
|
userRemoveCmd,
|
||||||
|
userShowCmd,
|
||||||
},
|
},
|
||||||
}
|
}
|
|
@ -15,25 +15,26 @@
|
||||||
package user
|
package user
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"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"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||||
)
|
)
|
||||||
|
|
||||||
var userAddCmd = &cli.Command{
|
var userAddCmd = &cli.Command{
|
||||||
Name: "add",
|
Name: "add",
|
||||||
Usage: "adds a user",
|
Usage: "add a user",
|
||||||
ArgsUsage: "<username>",
|
ArgsUsage: "<username>",
|
||||||
Action: userAdd,
|
Action: userAdd,
|
||||||
}
|
}
|
||||||
|
|
||||||
func userAdd(c *cli.Context) error {
|
func userAdd(ctx context.Context, c *cli.Command) error {
|
||||||
login := c.Args().First()
|
login := c.Args().First()
|
||||||
|
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
|
@ -15,13 +15,15 @@
|
||||||
package user
|
package user
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"text/template"
|
"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/v3/cli/common"
|
||||||
"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 userListCmd = &cli.Command{
|
var userListCmd = &cli.Command{
|
||||||
|
@ -32,13 +34,15 @@ var userListCmd = &cli.Command{
|
||||||
Flags: []cli.Flag{common.FormatFlag(tmplUserList)},
|
Flags: []cli.Flag{common.FormatFlag(tmplUserList)},
|
||||||
}
|
}
|
||||||
|
|
||||||
func userList(c *cli.Context) error {
|
func userList(ctx context.Context, c *cli.Command) error {
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
users, err := client.UserList()
|
opt := woodpecker.UserListOptions{}
|
||||||
|
|
||||||
|
users, err := client.UserList(opt)
|
||||||
if err != nil || len(users) == 0 {
|
if err != nil || len(users) == 0 {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
|
@ -15,11 +15,12 @@
|
||||||
package user
|
package user
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"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{
|
var userRemoveCmd = &cli.Command{
|
||||||
|
@ -29,10 +30,10 @@ var userRemoveCmd = &cli.Command{
|
||||||
Action: userRemove,
|
Action: userRemove,
|
||||||
}
|
}
|
||||||
|
|
||||||
func userRemove(c *cli.Context) error {
|
func userRemove(ctx context.Context, c *cli.Command) error {
|
||||||
login := c.Args().First()
|
login := c.Args().First()
|
||||||
|
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
|
@ -15,26 +15,27 @@
|
||||||
package user
|
package user
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"text/template"
|
"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/v3/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
var userInfoCmd = &cli.Command{
|
var userShowCmd = &cli.Command{
|
||||||
Name: "info",
|
Name: "show",
|
||||||
Usage: "show user details",
|
Usage: "show user information",
|
||||||
ArgsUsage: "<username>",
|
ArgsUsage: "<username>",
|
||||||
Action: userInfo,
|
Action: userShow,
|
||||||
Flags: []cli.Flag{common.FormatFlag(tmplUserInfo)},
|
Flags: []cli.Flag{common.FormatFlag(tmplUserInfo)},
|
||||||
}
|
}
|
||||||
|
|
||||||
func userInfo(c *cli.Context) error {
|
func userShow(ctx context.Context, c *cli.Command) error {
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
|
@ -15,52 +15,49 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
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{
|
var GlobalFlags = append([]cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"WOODPECKER_CONFIG"},
|
Sources: cli.EnvVars("WOODPECKER_CONFIG"),
|
||||||
Name: "config",
|
Name: "config",
|
||||||
Aliases: []string{"c"},
|
Aliases: []string{"c"},
|
||||||
Usage: "path to config file",
|
Usage: "path to config file",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"WOODPECKER_SERVER"},
|
Sources: cli.EnvVars("WOODPECKER_SERVER"),
|
||||||
Name: "server",
|
Name: "server",
|
||||||
Aliases: []string{"s"},
|
Aliases: []string{"s"},
|
||||||
Usage: "server address",
|
Usage: "server address",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"WOODPECKER_TOKEN"},
|
Sources: cli.EnvVars("WOODPECKER_TOKEN"),
|
||||||
Name: "token",
|
Name: "token",
|
||||||
Aliases: []string{"t"},
|
Aliases: []string{"t"},
|
||||||
Usage: "server auth token",
|
Usage: "server auth token",
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
EnvVars: []string{"WOODPECKER_DISABLE_UPDATE_CHECK"},
|
Sources: cli.EnvVars("WOODPECKER_DISABLE_UPDATE_CHECK"),
|
||||||
Name: "disable-update-check",
|
Name: "disable-update-check",
|
||||||
Usage: "disable update check",
|
Usage: "disable update check",
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
EnvVars: []string{"WOODPECKER_SKIP_VERIFY"},
|
Sources: cli.EnvVars("WOODPECKER_SKIP_VERIFY"),
|
||||||
Name: "skip-verify",
|
Name: "skip-verify",
|
||||||
Usage: "skip ssl verification",
|
Usage: "skip ssl verification",
|
||||||
Hidden: true,
|
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"SOCKS_PROXY"},
|
Sources: cli.EnvVars("SOCKS_PROXY"),
|
||||||
Name: "socks-proxy",
|
Name: "socks-proxy",
|
||||||
Usage: "socks proxy address",
|
Usage: "socks proxy address",
|
||||||
Hidden: true,
|
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
EnvVars: []string{"SOCKS_PROXY_OFF"},
|
Sources: cli.EnvVars("SOCKS_PROXY_OFF"),
|
||||||
Name: "socks-proxy-off",
|
Name: "socks-proxy-off",
|
||||||
Usage: "socks proxy ignored",
|
Usage: "socks proxy ignored",
|
||||||
Hidden: true,
|
|
||||||
},
|
},
|
||||||
}, logger.GlobalLoggerFlags...)
|
}, logger.GlobalLoggerFlags...)
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,10 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"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/v3/cli/internal/config"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/update"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/update"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -17,12 +17,12 @@ var (
|
||||||
cancelWaitForUpdate context.CancelCauseFunc
|
cancelWaitForUpdate context.CancelCauseFunc
|
||||||
)
|
)
|
||||||
|
|
||||||
func Before(c *cli.Context) error {
|
func Before(ctx context.Context, c *cli.Command) (context.Context, error) {
|
||||||
if err := setupGlobalLogger(c); err != nil {
|
if err := setupGlobalLogger(ctx, c); err != nil {
|
||||||
return err
|
return ctx, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func(context.Context) {
|
||||||
if c.Bool("disable-update-check") {
|
if c.Bool("disable-update-check") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -35,31 +35,31 @@ func Before(c *cli.Context) error {
|
||||||
waitForUpdateCheck, cancelWaitForUpdate = context.WithCancelCause(context.Background())
|
waitForUpdateCheck, cancelWaitForUpdate = context.WithCancelCause(context.Background())
|
||||||
defer cancelWaitForUpdate(errors.New("update check finished"))
|
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 {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("Failed to check for updates")
|
log.Error().Err(err).Msgf("failed to check for updates")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if newVersion != nil {
|
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 {
|
} 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 {
|
if waitForUpdateCheck != nil {
|
||||||
select {
|
select {
|
||||||
case <-waitForUpdateCheck.Done():
|
case <-waitForUpdateCheck.Done():
|
||||||
// When the actual command already finished, we still wait 500ms for the update check to finish
|
// When the actual command already finished, we still wait 500ms for the update check to finish
|
||||||
case <-time.After(time.Millisecond * 500):
|
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"))
|
cancelWaitForUpdate(errors.New("update check timeout"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,13 +15,14 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"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) {
|
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")
|
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 {
|
if c.Args().Len() == 0 {
|
||||||
isDir, path, err := DetectPipelineConfig()
|
isDir, path, err := DetectPipelineConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if isDir {
|
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
|
multiArgs := c.Args().Len() > 1
|
||||||
|
@ -59,11 +60,11 @@ func RunPipelineFunc(c *cli.Context, fileFunc, dirFunc func(*cli.Context, string
|
||||||
fmt.Println("#", fi.Name())
|
fmt.Println("#", fi.Name())
|
||||||
}
|
}
|
||||||
if fi.IsDir() {
|
if fi.IsDir() {
|
||||||
if err := dirFunc(c, arg); err != nil {
|
if err := dirFunc(ctx, c, arg); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err := fileFunc(c, arg); err != nil {
|
if err := fileFunc(ctx, c, arg); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,13 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
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 {
|
func setupGlobalLogger(ctx context.Context, c *cli.Command) error {
|
||||||
return logger.SetupGlobalLogger(c, false)
|
return logger.SetupGlobalLogger(ctx, c, false)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
package exec
|
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
|
func init() { //nolint:gochecknoinits
|
||||||
backends = append(backends, dummy.New())
|
backends = append(backends, dummy.New())
|
||||||
|
|
108
cli/exec/exec.go
108
cli/exec/exec.go
|
@ -25,23 +25,26 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/drone/envsubst"
|
"github.com/drone/envsubst"
|
||||||
|
"github.com/oklog/ulid/v2"
|
||||||
"github.com/rs/zerolog/log"
|
"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/v3/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/lint"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/lint"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline"
|
"go.woodpecker-ci.org/woodpecker/v3/pipeline"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend"
|
"go.woodpecker-ci.org/woodpecker/v3/pipeline/backend"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/docker"
|
"go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/docker"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/kubernetes"
|
"go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/kubernetes"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/local"
|
"go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/local"
|
||||||
backend_types "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
|
backend_types "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml"
|
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/metadata"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/compiler"
|
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/linter"
|
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml/compiler"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/matrix"
|
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml/linter"
|
||||||
pipelineLog "go.woodpecker-ci.org/woodpecker/v2/pipeline/log"
|
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml/matrix"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/shared/utils"
|
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.
|
// Command exports the exec command.
|
||||||
|
@ -59,11 +62,11 @@ var backends = []backend_types.Backend{
|
||||||
local.New(),
|
local.New(),
|
||||||
}
|
}
|
||||||
|
|
||||||
func run(c *cli.Context) error {
|
func run(ctx context.Context, c *cli.Command) error {
|
||||||
return common.RunPipelineFunc(c, execFile, execDir)
|
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
|
// TODO: respect pipeline dependency
|
||||||
repoPath := c.String("repo-path")
|
repoPath := c.String("repo-path")
|
||||||
if repoPath != "" {
|
if repoPath != "" {
|
||||||
|
@ -74,6 +77,7 @@ func execDir(c *cli.Context, dir string) error {
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
repoPath = convertPathForWindows(repoPath)
|
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 {
|
return filepath.Walk(dir, func(path string, info os.FileInfo, e error) error {
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return e
|
return e
|
||||||
|
@ -82,7 +86,7 @@ func execDir(c *cli.Context, dir string) error {
|
||||||
// check if it is a regular file (not dir)
|
// check if it is a regular file (not dir)
|
||||||
if info.Mode().IsRegular() && (strings.HasSuffix(info.Name(), ".yaml") || strings.HasSuffix(info.Name(), ".yml")) {
|
if info.Mode().IsRegular() && (strings.HasSuffix(info.Name(), ".yaml") || strings.HasSuffix(info.Name(), ".yml")) {
|
||||||
fmt.Println("#", info.Name())
|
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("")
|
fmt.Println("")
|
||||||
return nil
|
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")
|
repoPath := c.String("repo-path")
|
||||||
if repoPath != "" {
|
if repoPath != "" {
|
||||||
repoPath, _ = filepath.Abs(repoPath)
|
repoPath, _ = filepath.Abs(repoPath)
|
||||||
|
@ -101,10 +105,10 @@ func execFile(c *cli.Context, file string) error {
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
repoPath = convertPathForWindows(repoPath)
|
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)
|
dat, err := os.ReadFile(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -119,7 +123,7 @@ func runExec(c *cli.Context, file, repoPath string) error {
|
||||||
axes = append(axes, matrix.Axis{})
|
axes = append(axes, matrix.Axis{})
|
||||||
}
|
}
|
||||||
for _, axis := range axes {
|
for _, axis := range axes {
|
||||||
err := execWithAxis(c, file, repoPath, axis)
|
err := execWithAxis(ctx, c, file, repoPath, axis, singleExec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -127,8 +131,20 @@ func runExec(c *cli.Context, file, repoPath string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error {
|
func execWithAxis(ctx context.Context, c *cli.Command, file, repoPath string, axis matrix.Axis, singleExec bool) error {
|
||||||
metadata := metadataFromContext(c, axis)
|
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()
|
environ := metadata.Environ()
|
||||||
var secrets []compiler.Secret
|
var secrets []compiler.Secret
|
||||||
for key, val := range metadata.Workflow.Matrix {
|
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
|
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
|
// configure volumes for local execution
|
||||||
volumes := c.StringSlice("volumes")
|
volumes := c.StringSlice("volumes")
|
||||||
if c.Bool("local") {
|
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")
|
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))
|
volumes = append(volumes, repoPath+":"+path.Join(workspaceBase, workspacePath))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
privilegedPlugins := c.StringSlice("plugins-privileged")
|
||||||
|
|
||||||
// lint the yaml file
|
// 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),
|
File: path.Base(file),
|
||||||
RawConfig: confStr,
|
RawConfig: confStr,
|
||||||
Workflow: conf,
|
Workflow: conf,
|
||||||
}})
|
}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
str, err := lint.FormatLintError(file, err)
|
str, err := lint.FormatLintError(file, err, false)
|
||||||
fmt.Print(str)
|
fmt.Print(str)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -201,7 +230,7 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
|
||||||
// compiles the yaml file
|
// compiles the yaml file
|
||||||
compiled, err := compiler.New(
|
compiled, err := compiler.New(
|
||||||
compiler.WithEscalated(
|
compiler.WithEscalated(
|
||||||
c.StringSlice("privileged")...,
|
privilegedPlugins...,
|
||||||
),
|
),
|
||||||
compiler.WithVolumes(volumes...),
|
compiler.WithVolumes(volumes...),
|
||||||
compiler.WithWorkspace(
|
compiler.WithWorkspace(
|
||||||
|
@ -211,9 +240,7 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
|
||||||
compiler.WithNetworks(
|
compiler.WithNetworks(
|
||||||
c.StringSlice("network")...,
|
c.StringSlice("network")...,
|
||||||
),
|
),
|
||||||
compiler.WithPrefix(
|
compiler.WithPrefix(prefix),
|
||||||
c.String("prefix"),
|
|
||||||
),
|
|
||||||
compiler.WithProxy(compiler.ProxyOptions{
|
compiler.WithProxy(compiler.ProxyOptions{
|
||||||
NoProxy: c.String("backend-no-proxy"),
|
NoProxy: c.String("backend-no-proxy"),
|
||||||
HTTPProxy: c.String("backend-http-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-password"),
|
||||||
c.String("netrc-machine"),
|
c.String("netrc-machine"),
|
||||||
),
|
),
|
||||||
compiler.WithMetadata(metadata),
|
compiler.WithMetadata(*metadata),
|
||||||
compiler.WithSecret(secrets...),
|
compiler.WithSecret(secrets...),
|
||||||
compiler.WithEnviron(pipelineEnv),
|
compiler.WithEnviron(pipelineEnv),
|
||||||
).Compile(conf)
|
).Compile(conf)
|
||||||
|
@ -235,7 +262,7 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
|
||||||
return err
|
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"))
|
backendEngine, err := backend.FindBackend(backendCtx, backends, c.String("backend-engine"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -245,21 +272,21 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), c.Duration("timeout"))
|
pipelineCtx, cancel := context.WithTimeout(context.Background(), c.Duration("timeout"))
|
||||||
defer cancel()
|
defer cancel()
|
||||||
ctx = utils.WithContextSigtermCallback(ctx, func() {
|
pipelineCtx = utils.WithContextSigtermCallback(pipelineCtx, func() {
|
||||||
fmt.Println("ctrl+c received, terminating process")
|
fmt.Printf("ctrl+c received, terminating current pipeline '%s'\n", confStr)
|
||||||
})
|
})
|
||||||
|
|
||||||
return pipeline.New(compiled,
|
return pipeline.New(compiled,
|
||||||
pipeline.WithContext(ctx),
|
pipeline.WithContext(pipelineCtx), //nolint:contextcheck
|
||||||
pipeline.WithTracer(pipeline.DefaultTracer),
|
pipeline.WithTracer(pipeline.DefaultTracer),
|
||||||
pipeline.WithLogger(defaultLogger),
|
pipeline.WithLogger(defaultLogger),
|
||||||
pipeline.WithBackend(backendEngine),
|
pipeline.WithBackend(backendEngine),
|
||||||
pipeline.WithDescription(map[string]string{
|
pipeline.WithDescription(map[string]string{
|
||||||
"CLI": "exec",
|
"CLI": "exec",
|
||||||
}),
|
}),
|
||||||
).Run(c.Context)
|
).Run(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertPathForWindows converts a path to use slash separators
|
// convertPathForWindows converts a path to use slash separators
|
||||||
|
@ -281,8 +308,7 @@ func convertPathForWindows(path string) string {
|
||||||
return filepath.ToSlash(path)
|
return filepath.ToSlash(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxLogLineLength = 1024 * 1024 // 1mb
|
|
||||||
var defaultLogger = pipeline.Logger(func(step *backend_types.Step, rc io.ReadCloser) error {
|
var defaultLogger = pipeline.Logger(func(step *backend_types.Step, rc io.ReadCloser) error {
|
||||||
logWriter := NewLineWriter(step.Name, step.UUID)
|
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 (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/shared/constant"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var flags = []cli.Flag{
|
var flags = []cli.Flag{
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
EnvVars: []string{"WOODPECKER_LOCAL"},
|
Sources: cli.EnvVars("WOODPECKER_LOCAL"),
|
||||||
Name: "local",
|
Name: "local",
|
||||||
Usage: "run from local directory",
|
Usage: "run from local directory",
|
||||||
Value: true,
|
Value: true,
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"WOODPECKER_REPO_PATH"},
|
Sources: cli.EnvVars("WOODPECKER_REPO_PATH"),
|
||||||
Name: "repo-path",
|
Name: "repo-path",
|
||||||
Usage: "path to local repository",
|
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{
|
&cli.DurationFlag{
|
||||||
EnvVars: []string{"WOODPECKER_TIMEOUT"},
|
Sources: cli.EnvVars("WOODPECKER_TIMEOUT"),
|
||||||
Name: "timeout",
|
Name: "timeout",
|
||||||
Usage: "pipeline timeout",
|
Usage: "pipeline timeout",
|
||||||
Value: time.Hour,
|
Value: time.Hour,
|
||||||
},
|
},
|
||||||
&cli.StringSliceFlag{
|
&cli.StringSliceFlag{
|
||||||
EnvVars: []string{"WOODPECKER_VOLUMES"},
|
Sources: cli.EnvVars("WOODPECKER_VOLUMES"),
|
||||||
Name: "volumes",
|
Name: "volumes",
|
||||||
Usage: "pipeline volumes",
|
Usage: "pipeline volumes",
|
||||||
},
|
},
|
||||||
&cli.StringSliceFlag{
|
&cli.StringSliceFlag{
|
||||||
EnvVars: []string{"WOODPECKER_NETWORKS"},
|
Sources: cli.EnvVars("WOODPECKER_NETWORKS"),
|
||||||
Name: "network",
|
Name: "network",
|
||||||
Usage: "external networks",
|
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{
|
&cli.StringSliceFlag{
|
||||||
Name: "privileged",
|
Sources: cli.EnvVars("WOODPECKER_PLUGINS_PRIVILEGED"),
|
||||||
Usage: "privileged plugins",
|
Name: "plugins-privileged",
|
||||||
Value: cli.NewStringSlice(constant.PrivilegedPlugins...),
|
Usage: "Allow plugins to run in privileged mode, if environment variable is defined but empty there will be none",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"WOODPECKER_BACKEND"},
|
Sources: cli.EnvVars("WOODPECKER_BACKEND"),
|
||||||
Name: "backend-engine",
|
Name: "backend-engine",
|
||||||
Usage: "backend engine to run pipelines on",
|
Usage: "backend engine to run pipelines on",
|
||||||
Value: "auto-detect",
|
Value: "auto-detect",
|
||||||
|
@ -73,17 +69,17 @@ var flags = []cli.Flag{
|
||||||
// backend options for pipeline compiler
|
// backend options for pipeline compiler
|
||||||
//
|
//
|
||||||
&cli.StringFlag{
|
&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",
|
Usage: "if set, pass the environment variable down as \"NO_PROXY\" to steps",
|
||||||
Name: "backend-no-proxy",
|
Name: "backend-no-proxy",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&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",
|
Usage: "if set, pass the environment variable down as \"HTTP_PROXY\" to steps",
|
||||||
Name: "backend-http-proxy",
|
Name: "backend-http-proxy",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&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",
|
Usage: "if set, pass the environment variable down as \"HTTPS_PROXY\" to steps",
|
||||||
Name: "backend-https-proxy",
|
Name: "backend-https-proxy",
|
||||||
},
|
},
|
||||||
|
@ -97,12 +93,12 @@ var flags = []cli.Flag{
|
||||||
// workspace default
|
// workspace default
|
||||||
//
|
//
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_WORKSPACE_BASE"},
|
Sources: cli.EnvVars("CI_WORKSPACE_BASE"),
|
||||||
Name: "workspace-base",
|
Name: "workspace-base",
|
||||||
Value: "/woodpecker",
|
Value: "/woodpecker",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_WORKSPACE_PATH"},
|
Sources: cli.EnvVars("CI_WORKSPACE_PATH"),
|
||||||
Name: "workspace-path",
|
Name: "workspace-path",
|
||||||
Value: "src",
|
Value: "src",
|
||||||
},
|
},
|
||||||
|
@ -110,218 +106,298 @@ var flags = []cli.Flag{
|
||||||
// netrc parameters
|
// netrc parameters
|
||||||
//
|
//
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_NETRC_USERNAME"},
|
Sources: cli.EnvVars("CI_NETRC_USERNAME"),
|
||||||
Name: "netrc-username",
|
Name: "netrc-username",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_NETRC_PASSWORD"},
|
Sources: cli.EnvVars("CI_NETRC_PASSWORD"),
|
||||||
Name: "netrc-password",
|
Name: "netrc-password",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_NETRC_MACHINE"},
|
Sources: cli.EnvVars("CI_NETRC_MACHINE"),
|
||||||
Name: "netrc-machine",
|
Name: "netrc-machine",
|
||||||
},
|
},
|
||||||
//
|
//
|
||||||
// metadata parameters
|
// metadata parameters
|
||||||
//
|
//
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_SYSTEM_PLATFORM"},
|
Sources: cli.EnvVars("CI_SYSTEM_PLATFORM"),
|
||||||
Name: "system-platform",
|
Name: "system-platform",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_SYSTEM_PLATFORM\".",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&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",
|
Name: "system-name",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_SYSTEM_NAME\".",
|
||||||
Value: "woodpecker",
|
Value: "woodpecker",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_SYSTEM_URL"},
|
Sources: cli.EnvVars("CI_SYSTEM_URL"),
|
||||||
Name: "system-url",
|
Name: "system-url",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_SYSTEM_URL\".",
|
||||||
Value: "https://github.com/woodpecker-ci/woodpecker",
|
Value: "https://github.com/woodpecker-ci/woodpecker",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_REPO"},
|
Sources: cli.EnvVars("CI_REPO"),
|
||||||
Name: "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{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_REPO_REMOTE_ID"},
|
Sources: cli.EnvVars("CI_REPO_REMOTE_ID"),
|
||||||
Name: "repo-remote-id",
|
Name: "repo-remote-id",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_REPO_REMOTE_ID\".",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_REPO_URL"},
|
Sources: cli.EnvVars("CI_REPO_URL"),
|
||||||
Name: "repo-url",
|
Name: "repo-url",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_REPO_URL\".",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&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",
|
Name: "repo-clone-url",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_REPO_CLONE_URL\".",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_REPO_CLONE_SSH_URL"},
|
Sources: cli.EnvVars("CI_REPO_CLONE_SSH_URL"),
|
||||||
Name: "repo-clone-ssh-url",
|
Name: "repo-clone-ssh-url",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_REPO_CLONE_SSH_URL\".",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_REPO_PRIVATE"},
|
Sources: cli.EnvVars("CI_REPO_PRIVATE"),
|
||||||
Name: "repo-private",
|
Name: "repo-private",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_REPO_PRIVATE\".",
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
EnvVars: []string{"CI_REPO_TRUSTED"},
|
Sources: cli.EnvVars("CI_REPO_TRUSTED_NETWORK"),
|
||||||
Name: "repo-trusted",
|
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{
|
&cli.IntFlag{
|
||||||
EnvVars: []string{"CI_PIPELINE_NUMBER"},
|
Sources: cli.EnvVars("CI_PIPELINE_NUMBER"),
|
||||||
Name: "pipeline-number",
|
Name: "pipeline-number",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_PIPELINE_NUMBER\".",
|
||||||
},
|
},
|
||||||
&cli.IntFlag{
|
&cli.IntFlag{
|
||||||
EnvVars: []string{"CI_PIPELINE_PARENT"},
|
Sources: cli.EnvVars("CI_PIPELINE_PARENT"),
|
||||||
Name: "pipeline-parent",
|
Name: "pipeline-parent",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_PIPELINE_PARENT\".",
|
||||||
},
|
},
|
||||||
&cli.Int64Flag{
|
&cli.IntFlag{
|
||||||
EnvVars: []string{"CI_PIPELINE_CREATED"},
|
Sources: cli.EnvVars("CI_PIPELINE_CREATED"),
|
||||||
Name: "pipeline-created",
|
Name: "pipeline-created",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_PIPELINE_CREATED\".",
|
||||||
},
|
},
|
||||||
&cli.Int64Flag{
|
&cli.IntFlag{
|
||||||
EnvVars: []string{"CI_PIPELINE_STARTED"},
|
Sources: cli.EnvVars("CI_PIPELINE_STARTED"),
|
||||||
Name: "pipeline-started",
|
Name: "pipeline-started",
|
||||||
},
|
Usage: "Set the metadata environment variable \"CI_PIPELINE_STARTED\".",
|
||||||
&cli.Int64Flag{
|
|
||||||
EnvVars: []string{"CI_PIPELINE_FINISHED"},
|
|
||||||
Name: "pipeline-finished",
|
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_PIPELINE_STATUS"},
|
Sources: cli.EnvVars("CI_PIPELINE_EVENT"),
|
||||||
Name: "pipeline-status",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
EnvVars: []string{"CI_PIPELINE_EVENT"},
|
|
||||||
Name: "pipeline-event",
|
Name: "pipeline-event",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_PIPELINE_EVENT\".",
|
||||||
Value: "manual",
|
Value: "manual",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_PIPELINE_URL"},
|
Sources: cli.EnvVars("CI_PIPELINE_FORGE_URL"),
|
||||||
Name: "pipeline-url",
|
Name: "pipeline-url",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_PIPELINE_FORGE_URL\".",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&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",
|
Name: "pipeline-deploy-to",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_PIPELINE_DEPLOY_TARGET\".",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&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",
|
Name: "pipeline-deploy-task",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_PIPELINE_DEPLOY_TASK\".",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&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",
|
Name: "commit-sha",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_COMMIT_SHA\".",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_COMMIT_REF"},
|
Sources: cli.EnvVars("CI_COMMIT_REF"),
|
||||||
Name: "commit-ref",
|
Name: "commit-ref",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_COMMIT_REF\".",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_COMMIT_REFSPEC"},
|
Sources: cli.EnvVars("CI_COMMIT_REFSPEC"),
|
||||||
Name: "commit-refspec",
|
Name: "commit-refspec",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_COMMIT_REFSPEC\".",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_COMMIT_BRANCH"},
|
Sources: cli.EnvVars("CI_COMMIT_BRANCH"),
|
||||||
Name: "commit-branch",
|
Name: "commit-branch",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_COMMIT_BRANCH\".",
|
||||||
|
Value: "main",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_COMMIT_MESSAGE"},
|
Sources: cli.EnvVars("CI_COMMIT_MESSAGE"),
|
||||||
Name: "commit-message",
|
Name: "commit-message",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_COMMIT_MESSAGE\".",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_COMMIT_AUTHOR_NAME"},
|
Sources: cli.EnvVars("CI_COMMIT_AUTHOR"),
|
||||||
Name: "commit-author-name",
|
Name: "commit-author-name",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_COMMIT_AUTHOR\".",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_COMMIT_AUTHOR_AVATAR"},
|
Sources: cli.EnvVars("CI_COMMIT_AUTHOR_AVATAR"),
|
||||||
Name: "commit-author-avatar",
|
Name: "commit-author-avatar",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_COMMIT_AUTHOR_AVATAR\".",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_COMMIT_AUTHOR_EMAIL"},
|
Sources: cli.EnvVars("CI_COMMIT_AUTHOR_EMAIL"),
|
||||||
Name: "commit-author-email",
|
Name: "commit-author-email",
|
||||||
},
|
Usage: "Set the metadata environment variable \"CI_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",
|
|
||||||
},
|
},
|
||||||
&cli.StringSliceFlag{
|
&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",
|
Name: "env",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_ENV\".",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_FORGE_TYPE"},
|
Sources: cli.EnvVars("CI_FORGE_TYPE"),
|
||||||
Name: "forge-type",
|
Name: "forge-type",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_FORGE_TYPE\".",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_FORGE_URL"},
|
Sources: cli.EnvVars("CI_FORGE_URL"),
|
||||||
Name: "forge-url",
|
Name: "forge-url",
|
||||||
|
Usage: "Set the metadata environment variable \"CI_FORGE_URL\".",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,105 +15,147 @@
|
||||||
package exec
|
package exec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"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/v3/pipeline/frontend/metadata"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/matrix"
|
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml/matrix"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/version"
|
"go.woodpecker-ci.org/woodpecker/v3/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
// return the metadata from the cli context.
|
// 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")
|
platform := c.String("system-platform")
|
||||||
if platform == "" {
|
if platform == "" {
|
||||||
platform = runtime.GOOS + "/" + runtime.GOARCH
|
platform = runtime.GOOS + "/" + runtime.GOARCH
|
||||||
}
|
}
|
||||||
|
|
||||||
fullRepoName := c.String("repo-name")
|
metadataFileAndOverrideOrDefault(c, "repo-name", func(fullRepoName string) {
|
||||||
repoOwner := ""
|
if idx := strings.LastIndex(fullRepoName, "/"); idx != -1 {
|
||||||
repoName := ""
|
m.Repo.Owner = fullRepoName[:idx]
|
||||||
if idx := strings.LastIndex(fullRepoName, "/"); idx != -1 {
|
m.Repo.Name = fullRepoName[idx+1:]
|
||||||
repoOwner = fullRepoName[:idx]
|
}
|
||||||
repoName = 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
|
||||||
Repo: metadata.Repo{
|
metadataFileAndOverrideOrDefault(c, "repo-remote-id", func(s string) { m.Repo.RemoteID = s }, c.String)
|
||||||
Name: repoName,
|
metadataFileAndOverrideOrDefault(c, "repo-url", func(s string) { m.Repo.ForgeURL = s }, c.String)
|
||||||
Owner: repoOwner,
|
metadataFileAndOverrideOrDefault(c, "repo-default-branch", func(s string) { m.Repo.Branch = s }, c.String)
|
||||||
RemoteID: c.String("repo-remote-id"),
|
metadataFileAndOverrideOrDefault(c, "repo-clone-url", func(s string) { m.Repo.CloneURL = s }, c.String)
|
||||||
ForgeURL: c.String("repo-url"),
|
metadataFileAndOverrideOrDefault(c, "repo-clone-ssh-url", func(s string) { m.Repo.CloneSSHURL = s }, c.String)
|
||||||
CloneURL: c.String("repo-clone-url"),
|
metadataFileAndOverrideOrDefault(c, "repo-private", func(b bool) { m.Repo.Private = b }, c.Bool)
|
||||||
CloneSSHURL: c.String("repo-clone-ssh-url"),
|
metadataFileAndOverrideOrDefault(c, "repo-trusted-network", func(b bool) { m.Repo.Trusted.Network = b }, c.Bool)
|
||||||
Private: c.Bool("repo-private"),
|
metadataFileAndOverrideOrDefault(c, "repo-trusted-security", func(b bool) { m.Repo.Trusted.Security = b }, c.Bool)
|
||||||
Trusted: c.Bool("repo-trusted"),
|
metadataFileAndOverrideOrDefault(c, "repo-trusted-volumes", func(b bool) { m.Repo.Trusted.Volumes = b }, c.Bool)
|
||||||
},
|
|
||||||
Curr: metadata.Pipeline{
|
// Current Pipeline
|
||||||
Number: c.Int64("pipeline-number"),
|
metadataFileAndOverrideOrDefault(c, "pipeline-number", func(i int64) { m.Curr.Number = i }, c.Int)
|
||||||
Parent: c.Int64("pipeline-parent"),
|
metadataFileAndOverrideOrDefault(c, "pipeline-parent", func(i int64) { m.Curr.Parent = i }, c.Int)
|
||||||
Created: c.Int64("pipeline-created"),
|
metadataFileAndOverrideOrDefault(c, "pipeline-created", func(i int64) { m.Curr.Created = i }, c.Int)
|
||||||
Started: c.Int64("pipeline-started"),
|
metadataFileAndOverrideOrDefault(c, "pipeline-started", func(i int64) { m.Curr.Started = i }, c.Int)
|
||||||
Finished: c.Int64("pipeline-finished"),
|
metadataFileAndOverrideOrDefault(c, "pipeline-finished", func(i int64) { m.Curr.Finished = i }, c.Int)
|
||||||
Status: c.String("pipeline-status"),
|
metadataFileAndOverrideOrDefault(c, "pipeline-status", func(s string) { m.Curr.Status = s }, c.String)
|
||||||
Event: c.String("pipeline-event"),
|
metadataFileAndOverrideOrDefault(c, "pipeline-event", func(s string) { m.Curr.Event = s }, c.String)
|
||||||
ForgeURL: c.String("pipeline-url"),
|
metadataFileAndOverrideOrDefault(c, "pipeline-url", func(s string) { m.Curr.ForgeURL = s }, c.String)
|
||||||
DeployTo: c.String("pipeline-deploy-to"),
|
metadataFileAndOverrideOrDefault(c, "pipeline-deploy-to", func(s string) { m.Curr.DeployTo = s }, c.String)
|
||||||
DeployTask: c.String("pipeline-deploy-task"),
|
metadataFileAndOverrideOrDefault(c, "pipeline-deploy-task", func(s string) { m.Curr.DeployTask = s }, c.String)
|
||||||
Commit: metadata.Commit{
|
|
||||||
Sha: c.String("commit-sha"),
|
// Current Pipeline Commit
|
||||||
Ref: c.String("commit-ref"),
|
metadataFileAndOverrideOrDefault(c, "commit-sha", func(s string) { m.Curr.Commit.Sha = s }, c.String)
|
||||||
Refspec: c.String("commit-refspec"),
|
metadataFileAndOverrideOrDefault(c, "commit-ref", func(s string) { m.Curr.Commit.Ref = s }, c.String)
|
||||||
Branch: c.String("commit-branch"),
|
metadataFileAndOverrideOrDefault(c, "commit-refspec", func(s string) { m.Curr.Commit.Refspec = s }, c.String)
|
||||||
Message: c.String("commit-message"),
|
metadataFileAndOverrideOrDefault(c, "commit-branch", func(s string) { m.Curr.Commit.Branch = s }, c.String)
|
||||||
Author: metadata.Author{
|
metadataFileAndOverrideOrDefault(c, "commit-message", func(s string) { m.Curr.Commit.Message = s }, c.String)
|
||||||
Name: c.String("commit-author-name"),
|
metadataFileAndOverrideOrDefault(c, "commit-author-name", func(s string) { m.Curr.Commit.Author.Name = s }, c.String)
|
||||||
Email: c.String("commit-author-email"),
|
metadataFileAndOverrideOrDefault(c, "commit-author-email", func(s string) { m.Curr.Commit.Author.Email = s }, c.String)
|
||||||
Avatar: c.String("commit-author-avatar"),
|
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)
|
||||||
Prev: metadata.Pipeline{
|
|
||||||
Number: c.Int64("prev-pipeline-number"),
|
// Previous Pipeline
|
||||||
Created: c.Int64("prev-pipeline-created"),
|
metadataFileAndOverrideOrDefault(c, "prev-pipeline-number", func(i int64) { m.Prev.Number = i }, c.Int)
|
||||||
Started: c.Int64("prev-pipeline-started"),
|
metadataFileAndOverrideOrDefault(c, "prev-pipeline-created", func(i int64) { m.Prev.Created = i }, c.Int)
|
||||||
Finished: c.Int64("prev-pipeline-finished"),
|
metadataFileAndOverrideOrDefault(c, "prev-pipeline-started", func(i int64) { m.Prev.Started = i }, c.Int)
|
||||||
Status: c.String("prev-pipeline-status"),
|
metadataFileAndOverrideOrDefault(c, "prev-pipeline-finished", func(i int64) { m.Prev.Finished = i }, c.Int)
|
||||||
Event: c.String("prev-pipeline-event"),
|
metadataFileAndOverrideOrDefault(c, "prev-pipeline-status", func(s string) { m.Prev.Status = s }, c.String)
|
||||||
ForgeURL: c.String("prev-pipeline-url"),
|
metadataFileAndOverrideOrDefault(c, "prev-pipeline-event", func(s string) { m.Prev.Event = s }, c.String)
|
||||||
Commit: metadata.Commit{
|
metadataFileAndOverrideOrDefault(c, "prev-pipeline-url", func(s string) { m.Prev.ForgeURL = s }, c.String)
|
||||||
Sha: c.String("prev-commit-sha"),
|
|
||||||
Ref: c.String("prev-commit-ref"),
|
// Previous Pipeline Commit
|
||||||
Refspec: c.String("prev-commit-refspec"),
|
metadataFileAndOverrideOrDefault(c, "prev-commit-sha", func(s string) { m.Prev.Commit.Sha = s }, c.String)
|
||||||
Branch: c.String("prev-commit-branch"),
|
metadataFileAndOverrideOrDefault(c, "prev-commit-ref", func(s string) { m.Prev.Commit.Ref = s }, c.String)
|
||||||
Message: c.String("prev-commit-message"),
|
metadataFileAndOverrideOrDefault(c, "prev-commit-refspec", func(s string) { m.Prev.Commit.Refspec = s }, c.String)
|
||||||
Author: metadata.Author{
|
metadataFileAndOverrideOrDefault(c, "prev-commit-branch", func(s string) { m.Prev.Commit.Branch = s }, c.String)
|
||||||
Name: c.String("prev-commit-author-name"),
|
metadataFileAndOverrideOrDefault(c, "prev-commit-message", func(s string) { m.Prev.Commit.Message = s }, c.String)
|
||||||
Email: c.String("prev-commit-author-email"),
|
metadataFileAndOverrideOrDefault(c, "prev-commit-author-name", func(s string) { m.Prev.Commit.Author.Name = s }, c.String)
|
||||||
Avatar: c.String("prev-commit-author-avatar"),
|
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
|
||||||
Workflow: metadata.Workflow{
|
metadataFileAndOverrideOrDefault(c, "workflow-name", func(s string) { m.Workflow.Name = s }, c.String)
|
||||||
Name: c.String("workflow-name"),
|
metadataFileAndOverrideOrDefault(c, "workflow-number", func(i int64) { m.Workflow.Number = int(i) }, c.Int)
|
||||||
Number: c.Int("workflow-number"),
|
m.Workflow.Matrix = axis
|
||||||
Matrix: axis,
|
|
||||||
},
|
// System
|
||||||
Step: metadata.Step{
|
metadataFileAndOverrideOrDefault(c, "system-name", func(s string) { m.Sys.Name = s }, c.String)
|
||||||
Name: c.String("step-name"),
|
metadataFileAndOverrideOrDefault(c, "system-url", func(s string) { m.Sys.URL = s }, c.String)
|
||||||
Number: c.Int("step-number"),
|
metadataFileAndOverrideOrDefault(c, "system-host", func(s string) { m.Sys.Host = s }, c.String)
|
||||||
},
|
m.Sys.Platform = platform
|
||||||
Sys: metadata.System{
|
m.Sys.Version = version.Version
|
||||||
Name: c.String("system-name"),
|
|
||||||
URL: c.String("system-url"),
|
// Forge
|
||||||
Platform: platform,
|
metadataFileAndOverrideOrDefault(c, "forge-type", func(s string) { m.Forge.Type = s }, c.String)
|
||||||
Version: version.Version,
|
metadataFileAndOverrideOrDefault(c, "forge-url", func(s string) { m.Forge.URL = s }, c.String)
|
||||||
},
|
|
||||||
Forge: metadata.Forge{
|
if w != nil {
|
||||||
Type: c.String("forge-type"),
|
m.Workflow = *w
|
||||||
URL: c.String("forge-url"),
|
}
|
||||||
},
|
|
||||||
|
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
|
package info
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"text/template"
|
"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/v3/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Command exports the info command.
|
// Command exports the info command.
|
||||||
|
@ -33,8 +34,8 @@ var Command = &cli.Command{
|
||||||
Flags: []cli.Flag{common.FormatFlag(tmplInfo, true)},
|
Flags: []cli.Flag{common.FormatFlag(tmplInfo, true)},
|
||||||
}
|
}
|
||||||
|
|
||||||
func info(c *cli.Context) error {
|
func info(ctx context.Context, c *cli.Command) error {
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
|
@ -8,7 +9,7 @@ import (
|
||||||
|
|
||||||
"github.com/adrg/xdg"
|
"github.com/adrg/xdg"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
"github.com/zalando/go-keyring"
|
"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", ""}
|
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) {
|
if firstArg := c.Args().First(); slices.Contains(skipSetupForCommands, firstArg) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
config, err := Get(c, c.String("config"))
|
config, err := Get(ctx, c, c.String("config"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.ServerURL == "" || config.Token == "" {
|
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")
|
return errors.New("woodpecker-cli is not configured")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +63,7 @@ func Load(c *cli.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug().Any("config", config).Msg("Loaded config")
|
log.Debug().Any("config", config).Msg("loaded config")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -80,11 +81,11 @@ func getConfigPath(configPath string) (string, error) {
|
||||||
return configPath, nil
|
return configPath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Get(ctx *cli.Context, _configPath string) (*Config, error) {
|
func Get(_ context.Context, c *cli.Command, _configPath string) (*Config, error) {
|
||||||
c := &Config{
|
conf := &Config{
|
||||||
LogLevel: ctx.String("log-level"),
|
LogLevel: c.String("log-level"),
|
||||||
Token: ctx.String("token"),
|
Token: c.String("token"),
|
||||||
ServerURL: ctx.String("server"),
|
ServerURL: c.String("server"),
|
||||||
}
|
}
|
||||||
|
|
||||||
configPath, err := getConfigPath(_configPath)
|
configPath, err := getConfigPath(_configPath)
|
||||||
|
@ -92,16 +93,16 @@ func Get(ctx *cli.Context, _configPath string) (*Config, error) {
|
||||||
return nil, err
|
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)
|
content, err := os.ReadFile(configPath)
|
||||||
switch {
|
switch {
|
||||||
case err != nil && !os.IsNotExist(err):
|
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
|
return nil, err
|
||||||
|
|
||||||
case err != nil && os.IsNotExist(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:
|
default:
|
||||||
configFromFile := &Config{}
|
configFromFile := &Config{}
|
||||||
|
@ -109,33 +110,33 @@ func Get(ctx *cli.Context, _configPath string) (*Config, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c.MergeIfNotSet(configFromFile)
|
conf.MergeIfNotSet(configFromFile)
|
||||||
log.Debug().Msg("Loaded config from file")
|
log.Debug().Msg("loaded config from file")
|
||||||
}
|
}
|
||||||
|
|
||||||
// if server or token are explicitly set, use them
|
// if server or token are explicitly set, use them
|
||||||
if ctx.IsSet("server") || ctx.IsSet("token") {
|
if c.IsSet("server") || c.IsSet("token") {
|
||||||
return c, nil
|
return conf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// load token from keyring
|
// load token from keyring
|
||||||
service := ctx.App.Name
|
service := c.Root().Name
|
||||||
secret, err := keyring.Get(service, c.ServerURL)
|
secret, err := keyring.Get(service, conf.ServerURL)
|
||||||
if errors.Is(err, keyring.ErrUnsupportedPlatform) {
|
if errors.Is(err, keyring.ErrUnsupportedPlatform) {
|
||||||
log.Warn().Msg("Keyring is not supported on this platform")
|
log.Warn().Msg("keyring is not supported on this platform")
|
||||||
return c, nil
|
return conf, nil
|
||||||
}
|
}
|
||||||
if errors.Is(err, keyring.ErrNotFound) {
|
if errors.Is(err, keyring.ErrNotFound) {
|
||||||
log.Warn().Msg("Token not found in keyring")
|
log.Warn().Msg("token not found in keyring")
|
||||||
return c, nil
|
return conf, nil
|
||||||
}
|
}
|
||||||
c.Token = secret
|
conf.Token = secret
|
||||||
|
|
||||||
return c, nil
|
return conf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Save(ctx *cli.Context, _configPath string, c *Config) error {
|
func Save(_ context.Context, c *cli.Command, _configPath string, conf *Config) error {
|
||||||
config, err := json.Marshal(c)
|
config, err := json.Marshal(conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -146,8 +147,8 @@ func Save(ctx *cli.Context, _configPath string, c *Config) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// save token to keyring
|
// save token to keyring
|
||||||
service := ctx.App.Name
|
service := c.Root().Name
|
||||||
err = keyring.Set(service, c.ServerURL, c.Token)
|
err = keyring.Set(service, conf.ServerURL, conf.Token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
package internal
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -25,15 +26,15 @@ import (
|
||||||
|
|
||||||
vsc_url "github.com/gitsight/go-vcsurl"
|
vsc_url "github.com/gitsight/go-vcsurl"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
"golang.org/x/net/proxy"
|
"golang.org/x/net/proxy"
|
||||||
"golang.org/x/oauth2"
|
"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.
|
// 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 (
|
var (
|
||||||
skip = c.Bool("skip-verify")
|
skip = c.Bool("skip-verify")
|
||||||
socks = c.String("socks-proxy")
|
socks = c.String("socks-proxy")
|
||||||
|
@ -63,8 +64,7 @@ func NewClient(c *cli.Context) (woodpecker.Client, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
config := new(oauth2.Config)
|
config := new(oauth2.Config)
|
||||||
client := config.Client(
|
client := config.Client(ctx,
|
||||||
c.Context,
|
|
||||||
&oauth2.Token{
|
&oauth2.Token{
|
||||||
AccessToken: token,
|
AccessToken: token,
|
||||||
},
|
},
|
||||||
|
@ -161,3 +161,40 @@ func ParseKeyPair(p []string) map[string]string {
|
||||||
}
|
}
|
||||||
return params
|
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
|
package lint
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml"
|
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/linter"
|
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml/linter"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v3/shared/constant"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Command exports the info command.
|
// Command exports the info command.
|
||||||
|
@ -34,13 +36,31 @@ var Command = &cli.Command{
|
||||||
Usage: "lint a pipeline configuration file",
|
Usage: "lint a pipeline configuration file",
|
||||||
ArgsUsage: "[path/to/.woodpecker.yaml]",
|
ArgsUsage: "[path/to/.woodpecker.yaml]",
|
||||||
Action: lint,
|
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 {
|
func lint(ctx context.Context, c *cli.Command) error {
|
||||||
return common.RunPipelineFunc(c, lintFile, lintDir)
|
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
|
var errorStrings []string
|
||||||
if err := filepath.Walk(dir, func(path string, info os.FileInfo, e error) error {
|
if err := filepath.Walk(dir, func(path string, info os.FileInfo, e error) error {
|
||||||
if e != nil {
|
if e != nil {
|
||||||
|
@ -50,7 +70,7 @@ func lintDir(c *cli.Context, dir string) error {
|
||||||
// check if it is a regular file (not dir)
|
// check if it is a regular file (not dir)
|
||||||
if info.Mode().IsRegular() && (strings.HasSuffix(info.Name(), ".yaml") || strings.HasSuffix(info.Name(), ".yml")) {
|
if info.Mode().IsRegular() && (strings.HasSuffix(info.Name(), ".yaml") || strings.HasSuffix(info.Name(), ".yml")) {
|
||||||
fmt.Println("#", info.Name())
|
fmt.Println("#", info.Name())
|
||||||
if err := lintFile(c, path); err != nil {
|
if err := lintFile(ctx, c, path); err != nil {
|
||||||
errorStrings = append(errorStrings, err.Error())
|
errorStrings = append(errorStrings, err.Error())
|
||||||
}
|
}
|
||||||
fmt.Println("")
|
fmt.Println("")
|
||||||
|
@ -68,7 +88,7 @@ func lintDir(c *cli.Context, dir string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func lintFile(_ *cli.Context, file string) error {
|
func lintFile(_ context.Context, c *cli.Command, file string) error {
|
||||||
fi, err := os.Open(file)
|
fi, err := os.Open(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -82,7 +102,7 @@ func lintFile(_ *cli.Context, file string) error {
|
||||||
|
|
||||||
rawConfig := string(buf)
|
rawConfig := string(buf)
|
||||||
|
|
||||||
c, err := yaml.ParseString(rawConfig)
|
parsedConfig, err := yaml.ParseString(rawConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -90,13 +110,21 @@ func lintFile(_ *cli.Context, file string) error {
|
||||||
config := &linter.WorkflowConfig{
|
config := &linter.WorkflowConfig{
|
||||||
File: path.Base(file),
|
File: path.Base(file),
|
||||||
RawConfig: rawConfig,
|
RawConfig: rawConfig,
|
||||||
Workflow: c,
|
Workflow: parsedConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: lint multiple files at once to allow checks for sth like "depends_on" to work
|
// 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 {
|
if err != nil {
|
||||||
str, err := FormatLintError(config.File, err)
|
str, err := FormatLintError(config.File, err, c.Bool("strict"))
|
||||||
|
|
||||||
if str != "" {
|
if str != "" {
|
||||||
fmt.Print(str)
|
fmt.Print(str)
|
||||||
|
|
|
@ -7,10 +7,10 @@ import (
|
||||||
|
|
||||||
term_env "github.com/muesli/termenv"
|
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 {
|
if err == nil {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ func FormatLintError(file string, err error) (string, error) {
|
||||||
for _, err := range linterErrors {
|
for _, err := range linterErrors {
|
||||||
line := " "
|
line := " "
|
||||||
|
|
||||||
if err.IsWarning {
|
if !strict && err.IsWarning {
|
||||||
line = fmt.Sprintf("%s ⚠️ ", line)
|
line = fmt.Sprintf("%s ⚠️ ", line)
|
||||||
amountWarnings++
|
amountWarnings++
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -15,16 +15,18 @@
|
||||||
package org
|
package org
|
||||||
|
|
||||||
import (
|
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.
|
// Command exports the org command set.
|
||||||
var Command = &cli.Command{
|
var Command = &cli.Command{
|
||||||
Name: "org",
|
Name: "org",
|
||||||
Usage: "manage organizations",
|
Usage: "manage organizations",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
registry.Command,
|
registry.Command,
|
||||||
|
secret.Command,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,25 +17,25 @@ package registry
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"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.
|
// Command exports the registry command set.
|
||||||
var Command = &cli.Command{
|
var Command = &cli.Command{
|
||||||
Name: "registry",
|
Name: "registry",
|
||||||
Usage: "manage organization registries",
|
Usage: "manage organization registries",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
registryCreateCmd,
|
registryCreateCmd,
|
||||||
registryDeleteCmd,
|
registryDeleteCmd,
|
||||||
registryUpdateCmd,
|
|
||||||
registryInfoCmd,
|
|
||||||
registryListCmd,
|
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")
|
orgIDOrName := c.String("organization")
|
||||||
if orgIDOrName == "" {
|
if orgIDOrName == "" {
|
||||||
orgIDOrName = c.Args().First()
|
orgIDOrName = c.Args().First()
|
||||||
|
|
|
@ -15,19 +15,20 @@
|
||||||
package registry
|
package registry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||||
)
|
)
|
||||||
|
|
||||||
var registryCreateCmd = &cli.Command{
|
var registryCreateCmd = &cli.Command{
|
||||||
Name: "add",
|
Name: "add",
|
||||||
Usage: "adds a registry",
|
Usage: "add a registry",
|
||||||
ArgsUsage: "[org-id|org-full-name]",
|
ArgsUsage: "[org-id|org-full-name]",
|
||||||
Action: registryCreate,
|
Action: registryCreate,
|
||||||
Flags: []cli.Flag{
|
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 (
|
var (
|
||||||
hostname = c.String("hostname")
|
hostname = c.String("hostname")
|
||||||
username = c.String("username")
|
username = c.String("username")
|
||||||
password = c.String("password")
|
password = c.String("password")
|
||||||
)
|
)
|
||||||
|
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,13 +15,15 @@
|
||||||
package registry
|
package registry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"html/template"
|
"html/template"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||||
"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 registryListCmd = &cli.Command{
|
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"
|
format := c.String("format") + "\n"
|
||||||
|
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -48,7 +50,9 @@ func registryList(c *cli.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
list, err := client.OrgRegistryList(orgID)
|
opt := woodpecker.RegistryListOptions{}
|
||||||
|
|
||||||
|
list, err := client.OrgRegistryList(orgID, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,12 @@
|
||||||
package registry
|
package registry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/urfave/cli/v2"
|
"context"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"github.com/urfave/cli/v3"
|
||||||
"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 registryDeleteCmd = &cli.Command{
|
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")
|
hostname := c.String("hostname")
|
||||||
|
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,14 +15,15 @@
|
||||||
package registry
|
package registry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||||
)
|
)
|
||||||
|
|
||||||
var registryUpdateCmd = &cli.Command{
|
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 (
|
var (
|
||||||
hostname = c.String("hostname")
|
hostname = c.String("hostname")
|
||||||
username = c.String("username")
|
username = c.String("username")
|
||||||
password = c.String("password")
|
password = c.String("password")
|
||||||
)
|
)
|
||||||
|
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,20 +15,21 @@
|
||||||
package registry
|
package registry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"html/template"
|
"html/template"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
var registryInfoCmd = &cli.Command{
|
var registryShowCmd = &cli.Command{
|
||||||
Name: "info",
|
Name: "show",
|
||||||
Usage: "display registry info",
|
Usage: "show registry information",
|
||||||
ArgsUsage: "[org-id|org-full-name]",
|
ArgsUsage: "[org-id|org-full-name]",
|
||||||
Action: registryInfo,
|
Action: registryShow,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
common.OrgFlag,
|
common.OrgFlag,
|
||||||
&cli.StringFlag{
|
&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 (
|
var (
|
||||||
hostname = c.String("hostname")
|
hostname = c.String("hostname")
|
||||||
format = c.String("format") + "\n"
|
format = c.String("format") + "\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
package secret
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||||
)
|
)
|
||||||
|
|
||||||
var secretCreateCmd = &cli.Command{
|
var secretCreateCmd = &cli.Command{
|
||||||
Name: "add",
|
Name: "add",
|
||||||
Usage: "adds a secret",
|
Usage: "add a secret",
|
||||||
ArgsUsage: "[repo-id|repo-full-name]",
|
ArgsUsage: "[repo-id|repo-full-name]",
|
||||||
Action: secretCreate,
|
Action: secretCreate,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "global",
|
|
||||||
Usage: "global secret",
|
|
||||||
},
|
|
||||||
common.OrgFlag,
|
common.OrgFlag,
|
||||||
common.RepoFlag,
|
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "name",
|
Name: "name",
|
||||||
Usage: "secret name",
|
Usage: "secret name",
|
||||||
|
@ -56,8 +52,8 @@ var secretCreateCmd = &cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func secretCreate(c *cli.Context) error {
|
func secretCreate(ctx context.Context, c *cli.Command) error {
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -80,22 +76,12 @@ func secretCreate(c *cli.Context) error {
|
||||||
secret.Value = string(out)
|
secret.Value = string(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
global, orgID, repoID, err := parseTargetArgs(client, c)
|
orgID, err := parseTargetArgs(client, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if global {
|
_, err = client.OrgSecretCreate(orgID, secret)
|
||||||
_, err = client.GlobalSecretCreate(secret)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if orgID != -1 {
|
|
||||||
_, err = client.OrgSecretCreate(orgID, secret)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = client.SecretCreate(repoID, secret)
|
|
||||||
return err
|
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"
|
"text/tabwriter"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/go-viper/mapstructure/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewTable creates a new Table.
|
// NewTable creates a new Table.
|
||||||
|
@ -147,12 +147,12 @@ func (o *Table) Write(columns []string, obj any) error {
|
||||||
colName := strings.ToLower(col)
|
colName := strings.ToLower(col)
|
||||||
if alias, ok := o.fieldAlias[colName]; ok {
|
if alias, ok := o.fieldAlias[colName]; ok {
|
||||||
if fn, ok := o.fieldMapping[alias]; ok {
|
if fn, ok := o.fieldMapping[alias]; ok {
|
||||||
out = append(out, fn(obj))
|
out = append(out, sanitizeString(fn(obj)))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if fn, ok := o.fieldMapping[colName]; ok {
|
if fn, ok := o.fieldMapping[colName]; ok {
|
||||||
out = append(out, fn(obj))
|
out = append(out, sanitizeString(fn(obj)))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if value, ok := dataL[strings.ReplaceAll(colName, "_", "")]; ok {
|
if value, ok := dataL[strings.ReplaceAll(colName, "_", "")]; ok {
|
||||||
|
@ -165,10 +165,10 @@ func (o *Table) Write(columns []string, obj any) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if s, ok := value.(string); ok {
|
if s, ok := value.(string); ok {
|
||||||
out = append(out, NA(s))
|
out = append(out, NA(sanitizeString(s)))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
out = append(out, fmt.Sprintf("%v", value))
|
out = append(out, sanitizeString(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintln(o.w, strings.Join(out, "\t"))
|
_, _ = fmt.Fprintln(o.w, strings.Join(out, "\t"))
|
||||||
|
@ -201,3 +201,9 @@ func fieldName(name string) string {
|
||||||
}
|
}
|
||||||
return string(out)
|
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
|
package pipeline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"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{
|
var pipelineApproveCmd = &cli.Command{
|
||||||
|
@ -30,9 +31,9 @@ var pipelineApproveCmd = &cli.Command{
|
||||||
Action: pipelineApprove,
|
Action: pipelineApprove,
|
||||||
}
|
}
|
||||||
|
|
||||||
func pipelineApprove(c *cli.Context) (err error) {
|
func pipelineApprove(ctx context.Context, c *cli.Command) (err error) {
|
||||||
repoIDOrFullName := c.Args().First()
|
repoIDOrFullName := c.Args().First()
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,13 +15,14 @@
|
||||||
package pipeline
|
package pipeline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||||
)
|
)
|
||||||
|
|
||||||
var pipelineCreateCmd = &cli.Command{
|
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()
|
repoIDOrFullName := c.Args().First()
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -73,5 +74,5 @@ func pipelineCreate(c *cli.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return pipelineOutput(c, []woodpecker.Pipeline{*pipeline})
|
return pipelineOutput(c, []*woodpecker.Pipeline{pipeline})
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,13 @@
|
||||||
package pipeline
|
package pipeline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"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{
|
var pipelineDeclineCmd = &cli.Command{
|
||||||
|
@ -30,9 +31,9 @@ var pipelineDeclineCmd = &cli.Command{
|
||||||
Action: pipelineDecline,
|
Action: pipelineDecline,
|
||||||
}
|
}
|
||||||
|
|
||||||
func pipelineDecline(c *cli.Context) (err error) {
|
func pipelineDecline(ctx context.Context, c *cli.Command) (err error) {
|
||||||
repoIDOrFullName := c.Args().First()
|
repoIDOrFullName := c.Args().First()
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,16 +15,17 @@
|
||||||
package deploy
|
package deploy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Command exports the deploy command.
|
// Command exports the deploy command.
|
||||||
|
@ -52,13 +53,13 @@ var Command = &cli.Command{
|
||||||
&cli.StringSliceFlag{
|
&cli.StringSliceFlag{
|
||||||
Name: "param",
|
Name: "param",
|
||||||
Aliases: []string{"p"},
|
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 {
|
func deploy(ctx context.Context, c *cli.Command) error {
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -79,14 +80,14 @@ func deploy(c *cli.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
branch = repo.DefaultBranch
|
branch = repo.Branch
|
||||||
}
|
}
|
||||||
|
|
||||||
pipelineArg := c.Args().Get(1)
|
pipelineArg := c.Args().Get(1)
|
||||||
var number int64
|
var number int64
|
||||||
if pipelineArg == "last" {
|
if pipelineArg == "last" {
|
||||||
// Fetch the pipeline number from the last pipeline
|
// Fetch the pipeline number from the last pipeline
|
||||||
pipelines, err := client.PipelineList(repoID)
|
pipelines, err := client.PipelineList(repoID, woodpecker.PipelineListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -120,9 +121,12 @@ func deploy(c *cli.Context) error {
|
||||||
return fmt.Errorf("please specify the target environment (i.e. production)")
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
|
@ -15,12 +15,13 @@
|
||||||
package pipeline
|
package pipeline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"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{
|
var pipelineKillCmd = &cli.Command{
|
||||||
|
@ -31,14 +32,14 @@ var pipelineKillCmd = &cli.Command{
|
||||||
Hidden: true,
|
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)
|
number, err := strconv.ParseInt(c.Args().Get(1), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
repoIDOrFullName := c.Args().First()
|
repoIDOrFullName := c.Args().First()
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -47,7 +48,7 @@ func pipelineKill(c *cli.Context) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = client.PipelineKill(repoID, number)
|
err = client.PipelineDelete(repoID, number)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,16 +15,18 @@
|
||||||
package pipeline
|
package pipeline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/urfave/cli/v2"
|
"context"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"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/common"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||||
)
|
)
|
||||||
|
|
||||||
var pipelineLastCmd = &cli.Command{
|
var pipelineLastCmd = &cli.Command{
|
||||||
Name: "last",
|
Name: "last",
|
||||||
Usage: "show latest pipeline details",
|
Usage: "show latest pipeline information",
|
||||||
ArgsUsage: "<repo-id|repo-full-name>",
|
ArgsUsage: "<repo-id|repo-full-name>",
|
||||||
Action: pipelineLast,
|
Action: pipelineLast,
|
||||||
Flags: append(common.OutputFlags("table"), []cli.Flag{
|
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()
|
repoIDOrFullName := c.Args().First()
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -47,10 +49,14 @@ func pipelineLast(c *cli.Context) error {
|
||||||
return err
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return pipelineOutput(c, []woodpecker.Pipeline{*pipeline})
|
return pipelineOutput(c, []*woodpecker.Pipeline{pipeline})
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,88 +15,114 @@
|
||||||
package pipeline
|
package pipeline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/urfave/cli/v2"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"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/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
|
//nolint:mnd
|
||||||
var pipelineListCmd = &cli.Command{
|
func buildPipelineListCmd() *cli.Command {
|
||||||
Name: "ls",
|
return &cli.Command{
|
||||||
Usage: "show pipeline history",
|
Name: "ls",
|
||||||
ArgsUsage: "<repo-id|repo-full-name>",
|
Usage: "show pipeline history",
|
||||||
Action: List,
|
ArgsUsage: "<repo-id|repo-full-name>",
|
||||||
Flags: append(common.OutputFlags("table"), []cli.Flag{
|
Action: List,
|
||||||
&cli.StringFlag{
|
Flags: append(common.OutputFlags("table"), []cli.Flag{
|
||||||
Name: "branch",
|
&cli.StringFlag{
|
||||||
Usage: "branch filter",
|
Name: "branch",
|
||||||
},
|
Usage: "branch filter",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "event",
|
&cli.StringFlag{
|
||||||
Usage: "event filter",
|
Name: "event",
|
||||||
},
|
Usage: "event filter",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "status",
|
&cli.StringFlag{
|
||||||
Usage: "status filter",
|
Name: "status",
|
||||||
},
|
Usage: "status filter",
|
||||||
&cli.IntFlag{
|
},
|
||||||
Name: "limit",
|
&cli.IntFlag{
|
||||||
Usage: "limit the list size",
|
Name: "limit",
|
||||||
Value: 25,
|
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 {
|
func List(ctx context.Context, c *cli.Command) error {
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
resources, err := pipelineList(c, client)
|
pipelines, err := pipelineList(c, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return pipelineOutput(c, resources)
|
return pipelineOutput(c, pipelines)
|
||||||
}
|
}
|
||||||
|
|
||||||
func pipelineList(c *cli.Context, client woodpecker.Client) ([]woodpecker.Pipeline, error) {
|
func pipelineList(c *cli.Command, client woodpecker.Client) ([]*woodpecker.Pipeline, error) {
|
||||||
resources := make([]woodpecker.Pipeline, 0)
|
|
||||||
|
|
||||||
repoIDOrFullName := c.Args().First()
|
repoIDOrFullName := c.Args().First()
|
||||||
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
|
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return resources, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
pipelines, err := client.PipelineList(repoID)
|
opt := woodpecker.PipelineListOptions{}
|
||||||
if err != nil {
|
|
||||||
return resources, err
|
if before := c.Timestamp("before"); !before.IsZero() {
|
||||||
|
opt.Before = before
|
||||||
|
}
|
||||||
|
if after := c.Timestamp("after"); !after.IsZero() {
|
||||||
|
opt.After = after
|
||||||
}
|
}
|
||||||
|
|
||||||
branch := c.String("branch")
|
branch := c.String("branch")
|
||||||
event := c.String("event")
|
event := c.String("event")
|
||||||
status := c.String("status")
|
status := c.String("status")
|
||||||
limit := c.Int("limit")
|
limit := int(c.Int("limit"))
|
||||||
|
|
||||||
var count int
|
pipelines, err := shared_utils.Paginate(func(page int) ([]*woodpecker.Pipeline, error) {
|
||||||
for _, pipeline := range pipelines {
|
return client.PipelineList(repoID,
|
||||||
if count >= limit {
|
woodpecker.PipelineListOptions{
|
||||||
break
|
ListOptions: woodpecker.ListOptions{
|
||||||
}
|
Page: page,
|
||||||
if branch != "" && pipeline.Branch != branch {
|
},
|
||||||
continue
|
Before: opt.Before,
|
||||||
}
|
After: opt.After,
|
||||||
if event != "" && pipeline.Event != event {
|
Branch: branch,
|
||||||
continue
|
Events: []string{event},
|
||||||
}
|
Status: status,
|
||||||
if status != "" && pipeline.Status != status {
|
},
|
||||||
continue
|
)
|
||||||
}
|
}, limit)
|
||||||
resources = append(resources, *pipeline)
|
if err != nil {
|
||||||
count++
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return resources, nil
|
return pipelines, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
package pipeline
|
package pipeline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/mock"
|
"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/v3/woodpecker-go/woodpecker"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker/mocks"
|
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker/mocks"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPipelineList(t *testing.T) {
|
func TestPipelineList(t *testing.T) {
|
||||||
|
@ -21,7 +22,7 @@ func TestPipelineList(t *testing.T) {
|
||||||
pipelines []*woodpecker.Pipeline
|
pipelines []*woodpecker.Pipeline
|
||||||
pipelineErr error
|
pipelineErr error
|
||||||
args []string
|
args []string
|
||||||
expected []woodpecker.Pipeline
|
expected []*woodpecker.Pipeline
|
||||||
wantErr error
|
wantErr error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
@ -33,53 +34,12 @@ func TestPipelineList(t *testing.T) {
|
||||||
{ID: 3, Branch: "main", Event: "push", Status: "failure"},
|
{ID: 3, Branch: "main", Event: "push", Status: "failure"},
|
||||||
},
|
},
|
||||||
args: []string{"ls", "repo/name"},
|
args: []string{"ls", "repo/name"},
|
||||||
expected: []woodpecker.Pipeline{
|
expected: []*woodpecker.Pipeline{
|
||||||
{ID: 1, Branch: "main", Event: "push", Status: "success"},
|
{ID: 1, Branch: "main", Event: "push", Status: "success"},
|
||||||
{ID: 2, Branch: "develop", Event: "pull_request", Status: "running"},
|
{ID: 2, Branch: "develop", Event: "pull_request", Status: "running"},
|
||||||
{ID: 3, Branch: "main", Event: "push", Status: "failure"},
|
{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",
|
name: "limit results",
|
||||||
repoID: 1,
|
repoID: 1,
|
||||||
|
@ -89,7 +49,7 @@ func TestPipelineList(t *testing.T) {
|
||||||
{ID: 3, Branch: "main", Event: "push", Status: "failure"},
|
{ID: 3, Branch: "main", Event: "push", Status: "failure"},
|
||||||
},
|
},
|
||||||
args: []string{"ls", "--limit", "2", "repo/name"},
|
args: []string{"ls", "--limit", "2", "repo/name"},
|
||||||
expected: []woodpecker.Pipeline{
|
expected: []*woodpecker.Pipeline{
|
||||||
{ID: 1, Branch: "main", Event: "push", Status: "success"},
|
{ID: 1, Branch: "main", Event: "push", Status: "success"},
|
||||||
{ID: 2, Branch: "develop", Event: "pull_request", Status: "running"},
|
{ID: 2, Branch: "develop", Event: "pull_request", Status: "running"},
|
||||||
},
|
},
|
||||||
|
@ -106,14 +66,20 @@ func TestPipelineList(t *testing.T) {
|
||||||
for _, tt := range testtases {
|
for _, tt := range testtases {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
mockClient := mocks.NewClient(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)
|
mockClient.On("RepoLookup", mock.Anything).Return(&woodpecker.Repo{ID: tt.repoID}, nil)
|
||||||
|
|
||||||
app := &cli.App{Writer: io.Discard}
|
command := buildPipelineListCmd()
|
||||||
c := cli.NewContext(app, nil, nil)
|
command.Writer = io.Discard
|
||||||
|
command.Action = func(_ context.Context, c *cli.Command) error {
|
||||||
command := pipelineListCmd
|
|
||||||
command.Action = func(c *cli.Context) error {
|
|
||||||
pipelines, err := pipelineList(c, mockClient)
|
pipelines, err := pipelineList(c, mockClient)
|
||||||
if tt.wantErr != nil {
|
if tt.wantErr != nil {
|
||||||
assert.EqualError(t, err, tt.wantErr.Error())
|
assert.EqualError(t, err, tt.wantErr.Error())
|
||||||
|
@ -126,7 +92,7 @@ func TestPipelineList(t *testing.T) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = command.Run(c, tt.args...)
|
_ = command.Run(context.Background(), tt.args)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,14 +15,15 @@
|
||||||
package log
|
package log
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Command exports the log command set.
|
// Command exports the log command set.
|
||||||
var Command = &cli.Command{
|
var Command = &cli.Command{
|
||||||
Name: "log",
|
Name: "log",
|
||||||
Usage: "manage logs",
|
Usage: "manage logs",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
logPurgeCmd,
|
logPurgeCmd,
|
||||||
|
logShowCmd,
|
||||||
},
|
},
|
||||||
}
|
}
|
|
@ -15,55 +15,64 @@
|
||||||
package log
|
package log
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"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{
|
var logPurgeCmd = &cli.Command{
|
||||||
Name: "purge",
|
Name: "purge",
|
||||||
Usage: "purge a log",
|
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,
|
Action: logPurge,
|
||||||
}
|
}
|
||||||
|
|
||||||
func logPurge(c *cli.Context) (err error) {
|
func logPurge(ctx context.Context, c *cli.Command) (err error) {
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
repoIDOrFullName := c.Args().First()
|
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)
|
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
|
||||||
if err != nil {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
stepArg := c.Args().Get(2) //nolint:mnd
|
stepArg := c.Args().Get(2) //nolint:mnd
|
||||||
// TODO: Add lookup by name: stepID, err := internal.ParseStep(client, repoID, stepIDOrName)
|
|
||||||
var stepID int64
|
var stepID int64
|
||||||
if len(stepArg) != 0 {
|
if len(stepArg) != 0 {
|
||||||
stepID, err = strconv.ParseInt(stepArg, 10, 64)
|
stepID, err = internal.ParseStep(client, repoID, number, stepArg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if stepID > 0 {
|
if stepID > 0 {
|
||||||
|
fmt.Printf("Purging logs for pipeline %s#%d step %d\n", repoIDOrFullName, number, stepID)
|
||||||
err = client.StepLogsPurge(repoID, number, stepID)
|
err = client.StepLogsPurge(repoID, number, stepID)
|
||||||
} else {
|
} else {
|
||||||
|
fmt.Printf("Purging logs for pipeline %s#%d\n", repoIDOrFullName, number)
|
||||||
err = client.LogsPurge(repoID, number)
|
err = client.LogsPurge(repoID, number)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Purging logs for pipeline %s#%d\n", repoIDOrFullName, number)
|
|
||||||
return nil
|
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"
|
"os"
|
||||||
"text/template"
|
"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/v3/cli/output"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
"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.
|
// Command exports the pipeline command set.
|
||||||
var Command = &cli.Command{
|
var Command = &cli.Command{
|
||||||
Name: "pipeline",
|
Name: "pipeline",
|
||||||
Usage: "manage pipelines",
|
Usage: "manage pipelines",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
pipelineListCmd,
|
|
||||||
pipelineLastCmd,
|
|
||||||
pipelineLogsCmd,
|
|
||||||
pipelineInfoCmd,
|
|
||||||
pipelineStopCmd,
|
|
||||||
pipelineStartCmd,
|
|
||||||
pipelineApproveCmd,
|
pipelineApproveCmd,
|
||||||
pipelineDeclineCmd,
|
|
||||||
pipelineQueueCmd,
|
|
||||||
pipelineKillCmd,
|
|
||||||
pipelinePsCmd,
|
|
||||||
pipelineCreateCmd,
|
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"))
|
outFmt, outOpt := output.ParseOutputOptions(c.String("output"))
|
||||||
noHeader := c.Bool("output-no-headers")
|
noHeader := c.Bool("output-no-headers")
|
||||||
|
|
||||||
|
@ -70,7 +74,7 @@ func pipelineOutput(c *cli.Context, resources []woodpecker.Pipeline, fd ...io.Wr
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := tmpl.Execute(out, resources); err != nil {
|
if err := tmpl.Execute(out, pipelines); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case "table":
|
case "table":
|
||||||
|
@ -85,7 +89,7 @@ func pipelineOutput(c *cli.Context, resources []woodpecker.Pipeline, fd ...io.Wr
|
||||||
if !noHeader {
|
if !noHeader {
|
||||||
table.WriteHeader(cols)
|
table.WriteHeader(cols)
|
||||||
}
|
}
|
||||||
for _, resource := range resources {
|
for _, resource := range pipelines {
|
||||||
if err := table.Write(cols, resource); err != nil {
|
if err := table.Write(cols, resource); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,15 @@ package pipeline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"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/v3/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPipelineOutput(t *testing.T) {
|
func TestPipelineOutput(t *testing.T) {
|
||||||
|
@ -22,7 +23,7 @@ func TestPipelineOutput(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "table output with default columns",
|
name: "table output with default columns",
|
||||||
args: []string{},
|
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",
|
name: "table output with custom columns",
|
||||||
|
@ -32,7 +33,7 @@ func TestPipelineOutput(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "table output with no header",
|
name: "table output with no header",
|
||||||
args: []string{"output", "--output-no-headers"},
|
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",
|
name: "go-template output",
|
||||||
|
@ -46,41 +47,40 @@ func TestPipelineOutput(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pipelines := []woodpecker.Pipeline{
|
pipelines := []*woodpecker.Pipeline{
|
||||||
{
|
{
|
||||||
Number: 1,
|
Number: 1,
|
||||||
Status: "success",
|
Status: "success",
|
||||||
Event: "push",
|
Event: "push",
|
||||||
Branch: "main",
|
Branch: "main",
|
||||||
Message: "message",
|
Message: "message\nmultiline",
|
||||||
Author: "John Doe",
|
Author: "John Doe\n",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
app := &cli.App{Writer: io.Discard}
|
command := &cli.Command{
|
||||||
c := cli.NewContext(app, nil, nil)
|
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{}
|
if tt.wantErr {
|
||||||
command.Name = "output"
|
assert.Error(t, err)
|
||||||
command.Flags = common.OutputFlags("table")
|
return nil
|
||||||
command.Action = func(c *cli.Context) error {
|
}
|
||||||
var buf bytes.Buffer
|
|
||||||
err := pipelineOutput(c, pipelines, &buf)
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, tt.expected, buf.String())
|
||||||
|
|
||||||
if tt.wantErr {
|
|
||||||
assert.Error(t, err)
|
|
||||||
return nil
|
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
|
package pipeline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"text/template"
|
"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/v3/cli/common"
|
||||||
"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 pipelinePsCmd = &cli.Command{
|
var pipelinePsCmd = &cli.Command{
|
||||||
Name: "ps",
|
Name: "ps",
|
||||||
Usage: "show pipeline steps",
|
Usage: "show pipeline steps",
|
||||||
ArgsUsage: "<repo-id|repo-full-name> [pipeline]",
|
ArgsUsage: "<repo-id|repo-full-name> <pipeline>",
|
||||||
Action: pipelinePs,
|
Action: pipelinePs,
|
||||||
Flags: []cli.Flag{common.FormatFlag(tmplPipelinePs)},
|
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()
|
repoIDOrFullName := c.Args().First()
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
|
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("invalid repo '%s': %w", repoIDOrFullName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pipelineArg := c.Args().Get(1)
|
pipelineArg := c.Args().Get(1)
|
||||||
|
@ -49,7 +52,7 @@ func pipelinePs(c *cli.Context) error {
|
||||||
|
|
||||||
if pipelineArg == "last" || len(pipelineArg) == 0 {
|
if pipelineArg == "last" || len(pipelineArg) == 0 {
|
||||||
// Fetch the pipeline number from the last pipeline
|
// Fetch the pipeline number from the last pipeline
|
||||||
pipeline, err := client.PipelineLast(repoID, "")
|
pipeline, err := client.PipelineLast(repoID, woodpecker.PipelineLastOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -58,7 +61,7 @@ func pipelinePs(c *cli.Context) error {
|
||||||
} else {
|
} else {
|
||||||
number, err = strconv.ParseInt(pipelineArg, 10, 64)
|
number, err = strconv.ParseInt(pipelineArg, 10, 64)
|
||||||
if err != nil {
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, step := range pipeline.Workflows {
|
for _, workflow := range pipeline.Workflows {
|
||||||
for _, child := range step.Children {
|
for _, step := range workflow.Children {
|
||||||
if err := tmpl.Execute(os.Stdout, child); err != nil {
|
if err := tmpl.Execute(os.Stdout, map[string]any{"workflow": workflow, "step": step}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,8 +86,11 @@ func pipelinePs(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Template for pipeline ps information.
|
// template for pipeline ps information.
|
||||||
var tmplPipelinePs = "\x1b[33mStep #{{ .PID }} \x1b[0m" + `
|
var tmplPipelinePs = "\x1b[33m{{ .workflow.Name }} > {{ .step.Name }} (#{{ .step.PID }}):\x1b[0m" + `
|
||||||
Step: {{ .Name }}
|
Step: {{ .step.Name }}
|
||||||
State: {{ .State }}
|
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
|
package pipeline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"text/template"
|
"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/v3/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
var pipelineQueueCmd = &cli.Command{
|
var pipelineQueueCmd = &cli.Command{
|
||||||
|
@ -33,8 +34,8 @@ var pipelineQueueCmd = &cli.Command{
|
||||||
Flags: []cli.Flag{common.FormatFlag(tmplPipelineQueue)},
|
Flags: []cli.Flag{common.FormatFlag(tmplPipelineQueue)},
|
||||||
}
|
}
|
||||||
|
|
||||||
func pipelineQueue(c *cli.Context) error {
|
func pipelineQueue(ctx context.Context, c *cli.Command) error {
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,26 +15,27 @@
|
||||||
package pipeline
|
package pipeline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||||
)
|
)
|
||||||
|
|
||||||
var pipelineInfoCmd = &cli.Command{
|
var pipelineShowCmd = &cli.Command{
|
||||||
Name: "info",
|
Name: "show",
|
||||||
Usage: "show pipeline details",
|
Usage: "show pipeline information",
|
||||||
ArgsUsage: "<repo-id|repo-full-name> [pipeline]",
|
ArgsUsage: "<repo-id|repo-full-name> [pipeline]",
|
||||||
Action: pipelineInfo,
|
Action: pipelineShow,
|
||||||
Flags: common.OutputFlags("table"),
|
Flags: common.OutputFlags("table"),
|
||||||
}
|
}
|
||||||
|
|
||||||
func pipelineInfo(c *cli.Context) error {
|
func pipelineShow(ctx context.Context, c *cli.Command) error {
|
||||||
repoIDOrFullName := c.Args().First()
|
repoIDOrFullName := c.Args().First()
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -47,7 +48,7 @@ func pipelineInfo(c *cli.Context) error {
|
||||||
var number int64
|
var number int64
|
||||||
if pipelineArg == "last" || len(pipelineArg) == 0 {
|
if pipelineArg == "last" || len(pipelineArg) == 0 {
|
||||||
// Fetch the pipeline number from the last pipeline
|
// Fetch the pipeline number from the last pipeline
|
||||||
pipeline, err := client.PipelineLast(repoID, "")
|
pipeline, err := client.PipelineLast(repoID, woodpecker.PipelineLastOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -64,5 +65,5 @@ func pipelineInfo(c *cli.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return pipelineOutput(c, []woodpecker.Pipeline{*pipeline})
|
return pipelineOutput(c, []*woodpecker.Pipeline{pipeline})
|
||||||
}
|
}
|
|
@ -15,13 +15,15 @@
|
||||||
package pipeline
|
package pipeline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"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{
|
var pipelineStartCmd = &cli.Command{
|
||||||
|
@ -33,14 +35,14 @@ var pipelineStartCmd = &cli.Command{
|
||||||
&cli.StringSliceFlag{
|
&cli.StringSliceFlag{
|
||||||
Name: "param",
|
Name: "param",
|
||||||
Aliases: []string{"p"},
|
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()
|
repoIDOrFullName := c.Args().First()
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -53,7 +55,7 @@ func pipelineStart(c *cli.Context) (err error) {
|
||||||
var number int64
|
var number int64
|
||||||
if pipelineArg == "last" {
|
if pipelineArg == "last" {
|
||||||
// Fetch the pipeline number from the last pipeline
|
// Fetch the pipeline number from the last pipeline
|
||||||
pipeline, err := client.PipelineLast(repoID, "")
|
pipeline, err := client.PipelineLast(repoID, woodpecker.PipelineLastOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,13 @@
|
||||||
package pipeline
|
package pipeline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"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{
|
var pipelineStopCmd = &cli.Command{
|
||||||
|
@ -30,9 +31,9 @@ var pipelineStopCmd = &cli.Command{
|
||||||
Action: pipelineStop,
|
Action: pipelineStop,
|
||||||
}
|
}
|
||||||
|
|
||||||
func pipelineStop(c *cli.Context) (err error) {
|
func pipelineStop(ctx context.Context, c *cli.Command) (err error) {
|
||||||
repoIDOrFullName := c.Args().First()
|
repoIDOrFullName := c.Args().First()
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,18 +15,18 @@
|
||||||
package cron
|
package cron
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Command exports the cron command set.
|
// Command exports the cron command set.
|
||||||
var Command = &cli.Command{
|
var Command = &cli.Command{
|
||||||
Name: "cron",
|
Name: "cron",
|
||||||
Usage: "manage cron jobs",
|
Usage: "manage cron jobs",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
cronCreateCmd,
|
cronCreateCmd,
|
||||||
cronDeleteCmd,
|
cronDeleteCmd,
|
||||||
cronUpdateCmd,
|
|
||||||
cronInfoCmd,
|
|
||||||
cronListCmd,
|
cronListCmd,
|
||||||
|
cronShowCmd,
|
||||||
|
cronUpdateCmd,
|
||||||
},
|
},
|
||||||
}
|
}
|
|
@ -15,14 +15,15 @@
|
||||||
package cron
|
package cron
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"html/template"
|
"html/template"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/internal"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
|
||||||
)
|
)
|
||||||
|
|
||||||
var cronCreateCmd = &cli.Command{
|
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 (
|
var (
|
||||||
jobName = c.String("name")
|
cronName = c.String("name")
|
||||||
branch = c.String("branch")
|
branch = c.String("branch")
|
||||||
schedule = c.String("schedule")
|
schedule = c.String("schedule")
|
||||||
repoIDOrFullName = c.String("repository")
|
repoIDOrFullName = c.String("repository")
|
||||||
|
@ -62,7 +63,7 @@ func cronCreate(c *cli.Context) error {
|
||||||
repoIDOrFullName = c.Args().First()
|
repoIDOrFullName = c.Args().First()
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -73,7 +74,7 @@ func cronCreate(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
cron := &woodpecker.Cron{
|
cron := &woodpecker.Cron{
|
||||||
Name: jobName,
|
Name: cronName,
|
||||||
Branch: branch,
|
Branch: branch,
|
||||||
Schedule: schedule,
|
Schedule: schedule,
|
||||||
}
|
}
|
|
@ -15,13 +15,15 @@
|
||||||
package cron
|
package cron
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"html/template"
|
"html/template"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"go.woodpecker-ci.org/woodpecker/v3/cli/common"
|
||||||
"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 cronListCmd = &cli.Command{
|
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 (
|
var (
|
||||||
format = c.String("format") + "\n"
|
format = c.String("format") + "\n"
|
||||||
repoIDOrFullName = c.String("repository")
|
repoIDOrFullName = c.String("repository")
|
||||||
|
@ -43,7 +45,7 @@ func cronList(c *cli.Context) error {
|
||||||
if repoIDOrFullName == "" {
|
if repoIDOrFullName == "" {
|
||||||
repoIDOrFullName = c.Args().First()
|
repoIDOrFullName = c.Args().First()
|
||||||
}
|
}
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -51,7 +53,8 @@ func cronList(c *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
list, err := client.CronList(repoID)
|
opt := woodpecker.CronListOptions{}
|
||||||
|
list, err := client.CronList(repoID, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue