mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-02-01 12:12:22 +00:00
Merge remote-tracking branch 'upstream/main' into github-refresh
This commit is contained in:
commit
03a87a087e
619 changed files with 21084 additions and 12013 deletions
80
.cspell.json
80
.cspell.json
|
@ -6,27 +6,31 @@
|
||||||
"en_us",
|
"en_us",
|
||||||
// code
|
// code
|
||||||
"go",
|
"go",
|
||||||
"node",
|
"node"
|
||||||
// package names
|
|
||||||
"npm"
|
|
||||||
],
|
],
|
||||||
"words": [
|
"words": [
|
||||||
"abool",
|
"abool",
|
||||||
"anbraten",
|
"anbraten",
|
||||||
"antfu",
|
"antfu",
|
||||||
"apimachinery",
|
"apimachinery",
|
||||||
|
"Archlinux",
|
||||||
"autoincr",
|
"autoincr",
|
||||||
"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",
|
||||||
|
@ -38,6 +42,8 @@
|
||||||
"Debugf",
|
"Debugf",
|
||||||
"desaturate",
|
"desaturate",
|
||||||
"devx",
|
"devx",
|
||||||
|
"dind",
|
||||||
|
"Dockle",
|
||||||
"doublestar",
|
"doublestar",
|
||||||
"envsubst",
|
"envsubst",
|
||||||
"errgroup",
|
"errgroup",
|
||||||
|
@ -46,64 +52,89 @@
|
||||||
"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",
|
||||||
|
"opensource",
|
||||||
|
"Pacman",
|
||||||
|
"picus",
|
||||||
"Pinia",
|
"Pinia",
|
||||||
"pkce",
|
"pkce",
|
||||||
|
"pnpx",
|
||||||
|
"Polyform",
|
||||||
"posix",
|
"posix",
|
||||||
"ppid",
|
"ppid",
|
||||||
"Println",
|
"Println",
|
||||||
|
@ -123,19 +154,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 +181,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 +234,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",
|
||||||
|
"91-migrations.md",
|
||||||
|
// generated
|
||||||
|
"go.sum",
|
||||||
|
"flake.lock",
|
||||||
|
"pnpm-lock.yaml",
|
||||||
|
"**/node_modules/**/*",
|
||||||
|
"cmd/server/docs/docs.go",
|
||||||
// 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 +266,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"]
|
||||||
}
|
}
|
||||||
|
|
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.
|
||||||
|
|
||||||
|
-->
|
10
.github/renovate.json
vendored
10
.github/renovate.json
vendored
|
@ -1,6 +1,16 @@
|
||||||
{
|
{
|
||||||
"$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"],
|
||||||
|
"customManagers": [
|
||||||
|
{
|
||||||
|
"customType": "regex",
|
||||||
|
"fileMatch": ["shared/constant/constant.go"],
|
||||||
|
"matchStrings": [
|
||||||
|
"//\\s*renovate:\\s*datasource=(?<datasource>.*?) depName=(?<depName>.*?)( versioning=(?<versioning>.*?))?\\s+DefaultCloneImage = \"docker.io/woodpeckerci/plugin-git:(?<currentValue>.*)\""
|
||||||
|
],
|
||||||
|
"versioningTemplate": "{{#if versioning}}{{{versioning}}}{{else}}semver{{/if}}"
|
||||||
|
}
|
||||||
|
],
|
||||||
"packageRules": [
|
"packageRules": [
|
||||||
{
|
{
|
||||||
"matchCurrentVersion": "<1.0.0",
|
"matchCurrentVersion": "<1.0.0",
|
||||||
|
|
|
@ -184,3 +184,5 @@ issues:
|
||||||
|
|
||||||
run:
|
run:
|
||||||
timeout: 15m
|
timeout: 15m
|
||||||
|
build-tags:
|
||||||
|
- test
|
||||||
|
|
|
@ -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.12.0
|
rev: v2.13.0-beta
|
||||||
hooks:
|
hooks:
|
||||||
- id: hadolint
|
- id: hadolint
|
||||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||||
rev: v3.1.0
|
rev: v4.0.0-alpha.8
|
||||||
hooks:
|
hooks:
|
||||||
- id: prettier
|
- id: prettier
|
||||||
- repo: https://github.com/adrienverge/yamllint.git
|
- repo: https://github.com/adrienverge/yamllint.git
|
||||||
|
|
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
|
@ -8,11 +8,9 @@
|
||||||
},
|
},
|
||||||
"go.lintTool": "golangci-lint",
|
"go.lintTool": "golangci-lint",
|
||||||
"go.lintFlags": ["--fast"],
|
"go.lintFlags": ["--fast"],
|
||||||
|
"go.buildTags": "test",
|
||||||
"eslint.workingDirectories": ["./web"],
|
"eslint.workingDirectories": ["./web"],
|
||||||
"prettier.ignorePath": "./web/.prettierignore",
|
"prettier.ignorePath": "./web/.prettierignore",
|
||||||
// Enable the ESlint flat config support
|
|
||||||
// (remove this if your ESLint extension above v3.0.5)
|
|
||||||
"eslint.experimental.useFlatConfig": true,
|
|
||||||
// Auto fix
|
// Auto fix
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll.eslint": "explicit",
|
"source.fixAll.eslint": "explicit",
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
when:
|
when:
|
||||||
event: tag
|
- event: tag
|
||||||
|
- event: pull_request
|
||||||
|
branch: ${CI_REPO_DEFAULT_BRANCH}
|
||||||
|
path: Makefile
|
||||||
|
|
||||||
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:22-alpine'
|
||||||
- &xgo_image 'docker.io/techknowlogick/xgo:go-1.22.x'
|
- &xgo_image 'docker.io/techknowlogick/xgo:go-1.22.x'
|
||||||
|
|
||||||
# cspell:words bindata netgo TARGZ
|
# cspell:words bindata netgo
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
build-web:
|
build-web:
|
||||||
|
@ -35,7 +38,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 +53,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 +62,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:
|
||||||
|
@ -96,7 +103,10 @@ steps:
|
||||||
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:22-alpine'
|
||||||
- &xgo_image 'docker.io/techknowlogick/xgo:go-1.22.x'
|
- &xgo_image 'docker.io/techknowlogick/xgo:go-1.22.x'
|
||||||
- &buildx_plugin 'docker.io/woodpeckerci/plugin-docker-buildx:4.0.0'
|
- &buildx_plugin 'docker.io/woodpeckerci/plugin-docker-buildx:4.2.0'
|
||||||
- &platforms_release 'linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/386,linux/amd64,linux/ppc64le,linux/riscv64,linux/s390x,freebsd/arm64,freebsd/amd64,openbsd/arm64,openbsd/amd64'
|
- &platforms_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
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
steps:
|
steps:
|
||||||
release-helper:
|
release-helper:
|
||||||
image: woodpeckerci/plugin-ready-release-go:1.1.2
|
image: woodpeckerci/plugin-ready-release-go:1.2.0
|
||||||
pull: true
|
pull: true
|
||||||
settings:
|
settings:
|
||||||
release_branch: ${CI_REPO_DEFAULT_BRANCH}
|
release_branch: ${CI_REPO_DEFAULT_BRANCH}
|
||||||
|
|
|
@ -5,7 +5,7 @@ when:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: lint-editorconfig
|
- name: lint-editorconfig
|
||||||
image: docker.io/mstruebing/editorconfig-checker:v3.0.1
|
image: docker.io/mstruebing/editorconfig-checker:v3.0.3
|
||||||
depends_on: []
|
depends_on: []
|
||||||
when:
|
when:
|
||||||
- event: pull_request
|
- event: pull_request
|
||||||
|
@ -23,15 +23,15 @@ steps:
|
||||||
- tree --gitignore -I 012_columns_rename_procs_to_steps.go -I versioned_docs -I '*opensource.svg'| pnpx cspell lint --no-progress stdin
|
- 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:0.2.0
|
||||||
depends_on: []
|
depends_on: []
|
||||||
settings:
|
settings:
|
||||||
version: 3.2.5
|
version: 3.3.3
|
||||||
|
|
||||||
- name: links
|
- name: links
|
||||||
image: docker.io/lycheeverse/lychee:0.15.1
|
image: docker.io/lycheeverse/lychee:0.15.1
|
||||||
depends_on: []
|
depends_on: []
|
||||||
commands:
|
commands:
|
||||||
- lychee pipeline/frontend/yaml/linter/schema/schema.json
|
- lychee pipeline/frontend/yaml/linter/schema/schema.json
|
||||||
- lychee --exclude localhost docs/docs/
|
- lychee --user-agent "curl/8.4.0" --exclude localhost docs/docs/
|
||||||
- lychee --exclude localhost docs/src/pages/
|
- lychee --user-agent "curl/8.4.0" --exclude localhost docs/src/pages/
|
||||||
|
|
|
@ -40,6 +40,7 @@ steps:
|
||||||
- go run go.woodpecker-ci.org/woodpecker/v2/cmd/cli lint
|
- go run go.woodpecker-ci.org/woodpecker/v2/cmd/cli lint
|
||||||
environment:
|
environment:
|
||||||
WOODPECKER_DISABLE_UPDATE_CHECK: true
|
WOODPECKER_DISABLE_UPDATE_CHECK: true
|
||||||
|
WOODPECKER_PLUGINS_PRIVILEGED: 'docker.io/woodpeckerci/plugin-docker-buildx:4.2.0'
|
||||||
when:
|
when:
|
||||||
- event: pull_request
|
- event: pull_request
|
||||||
path:
|
path:
|
||||||
|
|
|
@ -58,6 +58,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:
|
||||||
|
|
128
CHANGELOG.md
128
CHANGELOG.md
|
@ -1,5 +1,133 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [2.7.1](https://github.com/woodpecker-ci/woodpecker/releases/tag/v2.7.1) - 2024-09-07
|
||||||
|
|
||||||
|
### ❤️ Thanks to all contributors! ❤️
|
||||||
|
|
||||||
|
@6543, @anbraten, @j04n-f, @qwerty287
|
||||||
|
|
||||||
|
### 🔒 Security
|
||||||
|
|
||||||
|
- Lint privileged plugin match and allow to be set empty [[#4084](https://github.com/woodpecker-ci/woodpecker/pull/4084)]
|
||||||
|
- Allow admins to specify privileged plugins by name **and tag** [[#4076](https://github.com/woodpecker-ci/woodpecker/pull/4076)]
|
||||||
|
- Warn if using secrets/env with plugin [[#4039](https://github.com/woodpecker-ci/woodpecker/pull/4039)]
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- Set refspec for gitlab MR [[#4021](https://github.com/woodpecker-ci/woodpecker/pull/4021)]
|
||||||
|
- Change Bitbucket PR hook to point the source branch, commit & ref [[#3965](https://github.com/woodpecker-ci/woodpecker/pull/3965)]
|
||||||
|
- Add updated, merged and declined events to bb webhook activation [[#3963](https://github.com/woodpecker-ci/woodpecker/pull/3963)]
|
||||||
|
- Fix login via navbar [[#3962](https://github.com/woodpecker-ci/woodpecker/pull/3962)]
|
||||||
|
- Fix panic if forge is unreachable [[#3944](https://github.com/woodpecker-ci/woodpecker/pull/3944)]
|
||||||
|
- Fix org settings page [[#4093](https://github.com/woodpecker-ci/woodpecker/pull/4093)]
|
||||||
|
|
||||||
|
### Misc
|
||||||
|
|
||||||
|
- Bump github.com/docker/docker from v24.0.9 to v24.0.9+30 [[#4077](https://github.com/woodpecker-ci/woodpecker/pull/4077)]
|
||||||
|
|
||||||
|
## [2.7.0](https://github.com/woodpecker-ci/woodpecker/releases/tag/v2.7.0) - 2024-07-18
|
||||||
|
|
||||||
|
### ❤️ Thanks to all contributors! ❤️
|
||||||
|
|
||||||
|
@6543, @anbraten, @dvjn, @hhamalai, @lafriks, @pat-s, @qwerty287, @smainz, @tongjicoder, @zc-devs
|
||||||
|
|
||||||
|
### 🔒 Security
|
||||||
|
|
||||||
|
- Add blocklist of environment variables who could alter execution of plugins [[#3934](https://github.com/woodpecker-ci/woodpecker/pull/3934)]
|
||||||
|
- Make sure plugins only mount the workspace base in a predefinde location [[#3933](https://github.com/woodpecker-ci/woodpecker/pull/3933)]
|
||||||
|
- Disallow to set arbitrary environments for plugins [[#3909](https://github.com/woodpecker-ci/woodpecker/pull/3909)]
|
||||||
|
- Use proper oauth state [[#3847](https://github.com/woodpecker-ci/woodpecker/pull/3847)]
|
||||||
|
- Enhance token checking [[#3842](https://github.com/woodpecker-ci/woodpecker/pull/3842)]
|
||||||
|
- Bump github.com/hashicorp/go-retryablehttp v0.7.5 -> v0.7.7 [[#3834](https://github.com/woodpecker-ci/woodpecker/pull/3834)]
|
||||||
|
|
||||||
|
### ✨ Features
|
||||||
|
|
||||||
|
- Gracefully shutdown server [[#3896](https://github.com/woodpecker-ci/woodpecker/pull/3896)]
|
||||||
|
- Gracefully shutdown agent [[#3895](https://github.com/woodpecker-ci/woodpecker/pull/3895)]
|
||||||
|
- Convert urls in logs to links [[#3904](https://github.com/woodpecker-ci/woodpecker/pull/3904)]
|
||||||
|
- Allow login using multiple forges [[#3822](https://github.com/woodpecker-ci/woodpecker/pull/3822)]
|
||||||
|
- Global and organization registries [[#1672](https://github.com/woodpecker-ci/woodpecker/pull/1672)]
|
||||||
|
- Cli get repo from git remote [[#3830](https://github.com/woodpecker-ci/woodpecker/pull/3830)]
|
||||||
|
- Add api for forges [[#3733](https://github.com/woodpecker-ci/woodpecker/pull/3733)]
|
||||||
|
|
||||||
|
### 📈 Enhancement
|
||||||
|
|
||||||
|
- Cli fix pipeline logs [[#3913](https://github.com/woodpecker-ci/woodpecker/pull/3913)]
|
||||||
|
- Migrate to github.com/urfave/cli/v3 [[#2951](https://github.com/woodpecker-ci/woodpecker/pull/2951)]
|
||||||
|
- Allow to change the working directory also for plugins and services [[#3914](https://github.com/woodpecker-ci/woodpecker/pull/3914)]
|
||||||
|
- Remove `unplugin-icons` [[#3809](https://github.com/woodpecker-ci/woodpecker/pull/3809)]
|
||||||
|
- Release windows binaries as zip file [[#3906](https://github.com/woodpecker-ci/woodpecker/pull/3906)]
|
||||||
|
- Convert to openapi 3.0 [[#3897](https://github.com/woodpecker-ci/woodpecker/pull/3897)]
|
||||||
|
- Add user registries UI [[#3888](https://github.com/woodpecker-ci/woodpecker/pull/3888)]
|
||||||
|
- Sort users by login [[#3891](https://github.com/woodpecker-ci/woodpecker/pull/3891)]
|
||||||
|
- Exclude dummy backend in production [[#3877](https://github.com/woodpecker-ci/woodpecker/pull/3877)]
|
||||||
|
- Fix deploy task env [[#3878](https://github.com/woodpecker-ci/woodpecker/pull/3878)]
|
||||||
|
- Get default branch and show message in pipeline list [[#3867](https://github.com/woodpecker-ci/woodpecker/pull/3867)]
|
||||||
|
- Add timestamp for last work done by agent [[#3844](https://github.com/woodpecker-ci/woodpecker/pull/3844)]
|
||||||
|
- Adjust logger types [[#3859](https://github.com/woodpecker-ci/woodpecker/pull/3859)]
|
||||||
|
- Cleanup state reporting [[#3850](https://github.com/woodpecker-ci/woodpecker/pull/3850)]
|
||||||
|
- Unify DB tables/columns [[#3806](https://github.com/woodpecker-ci/woodpecker/pull/3806)]
|
||||||
|
- Let webhook pass on pipeline parsing error [[#3829](https://github.com/woodpecker-ci/woodpecker/pull/3829)]
|
||||||
|
- Exclude mocks from release build [[#3831](https://github.com/woodpecker-ci/woodpecker/pull/3831)]
|
||||||
|
- K8s secrets reference from step [[#3655](https://github.com/woodpecker-ci/woodpecker/pull/3655)]
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- Handle empty repositories in gitea when listing PRs [[#3925](https://github.com/woodpecker-ci/woodpecker/pull/3925)]
|
||||||
|
- Update alpine package dep for docker images [[#3917](https://github.com/woodpecker-ci/woodpecker/pull/3917)]
|
||||||
|
- Don't report error if agent was terminated gracefully [[#3894](https://github.com/woodpecker-ci/woodpecker/pull/3894)]
|
||||||
|
- Let agents continuously report their health [[#3893](https://github.com/woodpecker-ci/woodpecker/pull/3893)]
|
||||||
|
- Ignore warnings for cli exec [[#3868](https://github.com/woodpecker-ci/woodpecker/pull/3868)]
|
||||||
|
- Correct favicon states [[#3832](https://github.com/woodpecker-ci/woodpecker/pull/3832)]
|
||||||
|
- Cleanup of the login flow and tests [[#3810](https://github.com/woodpecker-ci/woodpecker/pull/3810)]
|
||||||
|
- Fix newlines in logs [[#3808](https://github.com/woodpecker-ci/woodpecker/pull/3808)]
|
||||||
|
- Fix authentication error handling [[#3807](https://github.com/woodpecker-ci/woodpecker/pull/3807)]
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
- Streamline docs for new users [[#3803](https://github.com/woodpecker-ci/woodpecker/pull/3803)]
|
||||||
|
- Add mastodon verification [[#3843](https://github.com/woodpecker-ci/woodpecker/pull/3843)]
|
||||||
|
- chore(deps): update docs npm deps non-major [[#3837](https://github.com/woodpecker-ci/woodpecker/pull/3837)]
|
||||||
|
- fix(deps): update docs npm deps non-major [[#3824](https://github.com/woodpecker-ci/woodpecker/pull/3824)]
|
||||||
|
- Add openSUSE package [[#3800](https://github.com/woodpecker-ci/woodpecker/pull/3800)]
|
||||||
|
- chore(deps): update docs npm deps non-major [[#3798](https://github.com/woodpecker-ci/woodpecker/pull/3798)]
|
||||||
|
- Add "Docker Tags" Plugin [[#3796](https://github.com/woodpecker-ci/woodpecker/pull/3796)]
|
||||||
|
- chore(deps): update dependency marked to v13 [[#3792](https://github.com/woodpecker-ci/woodpecker/pull/3792)]
|
||||||
|
- chore: fix some comments [[#3788](https://github.com/woodpecker-ci/woodpecker/pull/3788)]
|
||||||
|
|
||||||
|
### Misc
|
||||||
|
|
||||||
|
- chore(deps): update web npm deps non-major [[#3930](https://github.com/woodpecker-ci/woodpecker/pull/3930)]
|
||||||
|
- chore(deps): update dependency vitest to v2 [[#3905](https://github.com/woodpecker-ci/woodpecker/pull/3905)]
|
||||||
|
- fix(deps): update module github.com/google/go-github/v62 to v63 [[#3910](https://github.com/woodpecker-ci/woodpecker/pull/3910)]
|
||||||
|
- chore(deps): update docker.io/woodpeckerci/plugin-docker-buildx docker tag to v4.1.0 [[#3908](https://github.com/woodpecker-ci/woodpecker/pull/3908)]
|
||||||
|
- Update plugin-git and add renovate trigger [[#3901](https://github.com/woodpecker-ci/woodpecker/pull/3901)]
|
||||||
|
- chore(deps): update docker.io/mstruebing/editorconfig-checker docker tag to v3.0.3 [[#3903](https://github.com/woodpecker-ci/woodpecker/pull/3903)]
|
||||||
|
- fix(deps): update golang-packages [[#3875](https://github.com/woodpecker-ci/woodpecker/pull/3875)]
|
||||||
|
- chore(deps): lock file maintenance [[#3876](https://github.com/woodpecker-ci/woodpecker/pull/3876)]
|
||||||
|
- [pre-commit.ci] pre-commit autoupdate [[#3862](https://github.com/woodpecker-ci/woodpecker/pull/3862)]
|
||||||
|
- Add dummy backend [[#3820](https://github.com/woodpecker-ci/woodpecker/pull/3820)]
|
||||||
|
- chore(deps): update dependency replace-in-file to v8 [[#3852](https://github.com/woodpecker-ci/woodpecker/pull/3852)]
|
||||||
|
- Update forgejo sdk [[#3840](https://github.com/woodpecker-ci/woodpecker/pull/3840)]
|
||||||
|
- chore(deps): lock file maintenance [[#3838](https://github.com/woodpecker-ci/woodpecker/pull/3838)]
|
||||||
|
- Allow to set dist dir using env var [[#3814](https://github.com/woodpecker-ci/woodpecker/pull/3814)]
|
||||||
|
- chore(deps): lock file maintenance [[#3805](https://github.com/woodpecker-ci/woodpecker/pull/3805)]
|
||||||
|
- chore(deps): update docker.io/lycheeverse/lychee docker tag to v0.15.1 [[#3797](https://github.com/woodpecker-ci/woodpecker/pull/3797)]
|
||||||
|
|
||||||
|
## [2.6.1](https://github.com/woodpecker-ci/woodpecker/releases/tag/v2.6.1) - 2024-07-19
|
||||||
|
|
||||||
|
### 🔒 Security
|
||||||
|
|
||||||
|
- Add blocklist of environment variables who could alter execution of plugins [[#3934](https://github.com/woodpecker-ci/woodpecker/pull/3934)]
|
||||||
|
- Make sure plugins only mount the workspace base in a predefinde location [[#3933](https://github.com/woodpecker-ci/woodpecker/pull/3933)]
|
||||||
|
- Disalow to set arbitrary environments for plugins [[#3909](https://github.com/woodpecker-ci/woodpecker/pull/3909)]
|
||||||
|
- Bump trivy plugin version and remove unused variable [[#3833](https://github.com/woodpecker-ci/woodpecker/pull/3833)]
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- Let webhook pass on pipeline parsion error [[#3829](https://github.com/woodpecker-ci/woodpecker/pull/3829)]
|
||||||
|
- Fix newlines in logs [[#3808](https://github.com/woodpecker-ci/woodpecker/pull/3808)]
|
||||||
|
|
||||||
## [2.6.0](https://github.com/woodpecker-ci/woodpecker/releases/tag/v2.6.0) - 2024-06-13
|
## [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! ❤️
|
||||||
|
|
134
Makefile
134
Makefile
|
@ -8,6 +8,8 @@ ifeq ($(TARGETOS),windows)
|
||||||
BIN_SUFFIX := .exe
|
BIN_SUFFIX := .exe
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
DIST_DIR ?= dist
|
||||||
|
|
||||||
VERSION ?= next
|
VERSION ?= next
|
||||||
VERSION_NUMBER ?= 0.0.0
|
VERSION_NUMBER ?= 0.0.0
|
||||||
CI_COMMIT_SHA ?= $(shell git rev-parse HEAD)
|
CI_COMMIT_SHA ?= $(shell git rev-parse HEAD)
|
||||||
|
@ -27,6 +29,7 @@ else
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
TAGS ?=
|
||||||
LDFLAGS := -X go.woodpecker-ci.org/woodpecker/v2/version.Version=${VERSION}
|
LDFLAGS := -X go.woodpecker-ci.org/woodpecker/v2/version.Version=${VERSION}
|
||||||
STATIC_BUILD ?= true
|
STATIC_BUILD ?= true
|
||||||
ifeq ($(STATIC_BUILD),true)
|
ifeq ($(STATIC_BUILD),true)
|
||||||
|
@ -103,7 +106,7 @@ clean: ## Clean build artifacts
|
||||||
|
|
||||||
.PHONY: clean-all
|
.PHONY: clean-all
|
||||||
clean-all: clean ## Clean all artifacts
|
clean-all: clean ## Clean all artifacts
|
||||||
rm -rf dist web/dist docs/build docs/node_modules web/node_modules
|
rm -rf ${DIST_DIR} web/dist docs/build docs/node_modules web/node_modules
|
||||||
# delete generated
|
# delete generated
|
||||||
rm -rf docs/docs/40-cli.md docs/swagger.json
|
rm -rf docs/docs/40-cli.md docs/swagger.json
|
||||||
|
|
||||||
|
@ -160,20 +163,20 @@ lint-ui: ui-dependencies ## Lint UI code
|
||||||
(cd web/; pnpm lint --quiet)
|
(cd web/; pnpm lint --quiet)
|
||||||
|
|
||||||
test-agent: ## Test agent code
|
test-agent: ## Test agent code
|
||||||
go test -race -cover -coverprofile agent-coverage.out -timeout 30s go.woodpecker-ci.org/woodpecker/v2/cmd/agent go.woodpecker-ci.org/woodpecker/v2/agent/...
|
go test -race -cover -coverprofile agent-coverage.out -timeout 60s -tags 'test $(TAGS)' go.woodpecker-ci.org/woodpecker/v2/cmd/agent go.woodpecker-ci.org/woodpecker/v2/agent/...
|
||||||
|
|
||||||
test-server: ## Test server code
|
test-server: ## Test server code
|
||||||
go test -race -cover -coverprofile server-coverage.out -timeout 30s go.woodpecker-ci.org/woodpecker/v2/cmd/server $(shell go list go.woodpecker-ci.org/woodpecker/v2/server/... | grep -v '/store')
|
go test -race -cover -coverprofile server-coverage.out -timeout 60s -tags 'test $(TAGS)' go.woodpecker-ci.org/woodpecker/v2/cmd/server $(shell go list go.woodpecker-ci.org/woodpecker/v2/server/... | grep -v '/store')
|
||||||
|
|
||||||
test-cli: ## Test cli code
|
test-cli: ## Test cli code
|
||||||
go test -race -cover -coverprofile cli-coverage.out -timeout 30s go.woodpecker-ci.org/woodpecker/v2/cmd/cli go.woodpecker-ci.org/woodpecker/v2/cli/...
|
go test -race -cover -coverprofile cli-coverage.out -timeout 60s -tags 'test $(TAGS)' go.woodpecker-ci.org/woodpecker/v2/cmd/cli go.woodpecker-ci.org/woodpecker/v2/cli/...
|
||||||
|
|
||||||
test-server-datastore: ## Test server datastore
|
test-server-datastore: ## Test server datastore
|
||||||
go test -timeout 120s -run TestMigrate go.woodpecker-ci.org/woodpecker/v2/server/store/...
|
go test -timeout 300s -tags 'test $(TAGS)' -run TestMigrate go.woodpecker-ci.org/woodpecker/v2/server/store/...
|
||||||
go test -race -timeout 30s -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/v2/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 180s go.woodpecker-ci.org/woodpecker/v2/server/store/...
|
go test -race -cover -coverprofile datastore-coverage.out -timeout 300s -tags 'test $(TAGS)' go.woodpecker-ci.org/woodpecker/v2/server/store/...
|
||||||
|
|
||||||
test-ui: ui-dependencies ## Test UI code
|
test-ui: ui-dependencies ## Test UI code
|
||||||
(cd web/; pnpm run lint)
|
(cd web/; pnpm run lint)
|
||||||
|
@ -182,7 +185,7 @@ test-ui: ui-dependencies ## Test UI code
|
||||||
(cd web/; pnpm run test)
|
(cd web/; pnpm run test)
|
||||||
|
|
||||||
test-lib: ## Test lib code
|
test-lib: ## Test lib code
|
||||||
go test -race -cover -coverprofile coverage.out -timeout 30s $(shell go list ./... | grep -v '/cmd\|/agent\|/cli\|/server')
|
go test -race -cover -coverprofile coverage.out -timeout 60s -tags 'test $(TAGS)' $(shell go list ./... | grep -v '/cmd\|/agent\|/cli\|/server')
|
||||||
|
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
test: test-agent test-server test-server-datastore test-cli test-lib ## Run all tests
|
test: test-agent test-server test-server-datastore test-cli test-lib ## Run all tests
|
||||||
|
@ -193,16 +196,16 @@ build-ui: ## Build UI
|
||||||
(cd web/; pnpm install --frozen-lockfile; pnpm build)
|
(cd web/; pnpm install --frozen-lockfile; pnpm build)
|
||||||
|
|
||||||
build-server: build-ui generate-swagger ## Build server
|
build-server: build-ui generate-swagger ## Build server
|
||||||
CGO_ENABLED=${CGO_ENABLED} GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -ldflags '${LDFLAGS}' -o dist/woodpecker-server${BIN_SUFFIX} go.woodpecker-ci.org/woodpecker/v2/cmd/server
|
CGO_ENABLED=${CGO_ENABLED} GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -tags '$(TAGS)' -ldflags '${LDFLAGS}' -o ${DIST_DIR}/woodpecker-server${BIN_SUFFIX} go.woodpecker-ci.org/woodpecker/v2/cmd/server
|
||||||
|
|
||||||
build-agent: ## Build agent
|
build-agent: ## Build agent
|
||||||
CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -ldflags '${LDFLAGS}' -o dist/woodpecker-agent${BIN_SUFFIX} go.woodpecker-ci.org/woodpecker/v2/cmd/agent
|
CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -tags '$(TAGS)' -ldflags '${LDFLAGS}' -o ${DIST_DIR}/woodpecker-agent${BIN_SUFFIX} go.woodpecker-ci.org/woodpecker/v2/cmd/agent
|
||||||
|
|
||||||
build-cli: ## Build cli
|
build-cli: ## Build cli
|
||||||
CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -ldflags '${LDFLAGS}' -o dist/woodpecker-cli${BIN_SUFFIX} go.woodpecker-ci.org/woodpecker/v2/cmd/cli
|
CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -tags '$(TAGS)' -ldflags '${LDFLAGS}' -o ${DIST_DIR}/woodpecker-cli${BIN_SUFFIX} go.woodpecker-ci.org/woodpecker/v2/cmd/cli
|
||||||
|
|
||||||
build-tarball: ## Build tar archive
|
build-tarball: ## Build tar archive
|
||||||
mkdir -p dist && tar chzvf dist/woodpecker-src.tar.gz \
|
mkdir -p ${DIST_DIR} && tar chzvf ${DIST_DIR}/woodpecker-src.tar.gz \
|
||||||
--exclude="*.exe" \
|
--exclude="*.exe" \
|
||||||
--exclude="./.pnpm-store" \
|
--exclude="./.pnpm-store" \
|
||||||
--exclude="node_modules" \
|
--exclude="node_modules" \
|
||||||
|
@ -224,7 +227,7 @@ cross-compile-server: ## Cross compile the server
|
||||||
TARGETARCH_BUILDX=$(subst arm64/v8,arm64,$(subst arm/v7,arm,$(word 2,$(subst |, ,$(platform))))) \
|
TARGETARCH_BUILDX=$(subst arm64/v8,arm64,$(subst arm/v7,arm,$(word 2,$(subst |, ,$(platform))))) \
|
||||||
make release-server-xgo || exit 1; \
|
make release-server-xgo || exit 1; \
|
||||||
)
|
)
|
||||||
tree dist
|
tree ${DIST_DIR}
|
||||||
|
|
||||||
release-server-xgo: check-xgo ## Create server binaries for release using xgo
|
release-server-xgo: check-xgo ## Create server binaries for release using xgo
|
||||||
@echo "Building for:"
|
@echo "Building for:"
|
||||||
|
@ -232,58 +235,79 @@ release-server-xgo: check-xgo ## Create server binaries for release using xgo
|
||||||
@echo "arch orgi:$(TARGETARCH)"
|
@echo "arch 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/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
|
||||||
mkdir -p ./dist/server/$(TARGETOS)_$(TARGETARCH_BUILDX); \
|
@if [ "$${XGO_IN_XGO:-0}" -eq "1" ]; then \
|
||||||
mv -vf /build/woodpecker-server* ./dist/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX); \
|
echo "inside xgo image"; \
|
||||||
else echo "outside xgo image"; \
|
mkdir -p ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX); \
|
||||||
[ -f "./dist/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX)" ] && rm -v ./dist/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX); \
|
mv -vf /build/woodpecker-server* ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX); \
|
||||||
mv -v ./dist/server/$(TARGETOS)_$(TARGETARCH_XGO)/woodpecker-server* ./dist/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX); \
|
else \
|
||||||
|
echo "outside xgo image"; \
|
||||||
|
[ -f "${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX)" ] && rm -v ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX); \
|
||||||
|
mv -v ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_XGO)/woodpecker-server* ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX); \
|
||||||
|
fi
|
||||||
|
# if enabled package it in an archive
|
||||||
|
@if [ "$${ARCHIVE_IT:-0}" -eq "1" ]; then \
|
||||||
|
if [ "$(BIN_SUFFIX)" = ".exe" ]; then \
|
||||||
|
rm -f ${DIST_DIR}/woodpecker-server_$(TARGETOS)_$(TARGETARCH_BUILDX).zip; \
|
||||||
|
zip -j ${DIST_DIR}/woodpecker-server_$(TARGETOS)_$(TARGETARCH_BUILDX).zip ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server.exe; \
|
||||||
|
else \
|
||||||
|
tar -cvzf ${DIST_DIR}/woodpecker-server_$(TARGETOS)_$(TARGETARCH_BUILDX).tar.gz -C ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX) woodpecker-server$(BIN_SUFFIX); \
|
||||||
|
fi; \
|
||||||
|
else \
|
||||||
|
echo "skip creating '${DIST_DIR}/woodpecker-server_$(TARGETOS)_$(TARGETARCH_BUILDX).tar.gz'"; \
|
||||||
fi
|
fi
|
||||||
@[ "$${TARGZ:-0}" -eq "1" ] && tar -cvzf dist/woodpecker-server_$(TARGETOS)_$(TARGETARCH_BUILDX).tar.gz -C dist/server/$(TARGETOS)_$(TARGETARCH_BUILDX) woodpecker-server$(BIN_SUFFIX) || echo "skip creating 'dist/woodpecker-server_$(TARGETOS)_$(TARGETARCH_BUILDX).tar.gz'"
|
|
||||||
|
|
||||||
release-server: ## Create server binaries for release
|
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/server/$(TARGETOS)_$(TARGETARCH)/woodpecker-server$(BIN_SUFFIX) go.woodpecker-ci.org/woodpecker/v2/cmd/server
|
GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) CGO_ENABLED=${CGO_ENABLED} go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH)/woodpecker-server$(BIN_SUFFIX) go.woodpecker-ci.org/woodpecker/v2/cmd/server
|
||||||
# tar binary files
|
# tar binary files
|
||||||
tar -cvzf dist/woodpecker-server_$(TARGETOS)_$(TARGETARCH).tar.gz -C dist/server/$(TARGETOS)_$(TARGETARCH) woodpecker-server$(BIN_SUFFIX)
|
if [ "$(BIN_SUFFIX)" == ".exe" ]; then \
|
||||||
|
zip -j ${DIST_DIR}/woodpecker-server_$(TARGETOS)_$(TARGETARCH).zip ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH)/woodpecker-server.exe; \
|
||||||
|
else \
|
||||||
|
tar -cvzf ${DIST_DIR}/woodpecker-server_$(TARGETOS)_$(TARGETARCH).tar.gz -C ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH) woodpecker-server$(BIN_SUFFIX); \
|
||||||
|
fi
|
||||||
|
|
||||||
release-agent: ## Create agent binaries for release
|
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/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/v2/cmd/agent
|
||||||
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o dist/agent/linux_arm64/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
|
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o ${DIST_DIR}/agent/linux_arm64/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
|
||||||
GOOS=linux GOARCH=arm CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o dist/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/v2/cmd/agent
|
||||||
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o dist/agent/windows_amd64/woodpecker-agent.exe go.woodpecker-ci.org/woodpecker/v2/cmd/agent
|
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o ${DIST_DIR}/agent/windows_amd64/woodpecker-agent.exe go.woodpecker-ci.org/woodpecker/v2/cmd/agent
|
||||||
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o dist/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/v2/cmd/agent
|
||||||
GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o dist/agent/darwin_arm64/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
|
GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o ${DIST_DIR}/agent/darwin_arm64/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
|
||||||
# tar binary files
|
# tar binary files
|
||||||
tar -cvzf dist/woodpecker-agent_linux_amd64.tar.gz -C dist/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/woodpecker-agent_linux_arm64.tar.gz -C dist/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/woodpecker-agent_linux_arm.tar.gz -C dist/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/woodpecker-agent_windows_amd64.tar.gz -C dist/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/woodpecker-agent_darwin_amd64.tar.gz -C dist/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/woodpecker-agent_darwin_arm64.tar.gz -C dist/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/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/v2/cmd/cli
|
||||||
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o dist/cli/linux_arm64/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
|
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o ${DIST_DIR}/cli/linux_arm64/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
|
||||||
GOOS=linux GOARCH=arm CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o dist/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/v2/cmd/cli
|
||||||
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o dist/cli/windows_amd64/woodpecker-cli.exe go.woodpecker-ci.org/woodpecker/v2/cmd/cli
|
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o ${DIST_DIR}/cli/windows_amd64/woodpecker-cli.exe go.woodpecker-ci.org/woodpecker/v2/cmd/cli
|
||||||
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o dist/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/v2/cmd/cli
|
||||||
GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o dist/cli/darwin_arm64/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
|
GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o ${DIST_DIR}/cli/darwin_arm64/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
|
||||||
# tar binary files
|
# tar binary files
|
||||||
tar -cvzf dist/woodpecker-cli_linux_amd64.tar.gz -C dist/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/woodpecker-cli_linux_arm64.tar.gz -C dist/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/woodpecker-cli_linux_arm.tar.gz -C dist/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/woodpecker-cli_windows_amd64.tar.gz -C dist/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/woodpecker-cli_darwin_amd64.tar.gz -C dist/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/woodpecker-cli_darwin_arm64.tar.gz -C dist/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
|
||||||
(cd dist/; sha256sum *.* > checksums.txt)
|
(cd ${DIST_DIR}/; sha256sum *.* > checksums.txt)
|
||||||
|
|
||||||
.PHONY: release
|
.PHONY: release
|
||||||
release: release-frontend release-server release-agent release-cli ## Release all binaries
|
release: release-frontend release-server release-agent release-cli ## Release all binaries
|
||||||
|
@ -292,16 +316,16 @@ bundle-prepare: ## Prepare the bundles
|
||||||
go install github.com/goreleaser/nfpm/v2/cmd/nfpm@v2.6.0
|
go install github.com/goreleaser/nfpm/v2/cmd/nfpm@v2.6.0
|
||||||
|
|
||||||
bundle-agent: bundle-prepare ## Create bundles for agent
|
bundle-agent: bundle-prepare ## Create bundles for agent
|
||||||
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/agent.yaml --target ./dist --packager deb
|
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/agent.yaml --target ${DIST_DIR} --packager deb
|
||||||
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/agent.yaml --target ./dist --packager rpm
|
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/agent.yaml --target ${DIST_DIR} --packager rpm
|
||||||
|
|
||||||
bundle-server: bundle-prepare ## Create bundles for server
|
bundle-server: bundle-prepare ## Create bundles for server
|
||||||
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/server.yaml --target ./dist --packager deb
|
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/server.yaml --target ${DIST_DIR} --packager deb
|
||||||
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/server.yaml --target ./dist --packager rpm
|
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/server.yaml --target ${DIST_DIR} --packager rpm
|
||||||
|
|
||||||
bundle-cli: bundle-prepare ## Create bundles for cli
|
bundle-cli: bundle-prepare ## Create bundles for cli
|
||||||
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/cli.yaml --target ./dist --packager deb
|
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/cli.yaml --target ${DIST_DIR} --packager deb
|
||||||
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/cli.yaml --target ./dist --packager rpm
|
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/cli.yaml --target ${DIST_DIR} --packager rpm
|
||||||
|
|
||||||
.PHONY: bundle
|
.PHONY: bundle
|
||||||
bundle: bundle-agent bundle-server bundle-cli ## Create all bundles
|
bundle: bundle-agent bundle-server bundle-cli ## Create all bundles
|
||||||
|
|
57
README.md
57
README.md
|
@ -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.
|
||||||
|
|
|
@ -26,17 +26,12 @@ import (
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
|
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// Store not more than 1mb in a log-line as 4mb is the limit of a grpc message
|
|
||||||
// and log-lines needs to be parsed by the browsers later on.
|
|
||||||
maxLogLineLength = 1024 * 1024 // 1mb
|
|
||||||
)
|
|
||||||
|
|
||||||
func (r *Runner) createLogger(_logger zerolog.Logger, uploads *sync.WaitGroup, workflow *rpc.Workflow) pipeline.Logger {
|
func (r *Runner) createLogger(_logger zerolog.Logger, uploads *sync.WaitGroup, workflow *rpc.Workflow) pipeline.Logger {
|
||||||
return func(step *backend.Step, rc io.Reader) error {
|
return func(step *backend.Step, rc io.ReadCloser) error {
|
||||||
|
defer rc.Close()
|
||||||
|
|
||||||
logger := _logger.With().
|
logger := _logger.With().
|
||||||
Str("image", step.Image).
|
Str("image", step.Image).
|
||||||
Str("workflowID", workflow.ID).
|
|
||||||
Logger()
|
Logger()
|
||||||
|
|
||||||
uploads.Add(1)
|
uploads.Add(1)
|
||||||
|
@ -49,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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,8 @@ import (
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc/proto"
|
"go.woodpecker-ci.org/woodpecker/v2/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():
|
||||||
|
return
|
||||||
|
case <-time.After(wait):
|
||||||
|
err := interceptor.refreshToken(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
wait = time.Second
|
wait = time.Second
|
||||||
} else {
|
} else {
|
||||||
wait = refreshDuration
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,29 +25,44 @@ import (
|
||||||
"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/v2/pipeline/backend/types"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
|
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc/proto"
|
"go.woodpecker-ci.org/woodpecker/v2/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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,28 +87,28 @@ 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 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove after adding continuous data exchange by something like #536
|
|
||||||
if strings.Contains(err.Error(), "\"too_many_pings\"") {
|
|
||||||
// https://github.com/woodpecker-ci/woodpecker/issues/717#issuecomment-1049365104
|
|
||||||
log.Trace().Err(err).Msg("grpc: to many keepalive pings without sending data")
|
|
||||||
} else {
|
|
||||||
log.Error().Err(err).Msgf("grpc error: done(): code: %v", status.Code(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
switch status.Code(err) {
|
switch status.Code(err) {
|
||||||
|
case codes.Canceled:
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
// expected as context was canceled
|
||||||
|
log.Debug().Err(err).Msgf("grpc error: next(): context canceled")
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
log.Error().Err(err).Msgf("grpc error: next(): code: %v", status.Code(err))
|
||||||
|
return nil, err
|
||||||
case
|
case
|
||||||
codes.Aborted,
|
codes.Aborted,
|
||||||
codes.DataLoss,
|
codes.DataLoss,
|
||||||
|
@ -101,14 +116,22 @@ func (c *client) Next(ctx context.Context, f rpc.Filter) (*rpc.Workflow, error)
|
||||||
codes.Internal,
|
codes.Internal,
|
||||||
codes.Unavailable:
|
codes.Unavailable:
|
||||||
// non-fatal errors
|
// non-fatal errors
|
||||||
|
// TODO: remove after adding continuous data exchange by something like #536
|
||||||
|
if strings.Contains(err.Error(), "\"too_many_pings\"") {
|
||||||
|
// https://github.com/woodpecker-ci/woodpecker/issues/717#issuecomment-1049365104
|
||||||
|
log.Trace().Err(err).Msg("grpc: to many keepalive pings without sending data")
|
||||||
|
} else {
|
||||||
|
log.Warn().Err(err).Msgf("grpc error: next(): code: %v", status.Code(err))
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
|
log.Error().Err(err).Msgf("grpc error: next(): code: %v", status.Code(err))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-time.After(retry.NextBackOff()):
|
case <-time.After(retry.NextBackOff()):
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return nil, ctx.Err()
|
return nil, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,19 +150,25 @@ func (c *client) Next(ctx context.Context, f rpc.Filter) (*rpc.Workflow, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait blocks until the workflow is complete.
|
// Wait blocks until the workflow is complete.
|
||||||
func (c *client) Wait(ctx context.Context, id string) (err error) {
|
func (c *client) Wait(ctx context.Context, workflowID string) (err error) {
|
||||||
retry := c.newBackOff()
|
retry := c.newBackOff()
|
||||||
req := new(proto.WaitRequest)
|
req := new(proto.WaitRequest)
|
||||||
req.Id = id
|
req.Id = workflowID
|
||||||
for {
|
for {
|
||||||
_, err = c.client.Wait(ctx, req)
|
_, err = c.client.Wait(ctx, req)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
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,
|
||||||
|
@ -147,7 +176,9 @@ func (c *client) Wait(ctx context.Context, id 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,17 +192,14 @@ func (c *client) Wait(ctx context.Context, id string) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init signals the workflow is initialized.
|
// Init signals the workflow is initialized.
|
||||||
func (c *client) Init(ctx context.Context, id string, state rpc.State) (err error) {
|
func (c *client) Init(ctx context.Context, workflowID string, state rpc.WorkflowState) (err error) {
|
||||||
retry := c.newBackOff()
|
retry := c.newBackOff()
|
||||||
req := new(proto.InitRequest)
|
req := new(proto.InitRequest)
|
||||||
req.Id = id
|
req.Id = workflowID
|
||||||
req.State = new(proto.State)
|
req.State = new(proto.WorkflowState)
|
||||||
req.State.Error = state.Error
|
|
||||||
req.State.ExitCode = int32(state.ExitCode)
|
|
||||||
req.State.Exited = state.Exited
|
|
||||||
req.State.Finished = state.Finished
|
|
||||||
req.State.Started = state.Started
|
req.State.Started = state.Started
|
||||||
req.State.StepUuid = state.StepUUID
|
req.State.Finished = state.Finished
|
||||||
|
req.State.Error = state.Error
|
||||||
for {
|
for {
|
||||||
_, err = c.client.Init(ctx, req)
|
_, err = c.client.Init(ctx, req)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -181,6 +209,14 @@ func (c *client) Init(ctx context.Context, id string, state rpc.State) (err erro
|
||||||
log.Error().Err(err).Msgf("grpc error: init(): code: %v", status.Code(err))
|
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,
|
||||||
|
@ -188,7 +224,9 @@ func (c *client) Init(ctx context.Context, id string, state rpc.State) (err erro
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,18 +239,15 @@ func (c *client) Init(ctx context.Context, id string, state rpc.State) (err erro
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Done signals the work is complete.
|
// Done signals the workflow is complete.
|
||||||
func (c *client) Done(ctx context.Context, id string, state rpc.State) (err error) {
|
func (c *client) Done(ctx context.Context, workflowID string, state rpc.WorkflowState) (err error) {
|
||||||
retry := c.newBackOff()
|
retry := c.newBackOff()
|
||||||
req := new(proto.DoneRequest)
|
req := new(proto.DoneRequest)
|
||||||
req.Id = id
|
req.Id = workflowID
|
||||||
req.State = new(proto.State)
|
req.State = new(proto.WorkflowState)
|
||||||
req.State.Error = state.Error
|
|
||||||
req.State.ExitCode = int32(state.ExitCode)
|
|
||||||
req.State.Exited = state.Exited
|
|
||||||
req.State.Finished = state.Finished
|
|
||||||
req.State.Started = state.Started
|
req.State.Started = state.Started
|
||||||
req.State.StepUuid = state.StepUUID
|
req.State.Finished = state.Finished
|
||||||
|
req.State.Error = state.Error
|
||||||
for {
|
for {
|
||||||
_, err = c.client.Done(ctx, req)
|
_, err = c.client.Done(ctx, req)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -222,6 +257,14 @@ func (c *client) Done(ctx context.Context, id string, state rpc.State) (err erro
|
||||||
log.Error().Err(err).Msgf("grpc error: done(): code: %v", status.Code(err))
|
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 +272,9 @@ func (c *client) Done(ctx context.Context, id string, state rpc.State) (err erro
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,10 +288,10 @@ func (c *client) Done(ctx context.Context, id string, state rpc.State) (err erro
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extend extends the workflow deadline.
|
// Extend extends the workflow deadline.
|
||||||
func (c *client) Extend(ctx context.Context, id string) (err error) {
|
func (c *client) Extend(ctx context.Context, workflowID string) (err error) {
|
||||||
retry := c.newBackOff()
|
retry := c.newBackOff()
|
||||||
req := new(proto.ExtendRequest)
|
req := new(proto.ExtendRequest)
|
||||||
req.Id = id
|
req.Id = workflowID
|
||||||
for {
|
for {
|
||||||
_, err = c.client.Extend(ctx, req)
|
_, err = c.client.Extend(ctx, req)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -256,6 +301,14 @@ func (c *client) Extend(ctx context.Context, id string) (err error) {
|
||||||
log.Error().Err(err).Msgf("grpc error: extend(): code: %v", status.Code(err))
|
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 +316,9 @@ func (c *client) Extend(ctx context.Context, id 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,17 +332,17 @@ func (c *client) Extend(ctx context.Context, id string) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update updates the workflow state.
|
// Update updates the workflow state.
|
||||||
func (c *client) Update(ctx context.Context, id string, state rpc.State) (err error) {
|
func (c *client) Update(ctx context.Context, workflowID string, state rpc.StepState) (err error) {
|
||||||
retry := c.newBackOff()
|
retry := c.newBackOff()
|
||||||
req := new(proto.UpdateRequest)
|
req := new(proto.UpdateRequest)
|
||||||
req.Id = id
|
req.Id = workflowID
|
||||||
req.State = new(proto.State)
|
req.State = new(proto.StepState)
|
||||||
req.State.Error = state.Error
|
|
||||||
req.State.ExitCode = int32(state.ExitCode)
|
|
||||||
req.State.Exited = state.Exited
|
|
||||||
req.State.Finished = state.Finished
|
|
||||||
req.State.Started = state.Started
|
|
||||||
req.State.StepUuid = state.StepUUID
|
req.State.StepUuid = state.StepUUID
|
||||||
|
req.State.Started = state.Started
|
||||||
|
req.State.Finished = state.Finished
|
||||||
|
req.State.Exited = state.Exited
|
||||||
|
req.State.ExitCode = int32(state.ExitCode)
|
||||||
|
req.State.Error = state.Error
|
||||||
for {
|
for {
|
||||||
_, err = c.client.Update(ctx, req)
|
_, err = c.client.Update(ctx, req)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -297,6 +352,14 @@ func (c *client) Update(ctx context.Context, id string, state rpc.State) (err er
|
||||||
log.Error().Err(err).Msgf("grpc error: update(): code: %v", status.Code(err))
|
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 +367,9 @@ func (c *client) Update(ctx context.Context, id string, state rpc.State) (err er
|
||||||
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 +382,82 @@ func (c *client) Update(ctx context.Context, id string, state rpc.State) (err er
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log writes the workflow 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 +465,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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,6 +507,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 +522,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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
102
agent/runner.go
102
agent/runner.go
|
@ -23,12 +23,12 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/tevino/abool/v2"
|
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline"
|
"go.woodpecker-ci.org/woodpecker/v2/pipeline"
|
||||||
backend "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
|
backend "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
|
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/shared/constant"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/shared/utils"
|
"go.woodpecker-ci.org/woodpecker/v2/shared/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -50,41 +50,41 @@ func NewRunner(workEngine rpc.Peer, f rpc.Filter, h string, state *State, backen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Runner) Run(runnerCtx context.Context) error { //nolint:contextcheck
|
func (r *Runner) Run(runnerCtx, shutdownCtx context.Context) error { //nolint:contextcheck
|
||||||
log.Debug().Msg("request next execution")
|
log.Debug().Msg("request next execution")
|
||||||
|
|
||||||
meta, _ := metadata.FromOutgoingContext(runnerCtx)
|
meta, _ := metadata.FromOutgoingContext(runnerCtx)
|
||||||
ctxMeta := metadata.NewOutgoingContext(context.Background(), meta)
|
ctxMeta := metadata.NewOutgoingContext(context.Background(), meta)
|
||||||
|
|
||||||
// get the next workflow from the queue
|
// get the next workflow from the queue
|
||||||
work, err := r.client.Next(runnerCtx, r.filter)
|
workflow, err := r.client.Next(runnerCtx, r.filter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if work == nil {
|
if workflow == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
timeout := time.Hour
|
timeout := time.Hour
|
||||||
if minutes := work.Timeout; minutes != 0 {
|
if minutes := workflow.Timeout; minutes != 0 {
|
||||||
timeout = time.Duration(minutes) * time.Minute
|
timeout = time.Duration(minutes) * time.Minute
|
||||||
}
|
}
|
||||||
|
|
||||||
repoName := extractRepositoryName(work.Config) // hack
|
repoName := extractRepositoryName(workflow.Config) // hack
|
||||||
pipelineNumber := extractPipelineNumber(work.Config) // hack
|
pipelineNumber := extractPipelineNumber(workflow.Config) // hack
|
||||||
|
|
||||||
r.counter.Add(
|
r.counter.Add(
|
||||||
work.ID,
|
workflow.ID,
|
||||||
timeout,
|
timeout,
|
||||||
repoName,
|
repoName,
|
||||||
pipelineNumber,
|
pipelineNumber,
|
||||||
)
|
)
|
||||||
defer r.counter.Done(work.ID)
|
defer r.counter.Done(workflow.ID)
|
||||||
|
|
||||||
logger := log.With().
|
logger := log.With().
|
||||||
Str("repo", repoName).
|
Str("repo", repoName).
|
||||||
Str("pipeline", pipelineNumber).
|
Str("pipeline", pipelineNumber).
|
||||||
Str("id", work.ID).
|
Str("workflow_id", workflow.ID).
|
||||||
Logger()
|
Logger()
|
||||||
|
|
||||||
logger.Debug().Msg("received execution")
|
logger.Debug().Msg("received execution")
|
||||||
|
@ -99,17 +99,16 @@ func (r *Runner) Run(runnerCtx context.Context) error { //nolint:contextcheck
|
||||||
logger.Error().Msg("Received sigterm termination signal")
|
logger.Error().Msg("Received sigterm termination signal")
|
||||||
})
|
})
|
||||||
|
|
||||||
canceled := abool.New()
|
canceled := false
|
||||||
go func() {
|
go func() {
|
||||||
logger.Debug().Msg("listen for cancel signal")
|
logger.Debug().Msg("listen for cancel signal")
|
||||||
|
|
||||||
if err := r.client.Wait(workflowCtx, work.ID); err != nil {
|
if err := r.client.Wait(workflowCtx, workflow.ID); err != nil {
|
||||||
canceled.SetTo(true)
|
canceled = true
|
||||||
logger.Warn().Err(err).Msg("cancel signal received")
|
logger.Warn().Err(err).Msg("cancel signal received")
|
||||||
|
|
||||||
cancel()
|
cancel()
|
||||||
} else {
|
} else {
|
||||||
logger.Debug().Msg("stop listening for cancel signal")
|
logger.Debug().Msg("done listening for cancel signal")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -118,81 +117,74 @@ func (r *Runner) Run(runnerCtx context.Context) error { //nolint:contextcheck
|
||||||
select {
|
select {
|
||||||
case <-workflowCtx.Done():
|
case <-workflowCtx.Done():
|
||||||
logger.Debug().Msg("pipeline done")
|
logger.Debug().Msg("pipeline done")
|
||||||
|
|
||||||
return
|
return
|
||||||
case <-time.After(time.Minute):
|
|
||||||
logger.Debug().Msg("pipeline lease renewed")
|
|
||||||
|
|
||||||
if err := r.client.Extend(workflowCtx, work.ID); err != nil {
|
case <-time.After(constant.TaskTimeout / 3):
|
||||||
|
logger.Debug().Msg("pipeline lease renewed")
|
||||||
|
if err := r.client.Extend(workflowCtx, workflow.ID); err != nil {
|
||||||
log.Error().Err(err).Msg("extending pipeline deadline failed")
|
log.Error().Err(err).Msg("extending pipeline deadline failed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
state := rpc.State{}
|
state := rpc.WorkflowState{}
|
||||||
state.Started = time.Now().Unix()
|
state.Started = time.Now().Unix()
|
||||||
|
|
||||||
err = r.client.Init(runnerCtx, work.ID, state)
|
err = r.client.Init(runnerCtx, workflow.ID, state)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error().Err(err).Msg("pipeline initialization failed")
|
logger.Error().Err(err).Msg("workflow initialization failed")
|
||||||
|
// TODO: should we return here?
|
||||||
}
|
}
|
||||||
|
|
||||||
var uploads sync.WaitGroup
|
var uploads sync.WaitGroup
|
||||||
//nolint:contextcheck
|
//nolint:contextcheck
|
||||||
err = pipeline.New(work.Config,
|
err = pipeline.New(workflow.Config,
|
||||||
pipeline.WithContext(workflowCtx),
|
pipeline.WithContext(workflowCtx),
|
||||||
pipeline.WithTaskUUID(fmt.Sprint(work.ID)),
|
pipeline.WithTaskUUID(fmt.Sprint(workflow.ID)),
|
||||||
pipeline.WithLogger(r.createLogger(logger, &uploads, work)),
|
pipeline.WithLogger(r.createLogger(logger, &uploads, workflow)),
|
||||||
pipeline.WithTracer(r.createTracer(ctxMeta, logger, work)),
|
pipeline.WithTracer(r.createTracer(ctxMeta, &uploads, logger, workflow)),
|
||||||
pipeline.WithBackend(*r.backend),
|
pipeline.WithBackend(*r.backend),
|
||||||
pipeline.WithDescription(map[string]string{
|
pipeline.WithDescription(map[string]string{
|
||||||
"ID": work.ID,
|
"workflow_id": workflow.ID,
|
||||||
"Repo": repoName,
|
"repo": repoName,
|
||||||
"Pipeline": pipelineNumber,
|
"pipeline_number": pipelineNumber,
|
||||||
}),
|
}),
|
||||||
).Run(runnerCtx)
|
).Run(runnerCtx)
|
||||||
|
|
||||||
state.Finished = time.Now().Unix()
|
state.Finished = time.Now().Unix()
|
||||||
state.Exited = true
|
|
||||||
|
|
||||||
if canceled.IsSet() {
|
if errors.Is(err, pipeline.ErrCancel) {
|
||||||
state.Error = ""
|
canceled = true
|
||||||
state.ExitCode = pipeline.ExitCodeKilled
|
} else if canceled {
|
||||||
} else if err != nil {
|
err = errors.Join(err, pipeline.ErrCancel)
|
||||||
pExitError := &pipeline.ExitError{}
|
}
|
||||||
switch {
|
|
||||||
case errors.As(err, &pExitError):
|
if err != nil {
|
||||||
state.ExitCode = pExitError.Code
|
|
||||||
case errors.Is(err, pipeline.ErrCancel):
|
|
||||||
state.Error = ""
|
|
||||||
state.ExitCode = pipeline.ExitCodeKilled
|
|
||||||
canceled.SetTo(true)
|
|
||||||
default:
|
|
||||||
state.ExitCode = 1
|
|
||||||
state.Error = err.Error()
|
state.Error = err.Error()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
logger.Debug().
|
logger.Debug().
|
||||||
Str("error", state.Error).
|
Str("error", state.Error).
|
||||||
Int("exit_code", state.ExitCode).
|
Bool("canceled", canceled).
|
||||||
Bool("canceled", canceled.IsSet()).
|
Msg("workflow finished")
|
||||||
Msg("pipeline complete")
|
|
||||||
|
|
||||||
logger.Debug().Msg("uploading logs")
|
logger.Debug().Msg("uploading logs and traces / states ...")
|
||||||
uploads.Wait()
|
uploads.Wait()
|
||||||
logger.Debug().Msg("uploading logs complete")
|
logger.Debug().Msg("uploaded logs and traces / states")
|
||||||
|
|
||||||
logger.Debug().
|
logger.Debug().
|
||||||
Str("error", state.Error).
|
Str("error", state.Error).
|
||||||
Int("exit_code", state.ExitCode).
|
Msg("updating workflow status")
|
||||||
Msg("updating pipeline status")
|
|
||||||
|
|
||||||
if err := r.client.Done(runnerCtx, work.ID, state); err != nil {
|
doneCtx := runnerCtx
|
||||||
logger.Error().Err(err).Msg("updating pipeline status failed")
|
if doneCtx.Err() != nil {
|
||||||
|
doneCtx = shutdownCtx
|
||||||
|
}
|
||||||
|
if err := r.client.Done(doneCtx, workflow.ID, state); err != nil {
|
||||||
|
logger.Error().Err(err).Msg("updating workflow status failed")
|
||||||
} else {
|
} else {
|
||||||
logger.Debug().Msg("updating pipeline status complete")
|
logger.Debug().Msg("updating workflow status complete")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
|
@ -26,17 +27,19 @@ import (
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
|
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *Runner) createTracer(ctxMeta context.Context, logger zerolog.Logger, workflow *rpc.Workflow) pipeline.TraceFunc {
|
func (r *Runner) createTracer(ctxMeta context.Context, uploads *sync.WaitGroup, logger zerolog.Logger, workflow *rpc.Workflow) pipeline.TraceFunc {
|
||||||
return func(state *pipeline.State) error {
|
return func(state *pipeline.State) error {
|
||||||
|
uploads.Add(1)
|
||||||
|
|
||||||
stepLogger := logger.With().
|
stepLogger := logger.With().
|
||||||
Str("image", state.Pipeline.Step.Image).
|
Str("image", state.Pipeline.Step.Image).
|
||||||
Str("workflowID", workflow.ID).
|
Str("workflow_id", workflow.ID).
|
||||||
Err(state.Process.Error).
|
Err(state.Process.Error).
|
||||||
Int("exit_code", state.Process.ExitCode).
|
Int("exit_code", state.Process.ExitCode).
|
||||||
Bool("exited", state.Process.Exited).
|
Bool("exited", state.Process.Exited).
|
||||||
Logger()
|
Logger()
|
||||||
|
|
||||||
stepState := rpc.State{
|
stepState := rpc.StepState{
|
||||||
StepUUID: state.Pipeline.Step.UUID,
|
StepUUID: state.Pipeline.Step.UUID,
|
||||||
Exited: state.Process.Exited,
|
Exited: state.Process.Exited,
|
||||||
ExitCode: state.Process.ExitCode,
|
ExitCode: state.Process.ExitCode,
|
||||||
|
@ -57,6 +60,7 @@ func (r *Runner) createTracer(ctxMeta context.Context, logger zerolog.Logger, wo
|
||||||
}
|
}
|
||||||
|
|
||||||
stepLogger.Debug().Msg("update step status complete")
|
stepLogger.Debug().Msg("update step status complete")
|
||||||
|
uploads.Done()
|
||||||
}()
|
}()
|
||||||
if state.Process.Exited {
|
if state.Process.Exited {
|
||||||
return nil
|
return nil
|
||||||
|
@ -68,21 +72,12 @@ func (r *Runner) createTracer(ctxMeta context.Context, logger zerolog.Logger, wo
|
||||||
// TODO: find better way to update this state and move it to pipeline to have the same env in cli-exec
|
// 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.Time, 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.Time, 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2021 Woodpecker Authors
|
// Copyright 2024 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.
|
||||||
|
@ -12,16 +12,19 @@
|
||||||
// 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 admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"src.techknowlogick.com/xormigrate"
|
"github.com/urfave/cli/v3"
|
||||||
"xorm.io/xorm"
|
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/admin/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
var alterTableReposDropCounter = xormigrate.Migration{
|
// Command exports the admin command set.
|
||||||
ID: "alter-table-drop-counter",
|
var Command = &cli.Command{
|
||||||
MigrateSession: func(sess *xorm.Session) error {
|
Name: "admin",
|
||||||
return dropTableColumns(sess, "repos", "repo_counter")
|
Usage: "administer server settings",
|
||||||
|
Commands: []*cli.Command{
|
||||||
|
registry.Command,
|
||||||
},
|
},
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2023 Woodpecker Authors
|
// Copyright 2024 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.
|
||||||
|
@ -15,14 +15,14 @@
|
||||||
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 registries",
|
Usage: "manage global registries",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
registryCreateCmd,
|
registryCreateCmd,
|
||||||
registryDeleteCmd,
|
registryDeleteCmd,
|
||||||
registryUpdateCmd,
|
registryUpdateCmd,
|
76
cli/admin/registry/registry_add.go
Normal file
76
cli/admin/registry/registry_add.go
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
// Copyright 2024 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package registry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||||
|
)
|
||||||
|
|
||||||
|
var registryCreateCmd = &cli.Command{
|
||||||
|
Name: "add",
|
||||||
|
Usage: "adds a registry",
|
||||||
|
Action: registryCreate,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "hostname",
|
||||||
|
Usage: "registry hostname",
|
||||||
|
Value: "docker.io",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "username",
|
||||||
|
Usage: "registry username",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "password",
|
||||||
|
Usage: "registry password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func registryCreate(ctx context.Context, c *cli.Command) error {
|
||||||
|
var (
|
||||||
|
hostname = c.String("hostname")
|
||||||
|
username = c.String("username")
|
||||||
|
password = c.String("password")
|
||||||
|
)
|
||||||
|
|
||||||
|
client, err := internal.NewClient(ctx, c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
registry := &woodpecker.Registry{
|
||||||
|
Address: hostname,
|
||||||
|
Username: username,
|
||||||
|
Password: password,
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(registry.Password, "@") {
|
||||||
|
path := strings.TrimPrefix(registry.Password, "@")
|
||||||
|
out, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
registry.Password = string(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = client.GlobalRegistryCreate(registry)
|
||||||
|
return err
|
||||||
|
}
|
63
cli/admin/registry/registry_info.go
Normal file
63
cli/admin/registry/registry_info.go
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
// Copyright 2024 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package registry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"html/template"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
var registryInfoCmd = &cli.Command{
|
||||||
|
Name: "info",
|
||||||
|
Usage: "display registry info",
|
||||||
|
Action: registryInfo,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "hostname",
|
||||||
|
Usage: "registry hostname",
|
||||||
|
Value: "docker.io",
|
||||||
|
},
|
||||||
|
common.FormatFlag(tmplRegistryList, true),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func registryInfo(ctx context.Context, c *cli.Command) error {
|
||||||
|
var (
|
||||||
|
hostname = c.String("hostname")
|
||||||
|
format = c.String("format") + "\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
client, err := internal.NewClient(ctx, c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
registry, err := client.GlobalRegistry(hostname)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl, err := template.New("_").Parse(format)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return tmpl.Execute(os.Stdout, registry)
|
||||||
|
}
|
66
cli/admin/registry/registry_list.go
Normal file
66
cli/admin/registry/registry_list.go
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
// Copyright 2024 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package registry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"html/template"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
var registryListCmd = &cli.Command{
|
||||||
|
Name: "ls",
|
||||||
|
Usage: "list registries",
|
||||||
|
Action: registryList,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
common.FormatFlag(tmplRegistryList, true),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func registryList(ctx context.Context, c *cli.Command) error {
|
||||||
|
format := c.String("format") + "\n"
|
||||||
|
|
||||||
|
client, err := internal.NewClient(ctx, c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
list, err := client.GlobalRegistryList()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl, err := template.New("_").Parse(format)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, registry := range list {
|
||||||
|
if err := tmpl.Execute(os.Stdout, registry); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Template for registry list information.
|
||||||
|
var tmplRegistryList = "\x1b[33m{{ .Address }} \x1b[0m" + `
|
||||||
|
Username: {{ .Username }}
|
||||||
|
Email: {{ .Email }}
|
||||||
|
`
|
47
cli/admin/registry/registry_rm.go
Normal file
47
cli/admin/registry/registry_rm.go
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
// Copyright 2024 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package registry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
var registryDeleteCmd = &cli.Command{
|
||||||
|
Name: "rm",
|
||||||
|
Usage: "remove a registry",
|
||||||
|
Action: registryDelete,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "hostname",
|
||||||
|
Usage: "registry hostname",
|
||||||
|
Value: "docker.io",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func registryDelete(ctx context.Context, c *cli.Command) error {
|
||||||
|
hostname := c.String("hostname")
|
||||||
|
|
||||||
|
client, err := internal.NewClient(ctx, c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.GlobalRegistryDelete(hostname)
|
||||||
|
}
|
79
cli/admin/registry/registry_set.go
Normal file
79
cli/admin/registry/registry_set.go
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
// Copyright 2024 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package registry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||||
|
)
|
||||||
|
|
||||||
|
var registryUpdateCmd = &cli.Command{
|
||||||
|
Name: "update",
|
||||||
|
Usage: "update a registry",
|
||||||
|
Action: registryUpdate,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
common.OrgFlag,
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "hostname",
|
||||||
|
Usage: "registry hostname",
|
||||||
|
Value: "docker.io",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "username",
|
||||||
|
Usage: "registry username",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "password",
|
||||||
|
Usage: "registry password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func registryUpdate(ctx context.Context, c *cli.Command) error {
|
||||||
|
var (
|
||||||
|
hostname = c.String("hostname")
|
||||||
|
username = c.String("username")
|
||||||
|
password = c.String("password")
|
||||||
|
)
|
||||||
|
|
||||||
|
client, err := internal.NewClient(ctx, c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
registry := &woodpecker.Registry{
|
||||||
|
Address: hostname,
|
||||||
|
Username: username,
|
||||||
|
Password: password,
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(registry.Password, "@") {
|
||||||
|
path := strings.TrimPrefix(registry.Password, "@")
|
||||||
|
out, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
registry.Password = string(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = client.GlobalRegistryUpdate(registry)
|
||||||
|
return err
|
||||||
|
}
|
|
@ -15,49 +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/v2/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,
|
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,
|
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,
|
Hidden: true,
|
||||||
|
|
|
@ -6,7 +6,7 @@ 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/v2/cli/internal/config"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/update"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/update"
|
||||||
|
@ -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) error {
|
||||||
if err := setupGlobalLogger(c); err != nil {
|
if err := setupGlobalLogger(ctx, c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func(context.Context) {
|
||||||
if c.Bool("disable-update-check") {
|
if c.Bool("disable-update-check") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -37,23 +37,23 @@ func Before(c *cli.Context) error {
|
||||||
|
|
||||||
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("A new version of woodpecker-cli is available: %s. Update by running: %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 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():
|
||||||
|
|
|
@ -15,11 +15,12 @@
|
||||||
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/v2/shared/constant"
|
||||||
)
|
)
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/shared/logger"
|
"go.woodpecker-ci.org/woodpecker/v2/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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,14 +15,14 @@
|
||||||
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,
|
cronUpdateCmd,
|
||||||
|
|
|
@ -15,10 +15,11 @@
|
||||||
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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -50,9 +51,9 @@ var cronCreateCmd = &cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func cronCreate(c *cli.Context) error {
|
func cronCreate(ctx context.Context, c *cli.Command) error {
|
||||||
var (
|
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,10 +15,11 @@
|
||||||
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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -40,16 +41,16 @@ var cronInfoCmd = &cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func cronInfo(c *cli.Context) error {
|
func cronInfo(ctx context.Context, c *cli.Command) error {
|
||||||
var (
|
var (
|
||||||
jobID = c.Int64("id")
|
cronID = c.Int("id")
|
||||||
repoIDOrFullName = c.String("repository")
|
repoIDOrFullName = c.String("repository")
|
||||||
format = c.String("format") + "\n"
|
format = c.String("format") + "\n"
|
||||||
)
|
)
|
||||||
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
|
||||||
}
|
}
|
||||||
|
@ -58,7 +59,7 @@ func cronInfo(c *cli.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cron, err := client.CronGet(repoID, jobID)
|
cron, err := client.CronGet(repoID, cronID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,11 @@
|
||||||
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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -35,7 +36,7 @@ var cronListCmd = &cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func cronList(c *cli.Context) error {
|
func cronList(ctx context.Context, c *cli.Command) error {
|
||||||
var (
|
var (
|
||||||
format = c.String("format") + "\n"
|
format = c.String("format") + "\n"
|
||||||
repoIDOrFullName = c.String("repository")
|
repoIDOrFullName = c.String("repository")
|
||||||
|
@ -43,7 +44,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
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,10 @@
|
||||||
package cron
|
package cron
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -38,15 +39,15 @@ var cronDeleteCmd = &cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func cronDelete(c *cli.Context) error {
|
func cronDelete(ctx context.Context, c *cli.Command) error {
|
||||||
var (
|
var (
|
||||||
jobID = c.Int64("id")
|
cronID = c.Int("id")
|
||||||
repoIDOrFullName = c.String("repository")
|
repoIDOrFullName = c.String("repository")
|
||||||
)
|
)
|
||||||
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
|
||||||
}
|
}
|
||||||
|
@ -54,7 +55,7 @@ func cronDelete(c *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = client.CronDelete(repoID, jobID)
|
err = client.CronDelete(repoID, cronID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,11 @@
|
||||||
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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -53,10 +54,10 @@ var cronUpdateCmd = &cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func cronUpdate(c *cli.Context) error {
|
func cronUpdate(ctx context.Context, c *cli.Command) error {
|
||||||
var (
|
var (
|
||||||
repoIDOrFullName = c.String("repository")
|
repoIDOrFullName = c.String("repository")
|
||||||
jobID = c.Int64("id")
|
cronID = c.Int("id")
|
||||||
jobName = c.String("name")
|
jobName = c.String("name")
|
||||||
branch = c.String("branch")
|
branch = c.String("branch")
|
||||||
schedule = c.String("schedule")
|
schedule = c.String("schedule")
|
||||||
|
@ -65,7 +66,7 @@ func cronUpdate(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
|
||||||
}
|
}
|
||||||
|
@ -74,7 +75,7 @@ func cronUpdate(c *cli.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cron := &woodpecker.Cron{
|
cron := &woodpecker.Cron{
|
||||||
ID: jobID,
|
ID: cronID,
|
||||||
Name: jobName,
|
Name: jobName,
|
||||||
Branch: branch,
|
Branch: branch,
|
||||||
Schedule: schedule,
|
Schedule: schedule,
|
||||||
|
|
|
@ -15,12 +15,13 @@
|
||||||
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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -30,7 +31,7 @@ import (
|
||||||
// Command exports the deploy command.
|
// Command exports the deploy command.
|
||||||
var Command = &cli.Command{
|
var Command = &cli.Command{
|
||||||
Name: "deploy",
|
Name: "deploy",
|
||||||
Usage: "deploy code",
|
Usage: "trigger a pipeline with the 'deployment' event",
|
||||||
ArgsUsage: "<repo-id|repo-full-name> <pipeline> <environment>",
|
ArgsUsage: "<repo-id|repo-full-name> <pipeline> <environment>",
|
||||||
Action: deploy,
|
Action: deploy,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
@ -38,7 +39,6 @@ var Command = &cli.Command{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "branch",
|
Name: "branch",
|
||||||
Usage: "branch filter",
|
Usage: "branch filter",
|
||||||
Value: "main",
|
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "event",
|
Name: "event",
|
||||||
|
@ -58,8 +58,8 @@ var Command = &cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,15 @@ func deploy(c *cli.Context) error {
|
||||||
event := c.String("event")
|
event := c.String("event")
|
||||||
status := c.String("status")
|
status := c.String("status")
|
||||||
|
|
||||||
|
if branch == "" {
|
||||||
|
repo, err := client.Repo(repoID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
branch = repo.DefaultBranch
|
||||||
|
}
|
||||||
|
|
||||||
pipelineArg := c.Args().Get(1)
|
pipelineArg := c.Args().Get(1)
|
||||||
var number int64
|
var number int64
|
||||||
if pipelineArg == "last" {
|
if pipelineArg == "last" {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2022 Woodpecker Authors
|
// Copyright 2024 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.
|
||||||
|
@ -12,16 +12,13 @@
|
||||||
// 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
|
//go:build test
|
||||||
|
// +build test
|
||||||
|
|
||||||
import (
|
package exec
|
||||||
"src.techknowlogick.com/xormigrate"
|
|
||||||
"xorm.io/xorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
var dropFiles = xormigrate.Migration{
|
import "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/dummy"
|
||||||
ID: "drop-files",
|
|
||||||
MigrateSession: func(sess *xorm.Session) error {
|
func init() { //nolint:gochecknoinits
|
||||||
return sess.DropTable("files")
|
backends = append(backends, dummy.New())
|
||||||
},
|
|
||||||
}
|
}
|
|
@ -26,20 +26,22 @@ import (
|
||||||
|
|
||||||
"github.com/drone/envsubst"
|
"github.com/drone/envsubst"
|
||||||
"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/v2/cli/common"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/lint"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline"
|
"go.woodpecker-ci.org/woodpecker/v2/pipeline"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend"
|
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/docker"
|
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/docker"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/kubernetes"
|
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/kubernetes"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/local"
|
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/local"
|
||||||
backendTypes "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
|
backend_types "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml"
|
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/compiler"
|
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/compiler"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/linter"
|
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/linter"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/matrix"
|
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/matrix"
|
||||||
pipelineLog "go.woodpecker-ci.org/woodpecker/v2/pipeline/log"
|
pipelineLog "go.woodpecker-ci.org/woodpecker/v2/pipeline/log"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/shared/constant"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/shared/utils"
|
"go.woodpecker-ci.org/woodpecker/v2/shared/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -52,11 +54,17 @@ var Command = &cli.Command{
|
||||||
Flags: utils.MergeSlices(flags, docker.Flags, kubernetes.Flags, local.Flags),
|
Flags: utils.MergeSlices(flags, docker.Flags, kubernetes.Flags, local.Flags),
|
||||||
}
|
}
|
||||||
|
|
||||||
func run(c *cli.Context) error {
|
var backends = []backend_types.Backend{
|
||||||
return common.RunPipelineFunc(c, execFile, execDir)
|
kubernetes.New(),
|
||||||
|
docker.New(),
|
||||||
|
local.New(),
|
||||||
}
|
}
|
||||||
|
|
||||||
func execDir(c *cli.Context, dir string) error {
|
func run(ctx context.Context, c *cli.Command) error {
|
||||||
|
return common.RunPipelineFunc(ctx, c, execFile, execDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
func execDir(ctx context.Context, c *cli.Command, dir string) error {
|
||||||
// TODO: respect pipeline dependency
|
// TODO: respect pipeline dependency
|
||||||
repoPath := c.String("repo-path")
|
repoPath := c.String("repo-path")
|
||||||
if repoPath != "" {
|
if repoPath != "" {
|
||||||
|
@ -75,7 +83,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) // TODO: should we drop errors or store them and report back?
|
||||||
fmt.Println("")
|
fmt.Println("")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -84,7 +92,7 @@ func execDir(c *cli.Context, dir string) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func execFile(c *cli.Context, file string) error {
|
func execFile(ctx context.Context, c *cli.Command, file string) error {
|
||||||
repoPath := c.String("repo-path")
|
repoPath := c.String("repo-path")
|
||||||
if repoPath != "" {
|
if repoPath != "" {
|
||||||
repoPath, _ = filepath.Abs(repoPath)
|
repoPath, _ = filepath.Abs(repoPath)
|
||||||
|
@ -94,10 +102,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)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runExec(c *cli.Context, file, repoPath string) error {
|
func runExec(ctx context.Context, c *cli.Command, file, repoPath string) error {
|
||||||
dat, err := os.ReadFile(file)
|
dat, err := os.ReadFile(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -112,7 +120,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)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -120,8 +128,11 @@ 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) error {
|
||||||
metadata := metadataFromContext(c, axis)
|
metadata, err := metadataFromContext(ctx, c, axis)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not create metadata: %w", err)
|
||||||
|
}
|
||||||
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 {
|
||||||
|
@ -177,19 +188,30 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
|
||||||
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
|
||||||
if err := linter.New(linter.WithTrusted(true)).Lint([]*linter.WorkflowConfig{{
|
err = linter.New(
|
||||||
|
linter.WithTrusted(true),
|
||||||
|
linter.PrivilegedPlugins(privilegedPlugins),
|
||||||
|
linter.WithTrustedClonePlugins(constant.TrustedClonePlugins),
|
||||||
|
).Lint([]*linter.WorkflowConfig{{
|
||||||
File: path.Base(file),
|
File: path.Base(file),
|
||||||
RawConfig: confStr,
|
RawConfig: confStr,
|
||||||
Workflow: conf,
|
Workflow: conf,
|
||||||
}}); err != nil {
|
}})
|
||||||
|
if err != nil {
|
||||||
|
str, err := lint.FormatLintError(file, err)
|
||||||
|
fmt.Print(str)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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(
|
||||||
|
@ -223,12 +245,7 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
backendCtx := context.WithValue(c.Context, backendTypes.CliContext, c)
|
backendCtx := context.WithValue(ctx, backend_types.CliCommand, c)
|
||||||
backends := []backendTypes.Backend{
|
|
||||||
kubernetes.New(),
|
|
||||||
docker.New(),
|
|
||||||
local.New(),
|
|
||||||
}
|
|
||||||
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
|
||||||
|
@ -238,21 +255,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
|
||||||
|
@ -274,8 +291,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 *backendTypes.Step, rc io.Reader) 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,51 @@ 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.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{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"WOODPECKER_PREFIX"},
|
Sources: cli.EnvVars("WOODPECKER_PREFIX"),
|
||||||
Name: "prefix",
|
Name: "prefix",
|
||||||
Value: "woodpecker",
|
Value: "woodpecker",
|
||||||
Usage: "prefix used for containers, volumes, networks, ... created by woodpecker",
|
Usage: "prefix used for containers, volumes, networks, ... created by woodpecker",
|
||||||
Hidden: true,
|
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 +71,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 +95,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 +108,246 @@ 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",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_SYSTEM_NAME"},
|
Sources: cli.EnvVars("CI_SYSTEM_HOST"),
|
||||||
|
Name: "system-host",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Sources: cli.EnvVars("CI_SYSTEM_NAME"),
|
||||||
Name: "system-name",
|
Name: "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",
|
||||||
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: "full repo name",
|
||||||
},
|
},
|
||||||
&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",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_REPO_URL"},
|
Sources: cli.EnvVars("CI_REPO_URL"),
|
||||||
Name: "repo-url",
|
Name: "repo-url",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_REPO_CLONE_URL"},
|
Sources: cli.EnvVars("CI_REPO_SCM"),
|
||||||
|
Name: "repo-scm",
|
||||||
|
Value: "git",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Sources: cli.EnvVars("CI_REPO_DEFAULT_BRANCH"),
|
||||||
|
Name: "repo-default-branch",
|
||||||
|
Value: "main",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Sources: cli.EnvVars("CI_REPO_CLONE_URL"),
|
||||||
Name: "repo-clone-url",
|
Name: "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",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_REPO_PRIVATE"},
|
Sources: cli.EnvVars("CI_REPO_PRIVATE"),
|
||||||
Name: "repo-private",
|
Name: "repo-private",
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
EnvVars: []string{"CI_REPO_TRUSTED"},
|
Sources: cli.EnvVars("CI_REPO_TRUSTED"),
|
||||||
Name: "repo-trusted",
|
Name: "repo-trusted",
|
||||||
},
|
},
|
||||||
&cli.IntFlag{
|
&cli.IntFlag{
|
||||||
EnvVars: []string{"CI_PIPELINE_NUMBER"},
|
Sources: cli.EnvVars("CI_PIPELINE_NUMBER"),
|
||||||
Name: "pipeline-number",
|
Name: "pipeline-number",
|
||||||
},
|
},
|
||||||
&cli.IntFlag{
|
&cli.IntFlag{
|
||||||
EnvVars: []string{"CI_PIPELINE_PARENT"},
|
Sources: cli.EnvVars("CI_PIPELINE_PARENT"),
|
||||||
Name: "pipeline-parent",
|
Name: "pipeline-parent",
|
||||||
},
|
},
|
||||||
&cli.Int64Flag{
|
&cli.IntFlag{
|
||||||
EnvVars: []string{"CI_PIPELINE_CREATED"},
|
Sources: cli.EnvVars("CI_PIPELINE_CREATED"),
|
||||||
Name: "pipeline-created",
|
Name: "pipeline-created",
|
||||||
},
|
},
|
||||||
&cli.Int64Flag{
|
&cli.IntFlag{
|
||||||
EnvVars: []string{"CI_PIPELINE_STARTED"},
|
Sources: cli.EnvVars("CI_PIPELINE_STARTED"),
|
||||||
Name: "pipeline-started",
|
Name: "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",
|
||||||
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",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_PIPELINE_TARGET"},
|
Sources: cli.EnvVars("CI_PIPELINE_DEPLOY_TARGET"),
|
||||||
Name: "pipeline-target",
|
Name: "pipeline-deploy-to",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_PIPELINE_TASK"},
|
Sources: cli.EnvVars("CI_PIPELINE_DEPLOY_TASK"),
|
||||||
Name: "pipeline-task",
|
Name: "pipeline-deploy-task",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_COMMIT_SHA"},
|
Sources: cli.EnvVars("CI_PIPELINE_FILES"),
|
||||||
|
Usage: "either json formatted list of strings, or comma separated string list",
|
||||||
|
Name: "pipeline-files",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Sources: cli.EnvVars("CI_COMMIT_SHA"),
|
||||||
Name: "commit-sha",
|
Name: "commit-sha",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_COMMIT_REF"},
|
Sources: cli.EnvVars("CI_COMMIT_REF"),
|
||||||
Name: "commit-ref",
|
Name: "commit-ref",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_COMMIT_REFSPEC"},
|
Sources: cli.EnvVars("CI_COMMIT_REFSPEC"),
|
||||||
Name: "commit-refspec",
|
Name: "commit-refspec",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_COMMIT_BRANCH"},
|
Sources: cli.EnvVars("CI_COMMIT_BRANCH"),
|
||||||
Name: "commit-branch",
|
Name: "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",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_COMMIT_AUTHOR_NAME"},
|
Sources: cli.EnvVars("CI_COMMIT_AUTHOR"),
|
||||||
Name: "commit-author-name",
|
Name: "commit-author-name",
|
||||||
},
|
},
|
||||||
&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",
|
||||||
},
|
},
|
||||||
&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",
|
||||||
},
|
},
|
||||||
|
&cli.StringSliceFlag{
|
||||||
|
Sources: cli.EnvVars("CI_COMMIT_PULL_REQUEST_LABELS"),
|
||||||
|
Name: "commit-pull-labels",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Sources: cli.EnvVars("CI_COMMIT_PRERELEASE"),
|
||||||
|
Name: "commit-release-is-pre",
|
||||||
|
},
|
||||||
&cli.IntFlag{
|
&cli.IntFlag{
|
||||||
EnvVars: []string{"CI_PREV_PIPELINE_NUMBER"},
|
Sources: cli.EnvVars("CI_PREV_PIPELINE_NUMBER"),
|
||||||
Name: "prev-pipeline-number",
|
Name: "prev-pipeline-number",
|
||||||
},
|
},
|
||||||
&cli.Int64Flag{
|
&cli.IntFlag{
|
||||||
EnvVars: []string{"CI_PREV_PIPELINE_CREATED"},
|
Sources: cli.EnvVars("CI_PREV_PIPELINE_CREATED"),
|
||||||
Name: "prev-pipeline-created",
|
Name: "prev-pipeline-created",
|
||||||
},
|
},
|
||||||
&cli.Int64Flag{
|
&cli.IntFlag{
|
||||||
EnvVars: []string{"CI_PREV_PIPELINE_STARTED"},
|
Sources: cli.EnvVars("CI_PREV_PIPELINE_STARTED"),
|
||||||
Name: "prev-pipeline-started",
|
Name: "prev-pipeline-started",
|
||||||
},
|
},
|
||||||
&cli.Int64Flag{
|
&cli.IntFlag{
|
||||||
EnvVars: []string{"CI_PREV_PIPELINE_FINISHED"},
|
Sources: cli.EnvVars("CI_PREV_PIPELINE_FINISHED"),
|
||||||
Name: "prev-pipeline-finished",
|
Name: "prev-pipeline-finished",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_PREV_PIPELINE_STATUS"},
|
Sources: cli.EnvVars("CI_PREV_PIPELINE_STATUS"),
|
||||||
Name: "prev-pipeline-status",
|
Name: "prev-pipeline-status",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_PREV_PIPELINE_EVENT"},
|
Sources: cli.EnvVars("CI_PREV_PIPELINE_EVENT"),
|
||||||
Name: "prev-pipeline-event",
|
Name: "prev-pipeline-event",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_PREV_PIPELINE_URL"},
|
Sources: cli.EnvVars("CI_PREV_PIPELINE_FORGE_URL"),
|
||||||
Name: "prev-pipeline-url",
|
Name: "prev-pipeline-url",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_PREV_COMMIT_SHA"},
|
Sources: cli.EnvVars("CI_PREV_PIPELINE_DEPLOY_TARGET"),
|
||||||
|
Name: "prev-pipeline-deploy-to",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Sources: cli.EnvVars("CI_PREV_PIPELINE_DEPLOY_TASK"),
|
||||||
|
Name: "prev-pipeline-deploy-task",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Sources: cli.EnvVars("CI_PREV_COMMIT_SHA"),
|
||||||
Name: "prev-commit-sha",
|
Name: "prev-commit-sha",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_PREV_COMMIT_REF"},
|
Sources: cli.EnvVars("CI_PREV_COMMIT_REF"),
|
||||||
Name: "prev-commit-ref",
|
Name: "prev-commit-ref",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_PREV_COMMIT_REFSPEC"},
|
Sources: cli.EnvVars("CI_PREV_COMMIT_REFSPEC"),
|
||||||
Name: "prev-commit-refspec",
|
Name: "prev-commit-refspec",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_PREV_COMMIT_BRANCH"},
|
Sources: cli.EnvVars("CI_PREV_COMMIT_BRANCH"),
|
||||||
Name: "prev-commit-branch",
|
Name: "prev-commit-branch",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_PREV_COMMIT_MESSAGE"},
|
Sources: cli.EnvVars("CI_PREV_COMMIT_MESSAGE"),
|
||||||
Name: "prev-commit-message",
|
Name: "prev-commit-message",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_PREV_COMMIT_AUTHOR_NAME"},
|
Sources: cli.EnvVars("CI_PREV_COMMIT_AUTHOR"),
|
||||||
Name: "prev-commit-author-name",
|
Name: "prev-commit-author-name",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_PREV_COMMIT_AUTHOR_AVATAR"},
|
Sources: cli.EnvVars("CI_PREV_COMMIT_AUTHOR_AVATAR"),
|
||||||
Name: "prev-commit-author-avatar",
|
Name: "prev-commit-author-avatar",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_PREV_COMMIT_AUTHOR_EMAIL"},
|
Sources: cli.EnvVars("CI_PREV_COMMIT_AUTHOR_EMAIL"),
|
||||||
Name: "prev-commit-author-email",
|
Name: "prev-commit-author-email",
|
||||||
},
|
},
|
||||||
&cli.IntFlag{
|
&cli.IntFlag{
|
||||||
EnvVars: []string{"CI_WORKFLOW_NAME"},
|
Sources: cli.EnvVars("CI_WORKFLOW_NAME"),
|
||||||
Name: "workflow-name",
|
Name: "workflow-name",
|
||||||
},
|
},
|
||||||
&cli.IntFlag{
|
&cli.IntFlag{
|
||||||
EnvVars: []string{"CI_WORKFLOW_NUMBER"},
|
Sources: cli.EnvVars("CI_WORKFLOW_NUMBER"),
|
||||||
Name: "workflow-number",
|
Name: "workflow-number",
|
||||||
},
|
},
|
||||||
&cli.IntFlag{
|
&cli.IntFlag{
|
||||||
EnvVars: []string{"CI_STEP_NAME"},
|
Sources: cli.EnvVars("CI_STEP_NAME"),
|
||||||
Name: "step-name",
|
Name: "step-name",
|
||||||
},
|
},
|
||||||
&cli.StringSliceFlag{
|
&cli.StringSliceFlag{
|
||||||
EnvVars: []string{"CI_ENV"},
|
Sources: cli.EnvVars("CI_ENV"),
|
||||||
Name: "env",
|
Name: "env",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_FORGE_TYPE"},
|
Sources: cli.EnvVars("CI_FORGE_TYPE"),
|
||||||
Name: "forge-type",
|
Name: "forge-type",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_FORGE_URL"},
|
Sources: cli.EnvVars("CI_FORGE_URL"),
|
||||||
Name: "forge-url",
|
Name: "forge-url",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,13 @@
|
||||||
package exec
|
package exec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"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/v2/pipeline/frontend/metadata"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/matrix"
|
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/matrix"
|
||||||
|
@ -26,7 +29,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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) (metadata.Metadata, error) {
|
||||||
platform := c.String("system-platform")
|
platform := c.String("system-platform")
|
||||||
if platform == "" {
|
if platform == "" {
|
||||||
platform = runtime.GOOS + "/" + runtime.GOARCH
|
platform = runtime.GOOS + "/" + runtime.GOARCH
|
||||||
|
@ -40,28 +43,42 @@ func metadataFromContext(c *cli.Context, axis matrix.Axis) metadata.Metadata {
|
||||||
repoName = fullRepoName[idx+1:]
|
repoName = fullRepoName[idx+1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var changedFiles []string
|
||||||
|
changedFilesRaw := c.String("pipeline-files")
|
||||||
|
if len(changedFilesRaw) != 0 && changedFilesRaw[0] == '[' {
|
||||||
|
if err := json.Unmarshal([]byte(changedFilesRaw), &changedFiles); err != nil {
|
||||||
|
return metadata.Metadata{}, fmt.Errorf("pipeline-files detected json but could not parse it: %w", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, file := range strings.Split(changedFilesRaw, ",") {
|
||||||
|
changedFiles = append(changedFiles, strings.TrimSpace(file))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return metadata.Metadata{
|
return metadata.Metadata{
|
||||||
Repo: metadata.Repo{
|
Repo: metadata.Repo{
|
||||||
Name: repoName,
|
Name: repoName,
|
||||||
Owner: repoOwner,
|
Owner: repoOwner,
|
||||||
RemoteID: c.String("repo-remote-id"),
|
RemoteID: c.String("repo-remote-id"),
|
||||||
ForgeURL: c.String("repo-url"),
|
ForgeURL: c.String("repo-url"),
|
||||||
|
SCM: c.String("repo-scm"),
|
||||||
|
Branch: c.String("repo-default-branch"),
|
||||||
CloneURL: c.String("repo-clone-url"),
|
CloneURL: c.String("repo-clone-url"),
|
||||||
CloneSSHURL: c.String("repo-clone-ssh-url"),
|
CloneSSHURL: c.String("repo-clone-ssh-url"),
|
||||||
Private: c.Bool("repo-private"),
|
Private: c.Bool("repo-private"),
|
||||||
Trusted: c.Bool("repo-trusted"),
|
Trusted: c.Bool("repo-trusted"),
|
||||||
},
|
},
|
||||||
Curr: metadata.Pipeline{
|
Curr: metadata.Pipeline{
|
||||||
Number: c.Int64("pipeline-number"),
|
Number: c.Int("pipeline-number"),
|
||||||
Parent: c.Int64("pipeline-parent"),
|
Parent: c.Int("pipeline-parent"),
|
||||||
Created: c.Int64("pipeline-created"),
|
Created: c.Int("pipeline-created"),
|
||||||
Started: c.Int64("pipeline-started"),
|
Started: c.Int("pipeline-started"),
|
||||||
Finished: c.Int64("pipeline-finished"),
|
Finished: c.Int("pipeline-finished"),
|
||||||
Status: c.String("pipeline-status"),
|
Status: c.String("pipeline-status"),
|
||||||
Event: c.String("pipeline-event"),
|
Event: c.String("pipeline-event"),
|
||||||
ForgeURL: c.String("pipeline-url"),
|
ForgeURL: c.String("pipeline-url"),
|
||||||
Target: c.String("pipeline-target"),
|
DeployTo: c.String("pipeline-deploy-to"),
|
||||||
Task: c.String("pipeline-task"),
|
DeployTask: c.String("pipeline-deploy-task"),
|
||||||
Commit: metadata.Commit{
|
Commit: metadata.Commit{
|
||||||
Sha: c.String("commit-sha"),
|
Sha: c.String("commit-sha"),
|
||||||
Ref: c.String("commit-ref"),
|
Ref: c.String("commit-ref"),
|
||||||
|
@ -73,13 +90,16 @@ func metadataFromContext(c *cli.Context, axis matrix.Axis) metadata.Metadata {
|
||||||
Email: c.String("commit-author-email"),
|
Email: c.String("commit-author-email"),
|
||||||
Avatar: c.String("commit-author-avatar"),
|
Avatar: c.String("commit-author-avatar"),
|
||||||
},
|
},
|
||||||
|
PullRequestLabels: c.StringSlice("commit-pull-labels"),
|
||||||
|
IsPrerelease: c.Bool("commit-release-is-pre"),
|
||||||
|
ChangedFiles: changedFiles,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Prev: metadata.Pipeline{
|
Prev: metadata.Pipeline{
|
||||||
Number: c.Int64("prev-pipeline-number"),
|
Number: c.Int("prev-pipeline-number"),
|
||||||
Created: c.Int64("prev-pipeline-created"),
|
Created: c.Int("prev-pipeline-created"),
|
||||||
Started: c.Int64("prev-pipeline-started"),
|
Started: c.Int("prev-pipeline-started"),
|
||||||
Finished: c.Int64("prev-pipeline-finished"),
|
Finished: c.Int("prev-pipeline-finished"),
|
||||||
Status: c.String("prev-pipeline-status"),
|
Status: c.String("prev-pipeline-status"),
|
||||||
Event: c.String("prev-pipeline-event"),
|
Event: c.String("prev-pipeline-event"),
|
||||||
ForgeURL: c.String("prev-pipeline-url"),
|
ForgeURL: c.String("prev-pipeline-url"),
|
||||||
|
@ -98,16 +118,17 @@ func metadataFromContext(c *cli.Context, axis matrix.Axis) metadata.Metadata {
|
||||||
},
|
},
|
||||||
Workflow: metadata.Workflow{
|
Workflow: metadata.Workflow{
|
||||||
Name: c.String("workflow-name"),
|
Name: c.String("workflow-name"),
|
||||||
Number: c.Int("workflow-number"),
|
Number: int(c.Int("workflow-number")),
|
||||||
Matrix: axis,
|
Matrix: axis,
|
||||||
},
|
},
|
||||||
Step: metadata.Step{
|
Step: metadata.Step{
|
||||||
Name: c.String("step-name"),
|
Name: c.String("step-name"),
|
||||||
Number: c.Int("step-number"),
|
Number: int(c.Int("step-number")),
|
||||||
},
|
},
|
||||||
Sys: metadata.System{
|
Sys: metadata.System{
|
||||||
Name: c.String("system-name"),
|
Name: c.String("system-name"),
|
||||||
URL: c.String("system-url"),
|
URL: c.String("system-url"),
|
||||||
|
Host: c.String("system-host"),
|
||||||
Platform: platform,
|
Platform: platform,
|
||||||
Version: version.Version,
|
Version: version.Version,
|
||||||
},
|
},
|
||||||
|
@ -115,5 +136,5 @@ func metadataFromContext(c *cli.Context, axis matrix.Axis) metadata.Metadata {
|
||||||
Type: c.String("forge-type"),
|
Type: c.String("forge-type"),
|
||||||
URL: c.String("forge-url"),
|
URL: c.String("forge-url"),
|
||||||
},
|
},
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,11 @@
|
||||||
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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -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,12 +33,12 @@ 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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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,15 +15,18 @@
|
||||||
package internal
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os/exec"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
@ -31,7 +34,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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")
|
||||||
|
@ -61,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,
|
||||||
},
|
},
|
||||||
|
@ -90,8 +92,52 @@ func NewClient(c *cli.Context) (woodpecker.Client, error) {
|
||||||
return woodpecker.NewClient(server, client), nil
|
return woodpecker.NewClient(server, client), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getRepoFromGit(remoteName string) (string, error) {
|
||||||
|
cmd := exec.Command("git", "remote", "get-url", remoteName)
|
||||||
|
stdout, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("could not get remote url: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
gitRemote := strings.TrimSpace(string(stdout))
|
||||||
|
|
||||||
|
log.Debug().Str("git-remote", gitRemote).Msg("extracted remote url from git")
|
||||||
|
|
||||||
|
if len(gitRemote) == 0 {
|
||||||
|
return "", fmt.Errorf("no repository provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := vsc_url.Parse(gitRemote)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("could not parse git remote url: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
repoFullName := u.FullName
|
||||||
|
log.Debug().Str("repo", repoFullName).Msg("extracted repository from remote url")
|
||||||
|
|
||||||
|
return repoFullName, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ParseRepo parses the repository owner and name from a string.
|
// ParseRepo parses the repository owner and name from a string.
|
||||||
func ParseRepo(client woodpecker.Client, str string) (repoID int64, err error) {
|
func ParseRepo(client woodpecker.Client, str string) (repoID int64, err error) {
|
||||||
|
if str == "" {
|
||||||
|
str, err = getRepoFromGit("upstream")
|
||||||
|
if err != nil {
|
||||||
|
log.Debug().Err(err).Msg("could not get repository from git upstream remote")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if str == "" {
|
||||||
|
str, err = getRepoFromGit("origin")
|
||||||
|
if err != nil {
|
||||||
|
log.Debug().Err(err).Msg("could not get repository from git origin remote")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if str == "" {
|
||||||
|
return 0, fmt.Errorf("no repository provided")
|
||||||
|
}
|
||||||
|
|
||||||
if strings.Contains(str, "/") {
|
if strings.Contains(str, "/") {
|
||||||
repo, err := client.RepoLookup(str)
|
repo, err := client.RepoLookup(str)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -115,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,20 +15,19 @@
|
||||||
package lint
|
package lint
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
term_env "github.com/muesli/termenv"
|
"github.com/urfave/cli/v3"
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||||
pipeline_errors "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors"
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml"
|
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/linter"
|
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/linter"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/shared/constant"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Command exports the info command.
|
// Command exports the info command.
|
||||||
|
@ -37,13 +36,26 @@ 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 environment variable is defined but empty there will be none",
|
||||||
|
},
|
||||||
|
&cli.StringSliceFlag{
|
||||||
|
Sources: cli.EnvVars("WOODPECKER_PLUGINS_TRUSTED_CLONE"),
|
||||||
|
Name: "plugins-trusted-clone",
|
||||||
|
Usage: "Plugins witch are trusted to handle the netrc info in clone steps",
|
||||||
|
Value: constant.TrustedClonePlugins,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func lint(c *cli.Context) error {
|
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 {
|
||||||
|
@ -53,7 +65,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("")
|
||||||
|
@ -71,9 +83,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 {
|
||||||
output := term_env.NewOutput(os.Stdout)
|
|
||||||
|
|
||||||
fi, err := os.Open(file)
|
fi, err := os.Open(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -87,7 +97,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
|
||||||
}
|
}
|
||||||
|
@ -95,40 +105,23 @@ 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(true),
|
||||||
|
linter.PrivilegedPlugins(c.StringSlice("plugins-privileged")),
|
||||||
|
linter.WithTrustedClonePlugins(c.StringSlice("plugins-trusted-clone")),
|
||||||
|
).Lint([]*linter.WorkflowConfig{config})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("🔥 %s has warnings / errors:\n", output.String(config.File).Underline())
|
str, err := FormatLintError(config.File, err)
|
||||||
|
|
||||||
hasErrors := false
|
if str != "" {
|
||||||
for _, err := range pipeline_errors.GetPipelineErrors(err) {
|
fmt.Print(str)
|
||||||
line := " "
|
|
||||||
|
|
||||||
if err.IsWarning {
|
|
||||||
line = fmt.Sprintf("%s ⚠️ ", line)
|
|
||||||
} else {
|
|
||||||
line = fmt.Sprintf("%s ❌", line)
|
|
||||||
hasErrors = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if data := pipeline_errors.GetLinterData(err); data != nil {
|
return err
|
||||||
line = fmt.Sprintf("%s %s\t%s", line, output.String(data.Field).Bold(), err.Message)
|
|
||||||
} else {
|
|
||||||
line = fmt.Sprintf("%s %s", line, err.Message)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: use table output
|
|
||||||
fmt.Printf("%s\n", line)
|
|
||||||
}
|
|
||||||
|
|
||||||
if hasErrors {
|
|
||||||
return errors.New("config has errors")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("✅ Config is valid")
|
fmt.Println("✅ Config is valid")
|
||||||
|
|
56
cli/lint/utils.go
Normal file
56
cli/lint/utils.go
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package lint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
term_env "github.com/muesli/termenv"
|
||||||
|
|
||||||
|
pipeline_errors "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FormatLintError(file string, err error) (string, error) {
|
||||||
|
if err == nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
output := term_env.NewOutput(os.Stdout)
|
||||||
|
str := ""
|
||||||
|
|
||||||
|
amountErrors := 0
|
||||||
|
amountWarnings := 0
|
||||||
|
linterErrors := pipeline_errors.GetPipelineErrors(err)
|
||||||
|
for _, err := range linterErrors {
|
||||||
|
line := " "
|
||||||
|
|
||||||
|
if err.IsWarning {
|
||||||
|
line = fmt.Sprintf("%s ⚠️ ", line)
|
||||||
|
amountWarnings++
|
||||||
|
} else {
|
||||||
|
line = fmt.Sprintf("%s ❌", line)
|
||||||
|
amountErrors++
|
||||||
|
}
|
||||||
|
|
||||||
|
if data := pipeline_errors.GetLinterData(err); data != nil {
|
||||||
|
line = fmt.Sprintf("%s %s\t%s", line, output.String(data.Field).Bold(), err.Message)
|
||||||
|
} else {
|
||||||
|
line = fmt.Sprintf("%s %s", line, err.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: use table output
|
||||||
|
str = fmt.Sprintf("%s%s\n", str, line)
|
||||||
|
}
|
||||||
|
|
||||||
|
if amountErrors > 0 {
|
||||||
|
if amountWarnings > 0 {
|
||||||
|
str = fmt.Sprintf("🔥 %s has %d errors and warnings:\n%s", output.String(file).Underline(), len(linterErrors), str)
|
||||||
|
} else {
|
||||||
|
str = fmt.Sprintf("🔥 %s has %d errors:\n%s", output.String(file).Underline(), len(linterErrors), str)
|
||||||
|
}
|
||||||
|
return str, errors.New("config has errors")
|
||||||
|
}
|
||||||
|
|
||||||
|
str = fmt.Sprintf("⚠️ %s has %d warnings:\n%s", output.String(file).Underline(), len(linterErrors), str)
|
||||||
|
return str, nil
|
||||||
|
}
|
|
@ -15,14 +15,14 @@
|
||||||
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,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,11 @@
|
||||||
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/v2/cli/internal"
|
||||||
)
|
)
|
||||||
|
@ -26,44 +27,52 @@ import (
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,11 @@
|
||||||
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/v2/cli/internal"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||||
|
@ -31,8 +33,8 @@ var Command = &cli.Command{
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2022 Woodpecker Authors
|
// Copyright 2024 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.
|
||||||
|
@ -12,16 +12,19 @@
|
||||||
// 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 org
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"src.techknowlogick.com/xormigrate"
|
"github.com/urfave/cli/v3"
|
||||||
"xorm.io/xorm"
|
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/org/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
var removeActiveFromUsers = xormigrate.Migration{
|
// Command exports the org command set.
|
||||||
ID: "remove-active-from-users",
|
var Command = &cli.Command{
|
||||||
MigrateSession: func(sess *xorm.Session) error {
|
Name: "org",
|
||||||
return dropTableColumns(sess, "users", "user_active")
|
Usage: "manage organizations",
|
||||||
|
Commands: []*cli.Command{
|
||||||
|
registry.Command,
|
||||||
},
|
},
|
||||||
}
|
}
|
60
cli/org/registry/registry.go
Normal file
60
cli/org/registry/registry.go
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
// Copyright 2024 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package registry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Command exports the registry command set.
|
||||||
|
var Command = &cli.Command{
|
||||||
|
Name: "registry",
|
||||||
|
Usage: "manage organization registries",
|
||||||
|
Commands: []*cli.Command{
|
||||||
|
registryCreateCmd,
|
||||||
|
registryDeleteCmd,
|
||||||
|
registryUpdateCmd,
|
||||||
|
registryInfoCmd,
|
||||||
|
registryListCmd,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseTargetArgs(client woodpecker.Client, c *cli.Command) (orgID int64, err error) {
|
||||||
|
orgIDOrName := c.String("organization")
|
||||||
|
if orgIDOrName == "" {
|
||||||
|
orgIDOrName = c.Args().First()
|
||||||
|
}
|
||||||
|
|
||||||
|
if orgIDOrName == "" {
|
||||||
|
if err := cli.ShowSubcommandHelp(c); err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if orgID, err := strconv.ParseInt(orgIDOrName, 10, 64); err == nil {
|
||||||
|
return orgID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
org, err := client.OrgLookup(orgIDOrName)
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return org.ID, nil
|
||||||
|
}
|
84
cli/org/registry/registry_add.go
Normal file
84
cli/org/registry/registry_add.go
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
// Copyright 2024 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package registry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||||
|
)
|
||||||
|
|
||||||
|
var registryCreateCmd = &cli.Command{
|
||||||
|
Name: "add",
|
||||||
|
Usage: "adds a registry",
|
||||||
|
ArgsUsage: "[org-id|org-full-name]",
|
||||||
|
Action: registryCreate,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
common.OrgFlag,
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "hostname",
|
||||||
|
Usage: "registry hostname",
|
||||||
|
Value: "docker.io",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "username",
|
||||||
|
Usage: "registry username",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "password",
|
||||||
|
Usage: "registry password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func registryCreate(ctx context.Context, c *cli.Command) error {
|
||||||
|
var (
|
||||||
|
hostname = c.String("hostname")
|
||||||
|
username = c.String("username")
|
||||||
|
password = c.String("password")
|
||||||
|
)
|
||||||
|
|
||||||
|
client, err := internal.NewClient(ctx, c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
registry := &woodpecker.Registry{
|
||||||
|
Address: hostname,
|
||||||
|
Username: username,
|
||||||
|
Password: password,
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(registry.Password, "@") {
|
||||||
|
path := strings.TrimPrefix(registry.Password, "@")
|
||||||
|
out, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
registry.Password = string(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
orgID, err := parseTargetArgs(client, c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = client.OrgRegistryCreate(orgID, registry)
|
||||||
|
return err
|
||||||
|
}
|
70
cli/org/registry/registry_info.go
Normal file
70
cli/org/registry/registry_info.go
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
// Copyright 2024 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package registry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"html/template"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
var registryInfoCmd = &cli.Command{
|
||||||
|
Name: "info",
|
||||||
|
Usage: "display registry info",
|
||||||
|
ArgsUsage: "[org-id|org-full-name]",
|
||||||
|
Action: registryInfo,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
common.OrgFlag,
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "hostname",
|
||||||
|
Usage: "registry hostname",
|
||||||
|
Value: "docker.io",
|
||||||
|
},
|
||||||
|
common.FormatFlag(tmplRegistryList, true),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func registryInfo(ctx context.Context, c *cli.Command) error {
|
||||||
|
var (
|
||||||
|
hostname = c.String("hostname")
|
||||||
|
format = c.String("format") + "\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
client, err := internal.NewClient(ctx, c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
orgID, err := parseTargetArgs(client, c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
registry, err := client.OrgRegistry(orgID, hostname)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl, err := template.New("_").Parse(format)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return tmpl.Execute(os.Stdout, registry)
|
||||||
|
}
|
73
cli/org/registry/registry_list.go
Normal file
73
cli/org/registry/registry_list.go
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
// Copyright 2024 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package registry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"html/template"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
var registryListCmd = &cli.Command{
|
||||||
|
Name: "ls",
|
||||||
|
Usage: "list registries",
|
||||||
|
ArgsUsage: "[org-id|org-full-name]",
|
||||||
|
Action: registryList,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
common.OrgFlag,
|
||||||
|
common.FormatFlag(tmplRegistryList, true),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func registryList(ctx context.Context, c *cli.Command) error {
|
||||||
|
format := c.String("format") + "\n"
|
||||||
|
|
||||||
|
client, err := internal.NewClient(ctx, c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
orgID, err := parseTargetArgs(client, c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
list, err := client.OrgRegistryList(orgID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl, err := template.New("_").Parse(format)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, registry := range list {
|
||||||
|
if err := tmpl.Execute(os.Stdout, registry); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Template for registry list information.
|
||||||
|
var tmplRegistryList = "\x1b[33m{{ .Address }} \x1b[0m" + `
|
||||||
|
Username: {{ .Username }}
|
||||||
|
Email: {{ .Email }}
|
||||||
|
`
|
55
cli/org/registry/registry_rm.go
Normal file
55
cli/org/registry/registry_rm.go
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
// Copyright 2024 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package registry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
var registryDeleteCmd = &cli.Command{
|
||||||
|
Name: "rm",
|
||||||
|
Usage: "remove a registry",
|
||||||
|
ArgsUsage: "[org-id|org-full-name]",
|
||||||
|
Action: registryDelete,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
common.OrgFlag,
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "hostname",
|
||||||
|
Usage: "registry hostname",
|
||||||
|
Value: "docker.io",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func registryDelete(ctx context.Context, c *cli.Command) error {
|
||||||
|
hostname := c.String("hostname")
|
||||||
|
|
||||||
|
client, err := internal.NewClient(ctx, c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
orgID, err := parseTargetArgs(client, c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.OrgRegistryDelete(orgID, hostname)
|
||||||
|
}
|
85
cli/org/registry/registry_set.go
Normal file
85
cli/org/registry/registry_set.go
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
// Copyright 2024 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package registry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||||
|
)
|
||||||
|
|
||||||
|
var registryUpdateCmd = &cli.Command{
|
||||||
|
Name: "update",
|
||||||
|
Usage: "update a registry",
|
||||||
|
ArgsUsage: "[org-id|org-full-name]",
|
||||||
|
Action: registryUpdate,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
common.OrgFlag,
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "hostname",
|
||||||
|
Usage: "registry hostname",
|
||||||
|
Value: "docker.io",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "username",
|
||||||
|
Usage: "registry username",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "password",
|
||||||
|
Usage: "registry password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func registryUpdate(ctx context.Context, c *cli.Command) error {
|
||||||
|
var (
|
||||||
|
hostname = c.String("hostname")
|
||||||
|
username = c.String("username")
|
||||||
|
password = c.String("password")
|
||||||
|
)
|
||||||
|
|
||||||
|
client, err := internal.NewClient(ctx, c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
registry := &woodpecker.Registry{
|
||||||
|
Address: hostname,
|
||||||
|
Username: username,
|
||||||
|
Password: password,
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(registry.Password, "@") {
|
||||||
|
path := strings.TrimPrefix(registry.Password, "@")
|
||||||
|
out, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
registry.Password = string(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
orgID, err := parseTargetArgs(client, c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = client.OrgRegistryUpdate(orgID, registry)
|
||||||
|
return err
|
||||||
|
}
|
|
@ -15,10 +15,11 @@
|
||||||
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/v2/cli/internal"
|
||||||
)
|
)
|
||||||
|
@ -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,9 +15,10 @@
|
||||||
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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -42,9 +43,9 @@ var pipelineCreateCmd = &cli.Command{
|
||||||
}...),
|
}...),
|
||||||
}
|
}
|
||||||
|
|
||||||
func pipelineCreate(c *cli.Context) error {
|
func pipelineCreate(ctx context.Context, c *cli.Command) error {
|
||||||
repoIDOrFullName := c.Args().First()
|
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,10 +15,11 @@
|
||||||
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/v2/cli/internal"
|
||||||
)
|
)
|
||||||
|
@ -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,9 +15,10 @@
|
||||||
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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -32,9 +33,9 @@ var pipelineInfoCmd = &cli.Command{
|
||||||
Flags: common.OutputFlags("table"),
|
Flags: common.OutputFlags("table"),
|
||||||
}
|
}
|
||||||
|
|
||||||
func pipelineInfo(c *cli.Context) error {
|
func pipelineInfo(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
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,11 @@
|
||||||
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/v2/cli/internal"
|
||||||
)
|
)
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,9 @@
|
||||||
package pipeline
|
package pipeline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/urfave/cli/v2"
|
"context"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -36,9 +38,9 @@ var pipelineLastCmd = &cli.Command{
|
||||||
}...),
|
}...),
|
||||||
}
|
}
|
||||||
|
|
||||||
func pipelineLast(c *cli.Context) error {
|
func pipelineLast(ctx context.Context, c *cli.Command) error {
|
||||||
repoIDOrFullName := c.Args().First()
|
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,7 +15,9 @@
|
||||||
package pipeline
|
package pipeline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/urfave/cli/v2"
|
"context"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -49,19 +51,19 @@ var pipelineListCmd = &cli.Command{
|
||||||
}...),
|
}...),
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
resources, err := pipelineList(ctx, c, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return pipelineOutput(c, resources)
|
return pipelineOutput(c, resources)
|
||||||
}
|
}
|
||||||
|
|
||||||
func pipelineList(c *cli.Context, client woodpecker.Client) ([]woodpecker.Pipeline, error) {
|
func pipelineList(_ context.Context, c *cli.Command, client woodpecker.Client) ([]woodpecker.Pipeline, error) {
|
||||||
resources := make([]woodpecker.Pipeline, 0)
|
resources := make([]woodpecker.Pipeline, 0)
|
||||||
|
|
||||||
repoIDOrFullName := c.Args().First()
|
repoIDOrFullName := c.Args().First()
|
||||||
|
@ -78,7 +80,7 @@ func pipelineList(c *cli.Context, client woodpecker.Client) ([]woodpecker.Pipeli
|
||||||
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
|
var count int
|
||||||
for _, pipeline := range pipelines {
|
for _, pipeline := range pipelines {
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
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/v2/woodpecker-go/woodpecker"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker/mocks"
|
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker/mocks"
|
||||||
|
@ -109,12 +110,10 @@ func TestPipelineList(t *testing.T) {
|
||||||
mockClient.On("PipelineList", mock.Anything).Return(tt.pipelines, tt.pipelineErr)
|
mockClient.On("PipelineList", mock.Anything).Return(tt.pipelines, tt.pipelineErr)
|
||||||
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}
|
|
||||||
c := cli.NewContext(app, nil, nil)
|
|
||||||
|
|
||||||
command := pipelineListCmd
|
command := pipelineListCmd
|
||||||
command.Action = func(c *cli.Context) error {
|
command.Writer = io.Discard
|
||||||
pipelines, err := pipelineList(c, mockClient)
|
command.Action = func(ctx context.Context, c *cli.Command) error {
|
||||||
|
pipelines, err := pipelineList(ctx, c, mockClient)
|
||||||
if tt.wantErr != nil {
|
if tt.wantErr != nil {
|
||||||
assert.EqualError(t, err, tt.wantErr.Error())
|
assert.EqualError(t, err, tt.wantErr.Error())
|
||||||
return nil
|
return nil
|
||||||
|
@ -126,7 +125,7 @@ func TestPipelineList(t *testing.T) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = command.Run(c, tt.args...)
|
_ = command.Run(context.Background(), tt.args)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,52 +15,98 @@
|
||||||
package pipeline
|
package pipeline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||||
)
|
)
|
||||||
|
|
||||||
var pipelineLogsCmd = &cli.Command{
|
var pipelineLogsCmd = &cli.Command{
|
||||||
Name: "logs",
|
Name: "logs",
|
||||||
Usage: "show pipeline logs",
|
Usage: "show pipeline logs",
|
||||||
ArgsUsage: "<repo-id|repo-full-name> [pipeline] [stepID]",
|
ArgsUsage: "<repo-id|repo-full-name> <pipeline> [step-number|step-name]",
|
||||||
Action: pipelineLogs,
|
Action: pipelineLogs,
|
||||||
}
|
}
|
||||||
|
|
||||||
func pipelineLogs(c *cli.Context) error {
|
func pipelineLogs(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
|
||||||
}
|
}
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
numberArgIndex := 1
|
pipelineArg := c.Args().Get(1)
|
||||||
number, err := strconv.ParseInt(c.Args().Get(numberArgIndex), 10, 64)
|
if len(pipelineArg) == 0 {
|
||||||
|
return fmt.Errorf("missing required argument pipeline")
|
||||||
|
}
|
||||||
|
number, err := strconv.ParseInt(pipelineArg, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid pipeline '%s': %w", pipelineArg, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stepArg := c.Args().Get(2) //nolint:mnd
|
||||||
|
if len(stepArg) == 0 {
|
||||||
|
return showPipelineLog(client, repoID, number)
|
||||||
|
}
|
||||||
|
|
||||||
|
step, err := internal.ParseStep(client, repoID, number, stepArg)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid step '%s': %w", stepArg, err)
|
||||||
|
}
|
||||||
|
return showStepLog(client, repoID, number, step)
|
||||||
|
}
|
||||||
|
|
||||||
|
func showPipelineLog(client woodpecker.Client, repoID, number int64) error {
|
||||||
|
pipeline, err := client.Pipeline(repoID, number)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
stepArgIndex := 2
|
tmpl, err := template.New("_").Parse(tmplPipelineLogs + "\n")
|
||||||
step, err := strconv.ParseInt(c.Args().Get(stepArgIndex), 10, 64)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, workflow := range pipeline.Workflows {
|
||||||
|
for _, step := range workflow.Children {
|
||||||
|
if err := tmpl.Execute(os.Stdout, map[string]any{"workflow": workflow, "step": step}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err := showStepLog(client, repoID, number, step.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func showStepLog(client woodpecker.Client, repoID, number, step int64) error {
|
||||||
logs, err := client.StepLogEntries(repoID, number, step)
|
logs, err := client.StepLogEntries(repoID, number, step)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, log := range logs {
|
for _, log := range logs {
|
||||||
fmt.Print(string(log.Data))
|
fmt.Println(string(log.Data))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// template for pipeline ps information.
|
||||||
|
var tmplPipelineLogs = "\x1b[33m{{ .workflow.Name }} > {{ .step.Name }} (#{{ .step.PID }}):\x1b[0m"
|
||||||
|
|
|
@ -20,7 +20,7 @@ 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/v2/cli/output"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||||
|
@ -30,7 +30,7 @@ import (
|
||||||
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,
|
pipelineListCmd,
|
||||||
pipelineLastCmd,
|
pipelineLastCmd,
|
||||||
pipelineLogsCmd,
|
pipelineLogsCmd,
|
||||||
|
@ -46,7 +46,7 @@ var Command = &cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func pipelineOutput(c *cli.Context, resources []woodpecker.Pipeline, fd ...io.Writer) error {
|
func pipelineOutput(c *cli.Command, resources []woodpecker.Pipeline, fd ...io.Writer) error {
|
||||||
outFmt, outOpt := output.ParseOutputOptions(c.String("output"))
|
outFmt, outOpt := output.ParseOutputOptions(c.String("output"))
|
||||||
noHeader := c.Bool("output-no-headers")
|
noHeader := c.Bool("output-no-headers")
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ func pipelineOutput(c *cli.Context, resources []woodpecker.Pipeline, fd ...io.Wr
|
||||||
fallthrough
|
fallthrough
|
||||||
default:
|
default:
|
||||||
table := output.NewTable(out)
|
table := output.NewTable(out)
|
||||||
cols := []string{"Number", "Status", "Event", "Branch", "Commit", "Author"}
|
cols := []string{"Number", "Status", "Event", "Branch", "Message", "Author"}
|
||||||
|
|
||||||
if len(outOpt) > 0 {
|
if len(outOpt) > 0 {
|
||||||
cols = outOpt
|
cols = outOpt
|
||||||
|
|
|
@ -2,11 +2,12 @@ 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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||||
|
@ -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 COMMIT AUTHOR\n1 success push main abcdef John Doe\n",
|
expected: "NUMBER STATUS EVENT BRANCH MESSAGE AUTHOR\n1 success push main message John Doe\n",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "table output with custom columns",
|
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 abcdef John Doe\n",
|
expected: "1 success push main message John Doe\n",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "go-template output",
|
name: "go-template output",
|
||||||
|
@ -52,20 +53,18 @@ func TestPipelineOutput(t *testing.T) {
|
||||||
Status: "success",
|
Status: "success",
|
||||||
Event: "push",
|
Event: "push",
|
||||||
Branch: "main",
|
Branch: "main",
|
||||||
Commit: "abcdef",
|
Message: "message",
|
||||||
Author: "John Doe",
|
Author: "John Doe",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
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",
|
||||||
command := &cli.Command{}
|
Flags: common.OutputFlags("table"),
|
||||||
command.Name = "output"
|
Action: func(_ context.Context, c *cli.Command) error {
|
||||||
command.Flags = common.OutputFlags("table")
|
|
||||||
command.Action = func(c *cli.Context) error {
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
err := pipelineOutput(c, pipelines, &buf)
|
err := pipelineOutput(c, pipelines, &buf)
|
||||||
|
|
||||||
|
@ -78,9 +77,10 @@ func TestPipelineOutput(t *testing.T) {
|
||||||
assert.Equal(t, tt.expected, buf.String())
|
assert.Equal(t, tt.expected, buf.String())
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = command.Run(c, tt.args...)
|
_ = command.Run(context.Background(), tt.args)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,13 @@
|
||||||
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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -28,20 +30,20 @@ import (
|
||||||
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)
|
||||||
|
@ -58,7 +60,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 +74,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 +85,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 }}
|
||||||
`
|
`
|
||||||
|
|
|
@ -15,11 +15,12 @@
|
||||||
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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -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,11 +15,12 @@
|
||||||
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/v2/cli/internal"
|
||||||
)
|
)
|
||||||
|
@ -38,9 +39,9 @@ var pipelineStartCmd = &cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func pipelineStart(c *cli.Context) (err error) {
|
func pipelineStart(ctx context.Context, c *cli.Command) (err error) {
|
||||||
repoIDOrFullName := c.Args().First()
|
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,10 +15,11 @@
|
||||||
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/v2/cli/internal"
|
||||||
)
|
)
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
44
cli/repo/registry/registry.go
Normal file
44
cli/repo/registry/registry.go
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
// Copyright 2023 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package registry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Command exports the registry command set.
|
||||||
|
var Command = &cli.Command{
|
||||||
|
Name: "registry",
|
||||||
|
Usage: "manage registries",
|
||||||
|
Commands: []*cli.Command{
|
||||||
|
registryCreateCmd,
|
||||||
|
registryDeleteCmd,
|
||||||
|
registryUpdateCmd,
|
||||||
|
registryInfoCmd,
|
||||||
|
registryListCmd,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseTargetArgs(client woodpecker.Client, c *cli.Command) (repoID int64, err error) {
|
||||||
|
repoIDOrFullName := c.String("repository")
|
||||||
|
if repoIDOrFullName == "" {
|
||||||
|
repoIDOrFullName = c.Args().First()
|
||||||
|
}
|
||||||
|
|
||||||
|
return internal.ParseRepo(client, repoIDOrFullName)
|
||||||
|
}
|
|
@ -15,10 +15,11 @@
|
||||||
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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -48,21 +49,14 @@ var registryCreateCmd = &cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func registryCreate(c *cli.Context) error {
|
func registryCreate(ctx context.Context, c *cli.Command) error {
|
||||||
var (
|
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")
|
||||||
repoIDOrFullName = c.String("repository")
|
|
||||||
)
|
)
|
||||||
if repoIDOrFullName == "" {
|
|
||||||
repoIDOrFullName = c.Args().First()
|
client, err := internal.NewClient(ctx, c)
|
||||||
}
|
|
||||||
client, err := internal.NewClient(c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -79,8 +73,12 @@ func registryCreate(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
registry.Password = string(out)
|
registry.Password = string(out)
|
||||||
}
|
}
|
||||||
if _, err := client.RegistryCreate(repoID, registry); err != nil {
|
|
||||||
|
repoID, err := parseTargetArgs(client, c)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
_, err = client.RegistryCreate(repoID, registry)
|
||||||
|
return err
|
||||||
}
|
}
|
|
@ -15,10 +15,11 @@
|
||||||
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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -40,27 +41,27 @@ var registryInfoCmd = &cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func registryInfo(c *cli.Context) error {
|
func registryInfo(ctx context.Context, c *cli.Command) error {
|
||||||
var (
|
var (
|
||||||
hostname = c.String("hostname")
|
hostname = c.String("hostname")
|
||||||
repoIDOrFullName = c.String("repository")
|
|
||||||
format = c.String("format") + "\n"
|
format = c.String("format") + "\n"
|
||||||
)
|
)
|
||||||
if repoIDOrFullName == "" {
|
|
||||||
repoIDOrFullName = c.Args().First()
|
client, err := internal.NewClient(ctx, c)
|
||||||
}
|
|
||||||
client, err := internal.NewClient(c)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
|
|
||||||
|
repoID, err := parseTargetArgs(client, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
registry, err := client.Registry(repoID, hostname)
|
registry, err := client.Registry(repoID, hostname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpl, err := template.New("_").Parse(format)
|
tmpl, err := template.New("_").Parse(format)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
|
@ -15,10 +15,11 @@
|
||||||
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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -35,26 +36,24 @@ var registryListCmd = &cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func registryList(c *cli.Context) error {
|
func registryList(ctx context.Context, c *cli.Command) error {
|
||||||
var (
|
format := c.String("format") + "\n"
|
||||||
format = c.String("format") + "\n"
|
|
||||||
repoIDOrFullName = c.String("repository")
|
client, err := internal.NewClient(ctx, c)
|
||||||
)
|
|
||||||
if repoIDOrFullName == "" {
|
|
||||||
repoIDOrFullName = c.Args().First()
|
|
||||||
}
|
|
||||||
client, err := internal.NewClient(c)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
|
|
||||||
|
repoID, err := parseTargetArgs(client, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
list, err := client.RegistryList(repoID)
|
list, err := client.RegistryList(repoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpl, err := template.New("_").Parse(format)
|
tmpl, err := template.New("_").Parse(format)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
|
@ -15,7 +15,9 @@
|
||||||
package registry
|
package registry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/urfave/cli/v2"
|
"context"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -36,21 +38,18 @@ var registryDeleteCmd = &cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func registryDelete(c *cli.Context) error {
|
func registryDelete(ctx context.Context, c *cli.Command) error {
|
||||||
var (
|
hostname := c.String("hostname")
|
||||||
hostname = c.String("hostname")
|
|
||||||
repoIDOrFullName = c.String("repository")
|
client, err := internal.NewClient(ctx, c)
|
||||||
)
|
|
||||||
if repoIDOrFullName == "" {
|
|
||||||
repoIDOrFullName = c.Args().First()
|
|
||||||
}
|
|
||||||
client, err := internal.NewClient(c)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
|
|
||||||
|
repoID, err := parseTargetArgs(client, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return client.RegistryDelete(repoID, hostname)
|
return client.RegistryDelete(repoID, hostname)
|
||||||
}
|
}
|
|
@ -15,10 +15,11 @@
|
||||||
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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -48,24 +49,18 @@ var registryUpdateCmd = &cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func registryUpdate(c *cli.Context) error {
|
func registryUpdate(ctx context.Context, c *cli.Command) error {
|
||||||
var (
|
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")
|
||||||
repoIDOrFullName = c.String("repository")
|
|
||||||
)
|
)
|
||||||
if repoIDOrFullName == "" {
|
|
||||||
repoIDOrFullName = c.Args().First()
|
client, err := internal.NewClient(ctx, c)
|
||||||
}
|
|
||||||
client, err := internal.NewClient(c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
registry := &woodpecker.Registry{
|
registry := &woodpecker.Registry{
|
||||||
Address: hostname,
|
Address: hostname,
|
||||||
Username: username,
|
Username: username,
|
||||||
|
@ -79,6 +74,12 @@ func registryUpdate(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
registry.Password = string(out)
|
registry.Password = string(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
repoID, err := parseTargetArgs(client, c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
_, err = client.RegistryUpdate(repoID, registry)
|
_, err = client.RegistryUpdate(repoID, registry)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
|
@ -15,14 +15,16 @@
|
||||||
package repo
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/cli/repo/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Command exports the repository command.
|
// Command exports the repository command.
|
||||||
var Command = &cli.Command{
|
var Command = &cli.Command{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Usage: "manage repositories",
|
Usage: "manage repositories",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
repoListCmd,
|
repoListCmd,
|
||||||
repoInfoCmd,
|
repoInfoCmd,
|
||||||
repoAddCmd,
|
repoAddCmd,
|
||||||
|
@ -31,5 +33,6 @@ var Command = &cli.Command{
|
||||||
repoRepairCmd,
|
repoRepairCmd,
|
||||||
repoChownCmd,
|
repoChownCmd,
|
||||||
repoSyncCmd,
|
repoSyncCmd,
|
||||||
|
registry.Command,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,11 @@
|
||||||
package repo
|
package repo
|
||||||
|
|
||||||
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/v2/cli/internal"
|
||||||
)
|
)
|
||||||
|
@ -30,14 +31,14 @@ var repoAddCmd = &cli.Command{
|
||||||
Action: repoAdd,
|
Action: repoAdd,
|
||||||
}
|
}
|
||||||
|
|
||||||
func repoAdd(c *cli.Context) error {
|
func repoAdd(ctx context.Context, c *cli.Command) error {
|
||||||
_forgeRemoteID := c.Args().First()
|
_forgeRemoteID := c.Args().First()
|
||||||
forgeRemoteID, err := strconv.Atoi(_forgeRemoteID)
|
forgeRemoteID, err := strconv.Atoi(_forgeRemoteID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid forge remote id: %s", _forgeRemoteID)
|
return fmt.Errorf("invalid forge remote id: %s", _forgeRemoteID)
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,10 @@
|
||||||
package repo
|
package repo
|
||||||
|
|
||||||
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/v2/cli/internal"
|
||||||
)
|
)
|
||||||
|
@ -29,9 +30,9 @@ var repoChownCmd = &cli.Command{
|
||||||
Action: repoChown,
|
Action: repoChown,
|
||||||
}
|
}
|
||||||
|
|
||||||
func repoChown(c *cli.Context) error {
|
func repoChown(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
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,11 @@
|
||||||
package repo
|
package repo
|
||||||
|
|
||||||
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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -32,9 +33,9 @@ var repoInfoCmd = &cli.Command{
|
||||||
Flags: []cli.Flag{common.FormatFlag(tmplRepoInfo)},
|
Flags: []cli.Flag{common.FormatFlag(tmplRepoInfo)},
|
||||||
}
|
}
|
||||||
|
|
||||||
func repoInfo(c *cli.Context) error {
|
func repoInfo(ctx context.Context, c *cli.Command) error {
|
||||||
repoIDOrFullName := c.Args().First()
|
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,10 +15,11 @@
|
||||||
package repo
|
package repo
|
||||||
|
|
||||||
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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -38,8 +39,8 @@ var repoListCmd = &cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func repoList(c *cli.Context) error {
|
func repoList(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,9 +15,10 @@
|
||||||
package repo
|
package repo
|
||||||
|
|
||||||
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/v2/cli/internal"
|
||||||
)
|
)
|
||||||
|
@ -29,9 +30,9 @@ var repoRepairCmd = &cli.Command{
|
||||||
Action: repoRepair,
|
Action: repoRepair,
|
||||||
}
|
}
|
||||||
|
|
||||||
func repoRepair(c *cli.Context) error {
|
func repoRepair(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
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,10 @@
|
||||||
package repo
|
package repo
|
||||||
|
|
||||||
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/v2/cli/internal"
|
||||||
)
|
)
|
||||||
|
@ -29,9 +30,9 @@ var repoRemoveCmd = &cli.Command{
|
||||||
Action: repoRemove,
|
Action: repoRemove,
|
||||||
}
|
}
|
||||||
|
|
||||||
func repoRemove(c *cli.Context) error {
|
func repoRemove(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
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,11 @@
|
||||||
package repo
|
package repo
|
||||||
|
|
||||||
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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -33,8 +34,8 @@ var repoSyncCmd = &cli.Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove this and add an option to the list cmd as we do not store the remote repo list anymore
|
// TODO: remove this and add an option to the list cmd as we do not store the remote repo list anymore
|
||||||
func repoSync(c *cli.Context) error {
|
func repoSync(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,10 +15,11 @@
|
||||||
package repo
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||||
|
@ -61,9 +62,9 @@ var repoUpdateCmd = &cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func repoUpdate(c *cli.Context) error {
|
func repoUpdate(ctx context.Context, c *cli.Command) error {
|
||||||
repoIDOrFullName := c.Args().First()
|
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
|
||||||
}
|
}
|
||||||
|
@ -78,7 +79,7 @@ func repoUpdate(c *cli.Context) error {
|
||||||
timeout = c.Duration("timeout")
|
timeout = c.Duration("timeout")
|
||||||
trusted = c.Bool("trusted")
|
trusted = c.Bool("trusted")
|
||||||
gated = c.Bool("gated")
|
gated = c.Bool("gated")
|
||||||
pipelineCounter = c.Int("pipeline-counter")
|
pipelineCounter = int(c.Int("pipeline-counter"))
|
||||||
unsafe = c.Bool("unsafe")
|
unsafe = c.Bool("unsafe")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"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/v2/cli/internal"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||||
|
@ -29,7 +29,7 @@ import (
|
||||||
var Command = &cli.Command{
|
var Command = &cli.Command{
|
||||||
Name: "secret",
|
Name: "secret",
|
||||||
Usage: "manage secrets",
|
Usage: "manage secrets",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
secretCreateCmd,
|
secretCreateCmd,
|
||||||
secretDeleteCmd,
|
secretDeleteCmd,
|
||||||
secretUpdateCmd,
|
secretUpdateCmd,
|
||||||
|
@ -38,7 +38,7 @@ var Command = &cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseTargetArgs(client woodpecker.Client, c *cli.Context) (global bool, orgID, repoID int64, err error) {
|
func parseTargetArgs(client woodpecker.Client, c *cli.Command) (global bool, orgID, repoID int64, err error) {
|
||||||
if c.Bool("global") {
|
if c.Bool("global") {
|
||||||
return true, -1, -1, nil
|
return true, -1, -1, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,11 @@
|
||||||
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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -56,8 +57,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
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,12 @@
|
||||||
package secret
|
package secret
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
"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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -45,12 +47,17 @@ var secretInfoCmd = &cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func secretInfo(c *cli.Context) error {
|
func secretInfo(ctx context.Context, c *cli.Command) error {
|
||||||
var (
|
var (
|
||||||
secretName = c.String("name")
|
secretName = c.String("name")
|
||||||
format = c.String("format") + "\n"
|
format = c.String("format") + "\n"
|
||||||
)
|
)
|
||||||
client, err := internal.NewClient(c)
|
|
||||||
|
if secretName == "" {
|
||||||
|
return fmt.Errorf("secret name is missing")
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,12 @@
|
||||||
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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -42,10 +43,10 @@ var secretListCmd = &cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func secretList(c *cli.Context) error {
|
func secretList(ctx context.Context, c *cli.Command) error {
|
||||||
format := c.String("format") + "\n"
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,9 @@
|
||||||
package secret
|
package secret
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/urfave/cli/v2"
|
"context"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -40,10 +42,10 @@ var secretDeleteCmd = &cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func secretDelete(c *cli.Context) error {
|
func secretDelete(ctx context.Context, c *cli.Command) error {
|
||||||
secretName := c.String("name")
|
secretName := c.String("name")
|
||||||
|
|
||||||
client, err := internal.NewClient(c)
|
client, err := internal.NewClient(ctx, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,11 @@
|
||||||
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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -56,8 +57,8 @@ var secretUpdateCmd = &cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func secretUpdate(c *cli.Context) error {
|
func secretUpdate(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,11 +1,12 @@
|
||||||
package setup
|
package setup
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"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/v2/cli/internal/config"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/setup/ui"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/setup/ui"
|
||||||
|
@ -15,7 +16,6 @@ import (
|
||||||
var Command = &cli.Command{
|
var Command = &cli.Command{
|
||||||
Name: "setup",
|
Name: "setup",
|
||||||
Usage: "setup the woodpecker-cli for the first time",
|
Usage: "setup the woodpecker-cli for the first time",
|
||||||
Args: true,
|
|
||||||
ArgsUsage: "[server]",
|
ArgsUsage: "[server]",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
|
@ -30,8 +30,8 @@ var Command = &cli.Command{
|
||||||
Action: setup,
|
Action: setup,
|
||||||
}
|
}
|
||||||
|
|
||||||
func setup(c *cli.Context) error {
|
func setup(ctx context.Context, c *cli.Command) error {
|
||||||
_config, err := config.Get(c, c.String("config"))
|
_config, err := config.Get(ctx, c, c.String("config"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
} else if _config != nil {
|
} else if _config != nil {
|
||||||
|
@ -68,7 +68,7 @@ func setup(c *cli.Context) error {
|
||||||
|
|
||||||
token := c.String("token")
|
token := c.String("token")
|
||||||
if token == "" {
|
if token == "" {
|
||||||
token, err = receiveTokenFromUI(c.Context, serverURL)
|
token, err = receiveTokenFromUI(ctx, serverURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ func setup(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = config.Save(c, c.String("config"), &config.Config{
|
err = config.Save(ctx, c, c.String("config"), &config.Config{
|
||||||
ServerURL: serverURL,
|
ServerURL: serverURL,
|
||||||
Token: token,
|
Token: token,
|
||||||
LogLevel: "info",
|
LogLevel: "info",
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
package update
|
package update
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Command exports the update command.
|
// Command exports the update command.
|
||||||
|
@ -22,10 +23,10 @@ var Command = &cli.Command{
|
||||||
Action: update,
|
Action: update,
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(c *cli.Context) error {
|
func update(ctx context.Context, c *cli.Command) error {
|
||||||
log.Info().Msg("Checking for updates ...")
|
log.Info().Msg("Checking for updates ...")
|
||||||
|
|
||||||
newVersion, err := CheckForUpdate(c.Context, c.Bool("force"))
|
newVersion, err := CheckForUpdate(ctx, c.Bool("force"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -38,7 +39,7 @@ func update(c *cli.Context) error {
|
||||||
log.Info().Msgf("New version %s is available! Updating ...", newVersion.Version)
|
log.Info().Msgf("New version %s is available! Updating ...", newVersion.Version)
|
||||||
|
|
||||||
var tarFilePath string
|
var tarFilePath string
|
||||||
tarFilePath, err = downloadNewVersion(c.Context, newVersion.AssetURL)
|
tarFilePath, err = downloadNewVersion(ctx, newVersion.AssetURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,14 +15,14 @@
|
||||||
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,
|
userListCmd,
|
||||||
userInfoCmd,
|
userInfoCmd,
|
||||||
userAddCmd,
|
userAddCmd,
|
||||||
|
|
|
@ -15,9 +15,10 @@
|
||||||
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/v2/cli/internal"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||||
|
@ -30,10 +31,10 @@ var userAddCmd = &cli.Command{
|
||||||
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,11 +15,12 @@
|
||||||
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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -33,8 +34,8 @@ var userInfoCmd = &cli.Command{
|
||||||
Flags: []cli.Flag{common.FormatFlag(tmplUserInfo)},
|
Flags: []cli.Flag{common.FormatFlag(tmplUserInfo)},
|
||||||
}
|
}
|
||||||
|
|
||||||
func userInfo(c *cli.Context) error {
|
func userInfo(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,10 +15,11 @@
|
||||||
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/v2/cli/common"
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||||
|
@ -32,8 +33,8 @@ 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
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue