mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-01-20 22:28:35 +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",
|
||||
// code
|
||||
"go",
|
||||
"node",
|
||||
// package names
|
||||
"npm"
|
||||
"node"
|
||||
],
|
||||
"words": [
|
||||
"abool",
|
||||
"anbraten",
|
||||
"antfu",
|
||||
"apimachinery",
|
||||
"Archlinux",
|
||||
"autoincr",
|
||||
"autoscaler",
|
||||
"backporting",
|
||||
"backports",
|
||||
"binutils",
|
||||
"bitbucketdatacenter",
|
||||
"Boguslawski",
|
||||
"bradrydzewski",
|
||||
"BUILDPLATFORM",
|
||||
"buildx",
|
||||
"caddyfile",
|
||||
"ccmenu",
|
||||
"certmagic",
|
||||
"charmbracelet",
|
||||
"cicd",
|
||||
"ciphertext",
|
||||
"Cloudron",
|
||||
"Codeberg",
|
||||
"compatiblelicenses",
|
||||
"corepack",
|
||||
|
@ -38,6 +42,8 @@
|
|||
"Debugf",
|
||||
"desaturate",
|
||||
"devx",
|
||||
"dind",
|
||||
"Dockle",
|
||||
"doublestar",
|
||||
"envsubst",
|
||||
"errgroup",
|
||||
|
@ -46,64 +52,89 @@
|
|||
"excalidraw",
|
||||
"favicons",
|
||||
"Fediverse",
|
||||
"Feishu",
|
||||
"Fogas",
|
||||
"forbidigo",
|
||||
"Forgejo",
|
||||
"fsnotify",
|
||||
"Geeklab",
|
||||
"Georgiana",
|
||||
"gitea",
|
||||
"gitmodules",
|
||||
"GOARCH",
|
||||
"GOBIN",
|
||||
"gocritic",
|
||||
"GODEBUG",
|
||||
"godoc",
|
||||
"Gogs",
|
||||
"golangci",
|
||||
"gomod",
|
||||
"gonic",
|
||||
"GOPATH",
|
||||
"Gource",
|
||||
"handlebargh",
|
||||
"HEALTHCHECK",
|
||||
"healthz",
|
||||
"Hetzner",
|
||||
"HETZNERCLOUD",
|
||||
"homelab",
|
||||
"HTMLURL",
|
||||
"HTTPFS",
|
||||
"httpsig",
|
||||
"httpsign",
|
||||
"HTTPURL",
|
||||
"httputil",
|
||||
"ianvs",
|
||||
"iconify",
|
||||
"inetutils",
|
||||
"Infima",
|
||||
"Infof",
|
||||
"Informatyka",
|
||||
"intlify",
|
||||
"Ionescu",
|
||||
"Jetpack",
|
||||
"Kaniko",
|
||||
"Keyfunc",
|
||||
"kyvg",
|
||||
"LASTEXITCODE",
|
||||
"Laszlo",
|
||||
"laszlocph",
|
||||
"letsencrypt",
|
||||
"loadbalancer",
|
||||
"logfile",
|
||||
"loglevel",
|
||||
"LONGBLOB",
|
||||
"LONGTEXT",
|
||||
"lonix1",
|
||||
"mapstructure",
|
||||
"markdownlint",
|
||||
"mdbook",
|
||||
"memswap",
|
||||
"Metas",
|
||||
"mhmxs",
|
||||
"moby",
|
||||
"Msgf",
|
||||
"mstruebing",
|
||||
"multiarch",
|
||||
"multierr",
|
||||
"netdns",
|
||||
"Netrc",
|
||||
"Nextcloud",
|
||||
"nfpm",
|
||||
"nixos",
|
||||
"nixpkgs",
|
||||
"nocolor",
|
||||
"nolint",
|
||||
"norunningpipelines",
|
||||
"nosniff",
|
||||
"ntfy",
|
||||
"octocat",
|
||||
"opensource",
|
||||
"Pacman",
|
||||
"picus",
|
||||
"Pinia",
|
||||
"pkce",
|
||||
"pnpx",
|
||||
"Polyform",
|
||||
"posix",
|
||||
"ppid",
|
||||
"Println",
|
||||
|
@ -123,19 +154,26 @@
|
|||
"repology",
|
||||
"reslimit",
|
||||
"Reviewdog",
|
||||
"Rieter",
|
||||
"riscv",
|
||||
"rundll32",
|
||||
"Rydzewski",
|
||||
"seccomp",
|
||||
"secprofile",
|
||||
"securecookie",
|
||||
"selfhosted",
|
||||
"sess",
|
||||
"shellescape",
|
||||
"sigstore",
|
||||
"Sonatype",
|
||||
"SSHURL",
|
||||
"sslmode",
|
||||
"stepbuilder",
|
||||
"stretchr",
|
||||
"structs",
|
||||
"sublicensable",
|
||||
"swaggo",
|
||||
"syscalls",
|
||||
"TARGETARCH",
|
||||
"TARGETOS",
|
||||
"techknowlogick",
|
||||
|
@ -143,38 +181,49 @@
|
|||
"threadcreate",
|
||||
"tink",
|
||||
"tinycolor",
|
||||
"tmole",
|
||||
"tmpfs",
|
||||
"tmpl",
|
||||
"tolerations",
|
||||
"Traefik",
|
||||
"tseslint",
|
||||
"ttlcache",
|
||||
"TUNEIT",
|
||||
"Tunnelmole",
|
||||
"typecheck",
|
||||
"Typeflag",
|
||||
"unplugin",
|
||||
"Upsert",
|
||||
"urfave",
|
||||
"usecase",
|
||||
"varchar",
|
||||
"varz",
|
||||
"Vieter",
|
||||
"virtualisation",
|
||||
"visualisation",
|
||||
"vite",
|
||||
"vueuse",
|
||||
"waivable",
|
||||
"Warnf",
|
||||
"webhookd",
|
||||
"Weblate",
|
||||
"windi",
|
||||
"windicss",
|
||||
"woodpeckerci",
|
||||
"WORKDIR",
|
||||
"Wrapf",
|
||||
"x-enum-varnames",
|
||||
"xlink",
|
||||
"xlog",
|
||||
"xorm",
|
||||
"xormigrate",
|
||||
"xyaml",
|
||||
"yamls",
|
||||
"Yuno",
|
||||
"zerolog",
|
||||
"zerologger"
|
||||
],
|
||||
"ignorePaths": [
|
||||
"**/node_modules/**/*",
|
||||
"*.excalidraw",
|
||||
"*.svg",
|
||||
"*_test.go",
|
||||
|
@ -185,19 +234,26 @@
|
|||
".vscode/extensions.json",
|
||||
"CHANGELOG.md",
|
||||
"Makefile",
|
||||
"flake.lock",
|
||||
"flake.nix",
|
||||
"go.mod",
|
||||
"go.sum",
|
||||
"pipeline/rpc/proto/woodpecker.pb.go",
|
||||
"pnpm-lock.yaml",
|
||||
"**/*.pb.go",
|
||||
"server/store/datastore/migration/**/*",
|
||||
"web/components.d.ts",
|
||||
"web/src/assets/locales/**/*",
|
||||
"**/fixtures/**",
|
||||
"**/testdata/**",
|
||||
"docs/versioned_docs/",
|
||||
"package.json",
|
||||
"91-migrations.md",
|
||||
// generated
|
||||
"go.sum",
|
||||
"flake.lock",
|
||||
"pnpm-lock.yaml",
|
||||
"**/node_modules/**/*",
|
||||
"cmd/server/docs/docs.go",
|
||||
// TODO: remove the following
|
||||
"docs/"
|
||||
"docs/**/*.js",
|
||||
"docs/**/*.ts"
|
||||
],
|
||||
// Exclude imports, because they are also strings.
|
||||
"ignoreRegExpList": [
|
||||
|
@ -210,7 +266,9 @@
|
|||
// ignore nolint directive
|
||||
"//\\s*nolint:.*",
|
||||
// ignore docker image names
|
||||
"\\s*docker\\.io/.*"
|
||||
"\\s*docker\\.io/.*",
|
||||
// ignore inline svg in css
|
||||
"\\s*url\\(\"data:image/svg\\+xml.*"
|
||||
],
|
||||
"enableFiletypes": ["dockercompose"]
|
||||
}
|
||||
|
|
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",
|
||||
"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": [
|
||||
{
|
||||
"matchCurrentVersion": "<1.0.0",
|
||||
|
|
|
@ -184,3 +184,5 @@ issues:
|
|||
|
||||
run:
|
||||
timeout: 15m
|
||||
build-tags:
|
||||
- test
|
||||
|
|
|
@ -24,11 +24,11 @@ repos:
|
|||
- id: checkmake
|
||||
exclude: '^docker/Dockerfile.make$' # actually a Dockerfile and not a makefile
|
||||
- repo: https://github.com/hadolint/hadolint
|
||||
rev: v2.12.0
|
||||
rev: v2.13.0-beta
|
||||
hooks:
|
||||
- id: hadolint
|
||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||
rev: v3.1.0
|
||||
rev: v4.0.0-alpha.8
|
||||
hooks:
|
||||
- id: prettier
|
||||
- repo: https://github.com/adrienverge/yamllint.git
|
||||
|
|
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
|
@ -8,11 +8,9 @@
|
|||
},
|
||||
"go.lintTool": "golangci-lint",
|
||||
"go.lintFlags": ["--fast"],
|
||||
"go.buildTags": "test",
|
||||
"eslint.workingDirectories": ["./web"],
|
||||
"prettier.ignorePath": "./web/.prettierignore",
|
||||
// Enable the ESlint flat config support
|
||||
// (remove this if your ESLint extension above v3.0.5)
|
||||
"eslint.experimental.useFlatConfig": true,
|
||||
// Auto fix
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit",
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
when:
|
||||
event: tag
|
||||
- event: tag
|
||||
- event: pull_request
|
||||
branch: ${CI_REPO_DEFAULT_BRANCH}
|
||||
path: Makefile
|
||||
|
||||
variables:
|
||||
- &golang_image 'docker.io/golang:1.22'
|
||||
- &golang_image 'docker.io/golang:1.23'
|
||||
- &node_image 'docker.io/node:22-alpine'
|
||||
- &xgo_image 'docker.io/techknowlogick/xgo:go-1.22.x'
|
||||
|
||||
# cspell:words bindata netgo TARGZ
|
||||
# cspell:words bindata netgo
|
||||
|
||||
steps:
|
||||
build-web:
|
||||
|
@ -35,7 +38,7 @@ steps:
|
|||
environment:
|
||||
PLATFORMS: linux|arm64/v8;linux|amd64;windows|amd64
|
||||
TAGS: bindata sqlite sqlite_unlock_notify netgo
|
||||
TARGZ: '1'
|
||||
ARCHIVE_IT: '1'
|
||||
|
||||
build-tarball:
|
||||
depends_on:
|
||||
|
@ -50,6 +53,8 @@ steps:
|
|||
- vendor
|
||||
image: *golang_image
|
||||
commands:
|
||||
- apt update
|
||||
- apt install -y zip
|
||||
- make release-agent
|
||||
|
||||
build-cli:
|
||||
|
@ -57,6 +62,8 @@ steps:
|
|||
- vendor
|
||||
image: *golang_image
|
||||
commands:
|
||||
- apt update
|
||||
- apt install -y zip
|
||||
- make release-cli
|
||||
|
||||
build-deb-rpm:
|
||||
|
@ -96,7 +103,10 @@ steps:
|
|||
from_secret: github_token
|
||||
files:
|
||||
- dist/*.tar.gz
|
||||
- dist/*.zip
|
||||
- dist/*.deb
|
||||
- dist/*.rpm
|
||||
- dist/checksums.txt
|
||||
title: ${CI_COMMIT_TAG##v}
|
||||
when:
|
||||
event: tag
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
variables:
|
||||
- &golang_image 'docker.io/golang:1.22'
|
||||
- &golang_image 'docker.io/golang:1.23'
|
||||
- &node_image 'docker.io/node:22-alpine'
|
||||
- &xgo_image 'docker.io/techknowlogick/xgo:go-1.22.x'
|
||||
- &buildx_plugin 'docker.io/woodpeckerci/plugin-docker-buildx:4.0.0'
|
||||
- &buildx_plugin 'docker.io/woodpeckerci/plugin-docker-buildx:4.2.0'
|
||||
- &platforms_release 'linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/386,linux/amd64,linux/ppc64le,linux/riscv64,linux/s390x,freebsd/arm64,freebsd/amd64,openbsd/arm64,openbsd/amd64'
|
||||
- &platforms_server 'linux/arm/v7,linux/arm64/v8,linux/amd64,linux/ppc64le,linux/riscv64'
|
||||
- &platforms_preview 'linux/amd64'
|
||||
- &platforms_alpine 'linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/amd64,linux/ppc64le'
|
||||
- &build_args 'CI_COMMIT_SHA=${CI_COMMIT_SHA},CI_COMMIT_BRANCH=${CI_COMMIT_BRANCH},CI_COMMIT_TAG=${CI_COMMIT_TAG}'
|
||||
|
||||
# cspell:words woodpeckerbot netgo TARGZ
|
||||
# cspell:words woodpeckerbot netgo
|
||||
|
||||
# vars used on push / tag events only
|
||||
- publish_logins: &publish_logins # Default DockerHub login
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
steps:
|
||||
release-helper:
|
||||
image: woodpeckerci/plugin-ready-release-go:1.1.2
|
||||
image: woodpeckerci/plugin-ready-release-go:1.2.0
|
||||
pull: true
|
||||
settings:
|
||||
release_branch: ${CI_REPO_DEFAULT_BRANCH}
|
||||
|
|
|
@ -5,7 +5,7 @@ when:
|
|||
|
||||
steps:
|
||||
- name: lint-editorconfig
|
||||
image: docker.io/mstruebing/editorconfig-checker:v3.0.1
|
||||
image: docker.io/mstruebing/editorconfig-checker:v3.0.3
|
||||
depends_on: []
|
||||
when:
|
||||
- event: pull_request
|
||||
|
@ -23,15 +23,15 @@ steps:
|
|||
- tree --gitignore -I 012_columns_rename_procs_to_steps.go -I versioned_docs -I '*opensource.svg'| pnpx cspell lint --no-progress stdin
|
||||
|
||||
- name: prettier
|
||||
image: docker.io/woodpeckerci/plugin-prettier:0.1.0
|
||||
image: docker.io/woodpeckerci/plugin-prettier:0.2.0
|
||||
depends_on: []
|
||||
settings:
|
||||
version: 3.2.5
|
||||
version: 3.3.3
|
||||
|
||||
- name: links
|
||||
image: docker.io/lycheeverse/lychee:0.15.1
|
||||
depends_on: []
|
||||
commands:
|
||||
- lychee pipeline/frontend/yaml/linter/schema/schema.json
|
||||
- lychee --exclude localhost docs/docs/
|
||||
- lychee --exclude localhost docs/src/pages/
|
||||
- lychee --user-agent "curl/8.4.0" --exclude localhost docs/docs/
|
||||
- lychee --user-agent "curl/8.4.0" --exclude localhost docs/src/pages/
|
||||
|
|
|
@ -40,6 +40,7 @@ steps:
|
|||
- go run go.woodpecker-ci.org/woodpecker/v2/cmd/cli lint
|
||||
environment:
|
||||
WOODPECKER_DISABLE_UPDATE_CHECK: true
|
||||
WOODPECKER_PLUGINS_PRIVILEGED: 'docker.io/woodpeckerci/plugin-docker-buildx:4.2.0'
|
||||
when:
|
||||
- event: pull_request
|
||||
path:
|
||||
|
|
|
@ -58,6 +58,7 @@ steps:
|
|||
test:
|
||||
depends_on:
|
||||
- install-dependencies
|
||||
- format-check # wait for it else test artifacts are falsely detected as wrong
|
||||
image: *node_image
|
||||
directory: web/
|
||||
commands:
|
||||
|
|
128
CHANGELOG.md
128
CHANGELOG.md
|
@ -1,5 +1,133 @@
|
|||
# Changelog
|
||||
|
||||
## [2.7.1](https://github.com/woodpecker-ci/woodpecker/releases/tag/v2.7.1) - 2024-09-07
|
||||
|
||||
### ❤️ Thanks to all contributors! ❤️
|
||||
|
||||
@6543, @anbraten, @j04n-f, @qwerty287
|
||||
|
||||
### 🔒 Security
|
||||
|
||||
- Lint privileged plugin match and allow to be set empty [[#4084](https://github.com/woodpecker-ci/woodpecker/pull/4084)]
|
||||
- Allow admins to specify privileged plugins by name **and tag** [[#4076](https://github.com/woodpecker-ci/woodpecker/pull/4076)]
|
||||
- Warn if using secrets/env with plugin [[#4039](https://github.com/woodpecker-ci/woodpecker/pull/4039)]
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- Set refspec for gitlab MR [[#4021](https://github.com/woodpecker-ci/woodpecker/pull/4021)]
|
||||
- Change Bitbucket PR hook to point the source branch, commit & ref [[#3965](https://github.com/woodpecker-ci/woodpecker/pull/3965)]
|
||||
- Add updated, merged and declined events to bb webhook activation [[#3963](https://github.com/woodpecker-ci/woodpecker/pull/3963)]
|
||||
- Fix login via navbar [[#3962](https://github.com/woodpecker-ci/woodpecker/pull/3962)]
|
||||
- Fix panic if forge is unreachable [[#3944](https://github.com/woodpecker-ci/woodpecker/pull/3944)]
|
||||
- Fix org settings page [[#4093](https://github.com/woodpecker-ci/woodpecker/pull/4093)]
|
||||
|
||||
### Misc
|
||||
|
||||
- Bump github.com/docker/docker from v24.0.9 to v24.0.9+30 [[#4077](https://github.com/woodpecker-ci/woodpecker/pull/4077)]
|
||||
|
||||
## [2.7.0](https://github.com/woodpecker-ci/woodpecker/releases/tag/v2.7.0) - 2024-07-18
|
||||
|
||||
### ❤️ Thanks to all contributors! ❤️
|
||||
|
||||
@6543, @anbraten, @dvjn, @hhamalai, @lafriks, @pat-s, @qwerty287, @smainz, @tongjicoder, @zc-devs
|
||||
|
||||
### 🔒 Security
|
||||
|
||||
- Add blocklist of environment variables who could alter execution of plugins [[#3934](https://github.com/woodpecker-ci/woodpecker/pull/3934)]
|
||||
- Make sure plugins only mount the workspace base in a predefinde location [[#3933](https://github.com/woodpecker-ci/woodpecker/pull/3933)]
|
||||
- Disallow to set arbitrary environments for plugins [[#3909](https://github.com/woodpecker-ci/woodpecker/pull/3909)]
|
||||
- Use proper oauth state [[#3847](https://github.com/woodpecker-ci/woodpecker/pull/3847)]
|
||||
- Enhance token checking [[#3842](https://github.com/woodpecker-ci/woodpecker/pull/3842)]
|
||||
- Bump github.com/hashicorp/go-retryablehttp v0.7.5 -> v0.7.7 [[#3834](https://github.com/woodpecker-ci/woodpecker/pull/3834)]
|
||||
|
||||
### ✨ Features
|
||||
|
||||
- Gracefully shutdown server [[#3896](https://github.com/woodpecker-ci/woodpecker/pull/3896)]
|
||||
- Gracefully shutdown agent [[#3895](https://github.com/woodpecker-ci/woodpecker/pull/3895)]
|
||||
- Convert urls in logs to links [[#3904](https://github.com/woodpecker-ci/woodpecker/pull/3904)]
|
||||
- Allow login using multiple forges [[#3822](https://github.com/woodpecker-ci/woodpecker/pull/3822)]
|
||||
- Global and organization registries [[#1672](https://github.com/woodpecker-ci/woodpecker/pull/1672)]
|
||||
- Cli get repo from git remote [[#3830](https://github.com/woodpecker-ci/woodpecker/pull/3830)]
|
||||
- Add api for forges [[#3733](https://github.com/woodpecker-ci/woodpecker/pull/3733)]
|
||||
|
||||
### 📈 Enhancement
|
||||
|
||||
- Cli fix pipeline logs [[#3913](https://github.com/woodpecker-ci/woodpecker/pull/3913)]
|
||||
- Migrate to github.com/urfave/cli/v3 [[#2951](https://github.com/woodpecker-ci/woodpecker/pull/2951)]
|
||||
- Allow to change the working directory also for plugins and services [[#3914](https://github.com/woodpecker-ci/woodpecker/pull/3914)]
|
||||
- Remove `unplugin-icons` [[#3809](https://github.com/woodpecker-ci/woodpecker/pull/3809)]
|
||||
- Release windows binaries as zip file [[#3906](https://github.com/woodpecker-ci/woodpecker/pull/3906)]
|
||||
- Convert to openapi 3.0 [[#3897](https://github.com/woodpecker-ci/woodpecker/pull/3897)]
|
||||
- Add user registries UI [[#3888](https://github.com/woodpecker-ci/woodpecker/pull/3888)]
|
||||
- Sort users by login [[#3891](https://github.com/woodpecker-ci/woodpecker/pull/3891)]
|
||||
- Exclude dummy backend in production [[#3877](https://github.com/woodpecker-ci/woodpecker/pull/3877)]
|
||||
- Fix deploy task env [[#3878](https://github.com/woodpecker-ci/woodpecker/pull/3878)]
|
||||
- Get default branch and show message in pipeline list [[#3867](https://github.com/woodpecker-ci/woodpecker/pull/3867)]
|
||||
- Add timestamp for last work done by agent [[#3844](https://github.com/woodpecker-ci/woodpecker/pull/3844)]
|
||||
- Adjust logger types [[#3859](https://github.com/woodpecker-ci/woodpecker/pull/3859)]
|
||||
- Cleanup state reporting [[#3850](https://github.com/woodpecker-ci/woodpecker/pull/3850)]
|
||||
- Unify DB tables/columns [[#3806](https://github.com/woodpecker-ci/woodpecker/pull/3806)]
|
||||
- Let webhook pass on pipeline parsing error [[#3829](https://github.com/woodpecker-ci/woodpecker/pull/3829)]
|
||||
- Exclude mocks from release build [[#3831](https://github.com/woodpecker-ci/woodpecker/pull/3831)]
|
||||
- K8s secrets reference from step [[#3655](https://github.com/woodpecker-ci/woodpecker/pull/3655)]
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- Handle empty repositories in gitea when listing PRs [[#3925](https://github.com/woodpecker-ci/woodpecker/pull/3925)]
|
||||
- Update alpine package dep for docker images [[#3917](https://github.com/woodpecker-ci/woodpecker/pull/3917)]
|
||||
- Don't report error if agent was terminated gracefully [[#3894](https://github.com/woodpecker-ci/woodpecker/pull/3894)]
|
||||
- Let agents continuously report their health [[#3893](https://github.com/woodpecker-ci/woodpecker/pull/3893)]
|
||||
- Ignore warnings for cli exec [[#3868](https://github.com/woodpecker-ci/woodpecker/pull/3868)]
|
||||
- Correct favicon states [[#3832](https://github.com/woodpecker-ci/woodpecker/pull/3832)]
|
||||
- Cleanup of the login flow and tests [[#3810](https://github.com/woodpecker-ci/woodpecker/pull/3810)]
|
||||
- Fix newlines in logs [[#3808](https://github.com/woodpecker-ci/woodpecker/pull/3808)]
|
||||
- Fix authentication error handling [[#3807](https://github.com/woodpecker-ci/woodpecker/pull/3807)]
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- Streamline docs for new users [[#3803](https://github.com/woodpecker-ci/woodpecker/pull/3803)]
|
||||
- Add mastodon verification [[#3843](https://github.com/woodpecker-ci/woodpecker/pull/3843)]
|
||||
- chore(deps): update docs npm deps non-major [[#3837](https://github.com/woodpecker-ci/woodpecker/pull/3837)]
|
||||
- fix(deps): update docs npm deps non-major [[#3824](https://github.com/woodpecker-ci/woodpecker/pull/3824)]
|
||||
- Add openSUSE package [[#3800](https://github.com/woodpecker-ci/woodpecker/pull/3800)]
|
||||
- chore(deps): update docs npm deps non-major [[#3798](https://github.com/woodpecker-ci/woodpecker/pull/3798)]
|
||||
- Add "Docker Tags" Plugin [[#3796](https://github.com/woodpecker-ci/woodpecker/pull/3796)]
|
||||
- chore(deps): update dependency marked to v13 [[#3792](https://github.com/woodpecker-ci/woodpecker/pull/3792)]
|
||||
- chore: fix some comments [[#3788](https://github.com/woodpecker-ci/woodpecker/pull/3788)]
|
||||
|
||||
### Misc
|
||||
|
||||
- chore(deps): update web npm deps non-major [[#3930](https://github.com/woodpecker-ci/woodpecker/pull/3930)]
|
||||
- chore(deps): update dependency vitest to v2 [[#3905](https://github.com/woodpecker-ci/woodpecker/pull/3905)]
|
||||
- fix(deps): update module github.com/google/go-github/v62 to v63 [[#3910](https://github.com/woodpecker-ci/woodpecker/pull/3910)]
|
||||
- chore(deps): update docker.io/woodpeckerci/plugin-docker-buildx docker tag to v4.1.0 [[#3908](https://github.com/woodpecker-ci/woodpecker/pull/3908)]
|
||||
- Update plugin-git and add renovate trigger [[#3901](https://github.com/woodpecker-ci/woodpecker/pull/3901)]
|
||||
- chore(deps): update docker.io/mstruebing/editorconfig-checker docker tag to v3.0.3 [[#3903](https://github.com/woodpecker-ci/woodpecker/pull/3903)]
|
||||
- fix(deps): update golang-packages [[#3875](https://github.com/woodpecker-ci/woodpecker/pull/3875)]
|
||||
- chore(deps): lock file maintenance [[#3876](https://github.com/woodpecker-ci/woodpecker/pull/3876)]
|
||||
- [pre-commit.ci] pre-commit autoupdate [[#3862](https://github.com/woodpecker-ci/woodpecker/pull/3862)]
|
||||
- Add dummy backend [[#3820](https://github.com/woodpecker-ci/woodpecker/pull/3820)]
|
||||
- chore(deps): update dependency replace-in-file to v8 [[#3852](https://github.com/woodpecker-ci/woodpecker/pull/3852)]
|
||||
- Update forgejo sdk [[#3840](https://github.com/woodpecker-ci/woodpecker/pull/3840)]
|
||||
- chore(deps): lock file maintenance [[#3838](https://github.com/woodpecker-ci/woodpecker/pull/3838)]
|
||||
- Allow to set dist dir using env var [[#3814](https://github.com/woodpecker-ci/woodpecker/pull/3814)]
|
||||
- chore(deps): lock file maintenance [[#3805](https://github.com/woodpecker-ci/woodpecker/pull/3805)]
|
||||
- chore(deps): update docker.io/lycheeverse/lychee docker tag to v0.15.1 [[#3797](https://github.com/woodpecker-ci/woodpecker/pull/3797)]
|
||||
|
||||
## [2.6.1](https://github.com/woodpecker-ci/woodpecker/releases/tag/v2.6.1) - 2024-07-19
|
||||
|
||||
### 🔒 Security
|
||||
|
||||
- Add blocklist of environment variables who could alter execution of plugins [[#3934](https://github.com/woodpecker-ci/woodpecker/pull/3934)]
|
||||
- Make sure plugins only mount the workspace base in a predefinde location [[#3933](https://github.com/woodpecker-ci/woodpecker/pull/3933)]
|
||||
- Disalow to set arbitrary environments for plugins [[#3909](https://github.com/woodpecker-ci/woodpecker/pull/3909)]
|
||||
- Bump trivy plugin version and remove unused variable [[#3833](https://github.com/woodpecker-ci/woodpecker/pull/3833)]
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- Let webhook pass on pipeline parsion error [[#3829](https://github.com/woodpecker-ci/woodpecker/pull/3829)]
|
||||
- Fix newlines in logs [[#3808](https://github.com/woodpecker-ci/woodpecker/pull/3808)]
|
||||
|
||||
## [2.6.0](https://github.com/woodpecker-ci/woodpecker/releases/tag/v2.6.0) - 2024-06-13
|
||||
|
||||
### ❤️ Thanks to all contributors! ❤️
|
||||
|
|
134
Makefile
134
Makefile
|
@ -8,6 +8,8 @@ ifeq ($(TARGETOS),windows)
|
|||
BIN_SUFFIX := .exe
|
||||
endif
|
||||
|
||||
DIST_DIR ?= dist
|
||||
|
||||
VERSION ?= next
|
||||
VERSION_NUMBER ?= 0.0.0
|
||||
CI_COMMIT_SHA ?= $(shell git rev-parse HEAD)
|
||||
|
@ -27,6 +29,7 @@ else
|
|||
endif
|
||||
endif
|
||||
|
||||
TAGS ?=
|
||||
LDFLAGS := -X go.woodpecker-ci.org/woodpecker/v2/version.Version=${VERSION}
|
||||
STATIC_BUILD ?= true
|
||||
ifeq ($(STATIC_BUILD),true)
|
||||
|
@ -103,7 +106,7 @@ clean: ## Clean build artifacts
|
|||
|
||||
.PHONY: clean-all
|
||||
clean-all: clean ## Clean all artifacts
|
||||
rm -rf dist web/dist docs/build docs/node_modules web/node_modules
|
||||
rm -rf ${DIST_DIR} web/dist docs/build docs/node_modules web/node_modules
|
||||
# delete generated
|
||||
rm -rf docs/docs/40-cli.md docs/swagger.json
|
||||
|
||||
|
@ -160,20 +163,20 @@ lint-ui: ui-dependencies ## Lint UI code
|
|||
(cd web/; pnpm lint --quiet)
|
||||
|
||||
test-agent: ## Test agent code
|
||||
go test -race -cover -coverprofile agent-coverage.out -timeout 30s go.woodpecker-ci.org/woodpecker/v2/cmd/agent go.woodpecker-ci.org/woodpecker/v2/agent/...
|
||||
go test -race -cover -coverprofile agent-coverage.out -timeout 60s -tags 'test $(TAGS)' go.woodpecker-ci.org/woodpecker/v2/cmd/agent go.woodpecker-ci.org/woodpecker/v2/agent/...
|
||||
|
||||
test-server: ## Test server code
|
||||
go test -race -cover -coverprofile server-coverage.out -timeout 30s go.woodpecker-ci.org/woodpecker/v2/cmd/server $(shell go list go.woodpecker-ci.org/woodpecker/v2/server/... | grep -v '/store')
|
||||
go test -race -cover -coverprofile server-coverage.out -timeout 60s -tags 'test $(TAGS)' go.woodpecker-ci.org/woodpecker/v2/cmd/server $(shell go list go.woodpecker-ci.org/woodpecker/v2/server/... | grep -v '/store')
|
||||
|
||||
test-cli: ## Test cli code
|
||||
go test -race -cover -coverprofile cli-coverage.out -timeout 30s go.woodpecker-ci.org/woodpecker/v2/cmd/cli go.woodpecker-ci.org/woodpecker/v2/cli/...
|
||||
go test -race -cover -coverprofile cli-coverage.out -timeout 60s -tags 'test $(TAGS)' go.woodpecker-ci.org/woodpecker/v2/cmd/cli go.woodpecker-ci.org/woodpecker/v2/cli/...
|
||||
|
||||
test-server-datastore: ## Test server datastore
|
||||
go test -timeout 120s -run TestMigrate go.woodpecker-ci.org/woodpecker/v2/server/store/...
|
||||
go test -race -timeout 30s -skip TestMigrate go.woodpecker-ci.org/woodpecker/v2/server/store/...
|
||||
go test -timeout 300s -tags 'test $(TAGS)' -run TestMigrate go.woodpecker-ci.org/woodpecker/v2/server/store/...
|
||||
go test -race -timeout 100s -tags 'test $(TAGS)' -skip TestMigrate go.woodpecker-ci.org/woodpecker/v2/server/store/...
|
||||
|
||||
test-server-datastore-coverage: ## Test server datastore with coverage report
|
||||
go test -race -cover -coverprofile datastore-coverage.out -timeout 180s go.woodpecker-ci.org/woodpecker/v2/server/store/...
|
||||
go test -race -cover -coverprofile datastore-coverage.out -timeout 300s -tags 'test $(TAGS)' go.woodpecker-ci.org/woodpecker/v2/server/store/...
|
||||
|
||||
test-ui: ui-dependencies ## Test UI code
|
||||
(cd web/; pnpm run lint)
|
||||
|
@ -182,7 +185,7 @@ test-ui: ui-dependencies ## Test UI code
|
|||
(cd web/; pnpm run test)
|
||||
|
||||
test-lib: ## Test lib code
|
||||
go test -race -cover -coverprofile coverage.out -timeout 30s $(shell go list ./... | grep -v '/cmd\|/agent\|/cli\|/server')
|
||||
go test -race -cover -coverprofile coverage.out -timeout 60s -tags 'test $(TAGS)' $(shell go list ./... | grep -v '/cmd\|/agent\|/cli\|/server')
|
||||
|
||||
.PHONY: test
|
||||
test: test-agent test-server test-server-datastore test-cli test-lib ## Run all tests
|
||||
|
@ -193,16 +196,16 @@ build-ui: ## Build UI
|
|||
(cd web/; pnpm install --frozen-lockfile; pnpm build)
|
||||
|
||||
build-server: build-ui generate-swagger ## Build server
|
||||
CGO_ENABLED=${CGO_ENABLED} GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -ldflags '${LDFLAGS}' -o dist/woodpecker-server${BIN_SUFFIX} go.woodpecker-ci.org/woodpecker/v2/cmd/server
|
||||
CGO_ENABLED=${CGO_ENABLED} GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -tags '$(TAGS)' -ldflags '${LDFLAGS}' -o ${DIST_DIR}/woodpecker-server${BIN_SUFFIX} go.woodpecker-ci.org/woodpecker/v2/cmd/server
|
||||
|
||||
build-agent: ## Build agent
|
||||
CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -ldflags '${LDFLAGS}' -o dist/woodpecker-agent${BIN_SUFFIX} go.woodpecker-ci.org/woodpecker/v2/cmd/agent
|
||||
CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -tags '$(TAGS)' -ldflags '${LDFLAGS}' -o ${DIST_DIR}/woodpecker-agent${BIN_SUFFIX} go.woodpecker-ci.org/woodpecker/v2/cmd/agent
|
||||
|
||||
build-cli: ## Build cli
|
||||
CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -ldflags '${LDFLAGS}' -o dist/woodpecker-cli${BIN_SUFFIX} go.woodpecker-ci.org/woodpecker/v2/cmd/cli
|
||||
CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -tags '$(TAGS)' -ldflags '${LDFLAGS}' -o ${DIST_DIR}/woodpecker-cli${BIN_SUFFIX} go.woodpecker-ci.org/woodpecker/v2/cmd/cli
|
||||
|
||||
build-tarball: ## Build tar archive
|
||||
mkdir -p dist && tar chzvf dist/woodpecker-src.tar.gz \
|
||||
mkdir -p ${DIST_DIR} && tar chzvf ${DIST_DIR}/woodpecker-src.tar.gz \
|
||||
--exclude="*.exe" \
|
||||
--exclude="./.pnpm-store" \
|
||||
--exclude="node_modules" \
|
||||
|
@ -224,7 +227,7 @@ cross-compile-server: ## Cross compile the server
|
|||
TARGETARCH_BUILDX=$(subst arm64/v8,arm64,$(subst arm/v7,arm,$(word 2,$(subst |, ,$(platform))))) \
|
||||
make release-server-xgo || exit 1; \
|
||||
)
|
||||
tree dist
|
||||
tree ${DIST_DIR}
|
||||
|
||||
release-server-xgo: check-xgo ## Create server binaries for release using xgo
|
||||
@echo "Building for:"
|
||||
|
@ -232,58 +235,79 @@ release-server-xgo: check-xgo ## Create server binaries for release using xgo
|
|||
@echo "arch orgi:$(TARGETARCH)"
|
||||
@echo "arch (xgo):$(TARGETARCH_XGO)"
|
||||
@echo "arch (buildx):$(TARGETARCH_BUILDX)"
|
||||
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -dest ./dist/server/$(TARGETOS)_$(TARGETARCH_BUILDX) -tags 'netgo osusergo grpcnotrace $(TAGS)' -ldflags '-linkmode external $(LDFLAGS)' -targets '$(TARGETOS)/$(TARGETARCH_XGO)' -out woodpecker-server -pkg cmd/server .
|
||||
@if [ "$${XGO_IN_XGO:-0}" -eq "1" ]; then echo "inside xgo image"; \
|
||||
mkdir -p ./dist/server/$(TARGETOS)_$(TARGETARCH_BUILDX); \
|
||||
mv -vf /build/woodpecker-server* ./dist/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX); \
|
||||
else echo "outside xgo image"; \
|
||||
[ -f "./dist/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX)" ] && rm -v ./dist/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX); \
|
||||
mv -v ./dist/server/$(TARGETOS)_$(TARGETARCH_XGO)/woodpecker-server* ./dist/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX); \
|
||||
# build via xgo
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -dest ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX) -tags 'netgo osusergo grpcnotrace $(TAGS)' -ldflags '-linkmode external $(LDFLAGS)' -targets '$(TARGETOS)/$(TARGETARCH_XGO)' -out woodpecker-server -pkg cmd/server .
|
||||
# move binary into subfolder depending on target os and arch
|
||||
@if [ "$${XGO_IN_XGO:-0}" -eq "1" ]; then \
|
||||
echo "inside xgo image"; \
|
||||
mkdir -p ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX); \
|
||||
mv -vf /build/woodpecker-server* ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX); \
|
||||
else \
|
||||
echo "outside xgo image"; \
|
||||
[ -f "${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX)" ] && rm -v ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX); \
|
||||
mv -v ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_XGO)/woodpecker-server* ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server$(BIN_SUFFIX); \
|
||||
fi
|
||||
# if enabled package it in an archive
|
||||
@if [ "$${ARCHIVE_IT:-0}" -eq "1" ]; then \
|
||||
if [ "$(BIN_SUFFIX)" = ".exe" ]; then \
|
||||
rm -f ${DIST_DIR}/woodpecker-server_$(TARGETOS)_$(TARGETARCH_BUILDX).zip; \
|
||||
zip -j ${DIST_DIR}/woodpecker-server_$(TARGETOS)_$(TARGETARCH_BUILDX).zip ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX)/woodpecker-server.exe; \
|
||||
else \
|
||||
tar -cvzf ${DIST_DIR}/woodpecker-server_$(TARGETOS)_$(TARGETARCH_BUILDX).tar.gz -C ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH_BUILDX) woodpecker-server$(BIN_SUFFIX); \
|
||||
fi; \
|
||||
else \
|
||||
echo "skip creating '${DIST_DIR}/woodpecker-server_$(TARGETOS)_$(TARGETARCH_BUILDX).tar.gz'"; \
|
||||
fi
|
||||
@[ "$${TARGZ:-0}" -eq "1" ] && tar -cvzf dist/woodpecker-server_$(TARGETOS)_$(TARGETARCH_BUILDX).tar.gz -C dist/server/$(TARGETOS)_$(TARGETARCH_BUILDX) woodpecker-server$(BIN_SUFFIX) || echo "skip creating 'dist/woodpecker-server_$(TARGETOS)_$(TARGETARCH_BUILDX).tar.gz'"
|
||||
|
||||
release-server: ## Create server binaries for release
|
||||
# compile
|
||||
GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) CGO_ENABLED=${CGO_ENABLED} go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o dist/server/$(TARGETOS)_$(TARGETARCH)/woodpecker-server$(BIN_SUFFIX) go.woodpecker-ci.org/woodpecker/v2/cmd/server
|
||||
GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) CGO_ENABLED=${CGO_ENABLED} go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH)/woodpecker-server$(BIN_SUFFIX) go.woodpecker-ci.org/woodpecker/v2/cmd/server
|
||||
# tar binary files
|
||||
tar -cvzf dist/woodpecker-server_$(TARGETOS)_$(TARGETARCH).tar.gz -C dist/server/$(TARGETOS)_$(TARGETARCH) woodpecker-server$(BIN_SUFFIX)
|
||||
if [ "$(BIN_SUFFIX)" == ".exe" ]; then \
|
||||
zip -j ${DIST_DIR}/woodpecker-server_$(TARGETOS)_$(TARGETARCH).zip ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH)/woodpecker-server.exe; \
|
||||
else \
|
||||
tar -cvzf ${DIST_DIR}/woodpecker-server_$(TARGETOS)_$(TARGETARCH).tar.gz -C ${DIST_DIR}/server/$(TARGETOS)_$(TARGETARCH) woodpecker-server$(BIN_SUFFIX); \
|
||||
fi
|
||||
|
||||
release-agent: ## Create agent binaries for release
|
||||
# compile
|
||||
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o dist/agent/linux_amd64/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
|
||||
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o dist/agent/linux_arm64/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
|
||||
GOOS=linux GOARCH=arm CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o dist/agent/linux_arm/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
|
||||
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o dist/agent/windows_amd64/woodpecker-agent.exe go.woodpecker-ci.org/woodpecker/v2/cmd/agent
|
||||
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o dist/agent/darwin_amd64/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
|
||||
GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o dist/agent/darwin_arm64/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
|
||||
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o ${DIST_DIR}/agent/linux_amd64/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
|
||||
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o ${DIST_DIR}/agent/linux_arm64/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
|
||||
GOOS=linux GOARCH=arm CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o ${DIST_DIR}/agent/linux_arm/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
|
||||
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o ${DIST_DIR}/agent/windows_amd64/woodpecker-agent.exe go.woodpecker-ci.org/woodpecker/v2/cmd/agent
|
||||
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o ${DIST_DIR}/agent/darwin_amd64/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
|
||||
GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -tags 'grpcnotrace $(TAGS)' -o ${DIST_DIR}/agent/darwin_arm64/woodpecker-agent go.woodpecker-ci.org/woodpecker/v2/cmd/agent
|
||||
# tar binary files
|
||||
tar -cvzf dist/woodpecker-agent_linux_amd64.tar.gz -C dist/agent/linux_amd64 woodpecker-agent
|
||||
tar -cvzf dist/woodpecker-agent_linux_arm64.tar.gz -C dist/agent/linux_arm64 woodpecker-agent
|
||||
tar -cvzf dist/woodpecker-agent_linux_arm.tar.gz -C dist/agent/linux_arm woodpecker-agent
|
||||
tar -cvzf dist/woodpecker-agent_windows_amd64.tar.gz -C dist/agent/windows_amd64 woodpecker-agent.exe
|
||||
tar -cvzf dist/woodpecker-agent_darwin_amd64.tar.gz -C dist/agent/darwin_amd64 woodpecker-agent
|
||||
tar -cvzf dist/woodpecker-agent_darwin_arm64.tar.gz -C dist/agent/darwin_arm64 woodpecker-agent
|
||||
tar -cvzf ${DIST_DIR}/woodpecker-agent_linux_amd64.tar.gz -C ${DIST_DIR}/agent/linux_amd64 woodpecker-agent
|
||||
tar -cvzf ${DIST_DIR}/woodpecker-agent_linux_arm64.tar.gz -C ${DIST_DIR}/agent/linux_arm64 woodpecker-agent
|
||||
tar -cvzf ${DIST_DIR}/woodpecker-agent_linux_arm.tar.gz -C ${DIST_DIR}/agent/linux_arm woodpecker-agent
|
||||
tar -cvzf ${DIST_DIR}/woodpecker-agent_darwin_amd64.tar.gz -C ${DIST_DIR}/agent/darwin_amd64 woodpecker-agent
|
||||
tar -cvzf ${DIST_DIR}/woodpecker-agent_darwin_arm64.tar.gz -C ${DIST_DIR}/agent/darwin_arm64 woodpecker-agent
|
||||
# zip binary files
|
||||
rm -f ${DIST_DIR}/woodpecker-agent_windows_amd64.zip
|
||||
zip -j ${DIST_DIR}/woodpecker-agent_windows_amd64.zip ${DIST_DIR}/agent/windows_amd64/woodpecker-agent.exe
|
||||
|
||||
release-cli: ## Create cli binaries for release
|
||||
# compile
|
||||
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o dist/cli/linux_amd64/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
|
||||
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o dist/cli/linux_arm64/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
|
||||
GOOS=linux GOARCH=arm CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o dist/cli/linux_arm/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
|
||||
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o dist/cli/windows_amd64/woodpecker-cli.exe go.woodpecker-ci.org/woodpecker/v2/cmd/cli
|
||||
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o dist/cli/darwin_amd64/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
|
||||
GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o dist/cli/darwin_arm64/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
|
||||
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o ${DIST_DIR}/cli/linux_amd64/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
|
||||
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o ${DIST_DIR}/cli/linux_arm64/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
|
||||
GOOS=linux GOARCH=arm CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o ${DIST_DIR}/cli/linux_arm/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
|
||||
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o ${DIST_DIR}/cli/windows_amd64/woodpecker-cli.exe go.woodpecker-ci.org/woodpecker/v2/cmd/cli
|
||||
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o ${DIST_DIR}/cli/darwin_amd64/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
|
||||
GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -ldflags '${LDFLAGS}' -o ${DIST_DIR}/cli/darwin_arm64/woodpecker-cli go.woodpecker-ci.org/woodpecker/v2/cmd/cli
|
||||
# tar binary files
|
||||
tar -cvzf dist/woodpecker-cli_linux_amd64.tar.gz -C dist/cli/linux_amd64 woodpecker-cli
|
||||
tar -cvzf dist/woodpecker-cli_linux_arm64.tar.gz -C dist/cli/linux_arm64 woodpecker-cli
|
||||
tar -cvzf dist/woodpecker-cli_linux_arm.tar.gz -C dist/cli/linux_arm woodpecker-cli
|
||||
tar -cvzf dist/woodpecker-cli_windows_amd64.tar.gz -C dist/cli/windows_amd64 woodpecker-cli.exe
|
||||
tar -cvzf dist/woodpecker-cli_darwin_amd64.tar.gz -C dist/cli/darwin_amd64 woodpecker-cli
|
||||
tar -cvzf dist/woodpecker-cli_darwin_arm64.tar.gz -C dist/cli/darwin_arm64 woodpecker-cli
|
||||
tar -cvzf ${DIST_DIR}/woodpecker-cli_linux_amd64.tar.gz -C ${DIST_DIR}/cli/linux_amd64 woodpecker-cli
|
||||
tar -cvzf ${DIST_DIR}/woodpecker-cli_linux_arm64.tar.gz -C ${DIST_DIR}/cli/linux_arm64 woodpecker-cli
|
||||
tar -cvzf ${DIST_DIR}/woodpecker-cli_linux_arm.tar.gz -C ${DIST_DIR}/cli/linux_arm woodpecker-cli
|
||||
tar -cvzf ${DIST_DIR}/woodpecker-cli_darwin_amd64.tar.gz -C ${DIST_DIR}/cli/darwin_amd64 woodpecker-cli
|
||||
tar -cvzf ${DIST_DIR}/woodpecker-cli_darwin_arm64.tar.gz -C ${DIST_DIR}/cli/darwin_arm64 woodpecker-cli
|
||||
# zip binary files
|
||||
rm -f ${DIST_DIR}/woodpecker-cli_windows_amd64.zip
|
||||
zip -j ${DIST_DIR}/woodpecker-cli_windows_amd64.zip ${DIST_DIR}/cli/windows_amd64/woodpecker-cli.exe
|
||||
|
||||
release-checksums: ## Create checksums for all release files
|
||||
# generate shas for tar files
|
||||
(cd dist/; sha256sum *.* > checksums.txt)
|
||||
(cd ${DIST_DIR}/; sha256sum *.* > checksums.txt)
|
||||
|
||||
.PHONY: release
|
||||
release: release-frontend release-server release-agent release-cli ## Release all binaries
|
||||
|
@ -292,16 +316,16 @@ bundle-prepare: ## Prepare the bundles
|
|||
go install github.com/goreleaser/nfpm/v2/cmd/nfpm@v2.6.0
|
||||
|
||||
bundle-agent: bundle-prepare ## Create bundles for agent
|
||||
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/agent.yaml --target ./dist --packager deb
|
||||
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/agent.yaml --target ./dist --packager rpm
|
||||
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/agent.yaml --target ${DIST_DIR} --packager deb
|
||||
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/agent.yaml --target ${DIST_DIR} --packager rpm
|
||||
|
||||
bundle-server: bundle-prepare ## Create bundles for server
|
||||
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/server.yaml --target ./dist --packager deb
|
||||
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/server.yaml --target ./dist --packager rpm
|
||||
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/server.yaml --target ${DIST_DIR} --packager deb
|
||||
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/server.yaml --target ${DIST_DIR} --packager rpm
|
||||
|
||||
bundle-cli: bundle-prepare ## Create bundles for cli
|
||||
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/cli.yaml --target ./dist --packager deb
|
||||
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/cli.yaml --target ./dist --packager rpm
|
||||
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/cli.yaml --target ${DIST_DIR} --packager deb
|
||||
VERSION_NUMBER=$(VERSION_NUMBER) nfpm package --config ./nfpm/cli.yaml --target ${DIST_DIR} --packager rpm
|
||||
|
||||
.PHONY: bundle
|
||||
bundle: bundle-agent bundle-server bundle-cli ## Create all bundles
|
||||
|
|
57
README.md
57
README.md
|
@ -43,55 +43,48 @@
|
|||
</p>
|
||||
<br/>
|
||||
|
||||
Woodpecker is a simple yet powerful CI/CD engine with great extensibility.
|
||||
Woodpecker is a simple, yet powerful CI/CD engine with great extensibility.
|
||||
|
||||
![woodpecker](docs/docs/woodpecker.png)
|
||||
![woodpecker](docs/woodpecker.png)
|
||||
|
||||
## 🫶 Support
|
||||
## Installation & Resources
|
||||
|
||||
Please consider donating and become a backer. 🙏 [[Become a backer](https://opencollective.com/woodpecker-ci#category-CONTRIBUTE)]
|
||||
Woodpecker can be installed in various ways (see the [Installation Instructions](https://woodpecker-ci.org/docs/administration/getting-started)) and runs with SQLite as database by default.
|
||||
It requires around 100 MB of RAM (Server) and 30 MB (Agent) at runtime in idle mode.
|
||||
|
||||
## Support
|
||||
|
||||
You can support the project by becoming a backer on [Open Collective](https://opencollective.com/woodpecker-ci#category-CONTRIBUTE) or via [GitHub Sponsors](https://github.com/sponsors/woodpecker-ci).
|
||||
|
||||
<a href="https://opencollective.com/woodpecker-ci" target="_blank"><img src="https://opencollective.com/woodpecker-ci/backers.svg?width=890" alt="Open Collective backers"></a>
|
||||
|
||||
## 📖 Documentation
|
||||
## Documentation
|
||||
|
||||
<https://woodpecker-ci.org/>
|
||||
Our documentation can be found at <https://woodpecker-ci.org/docs/intro>.
|
||||
|
||||
## ✨ Contribute
|
||||
## Translation
|
||||
|
||||
See [Contributing Guide](https://github.com/woodpecker-ci/.github/blob/main/CONTRIBUTING.md)
|
||||
We have a self-hosted [Weblate](https://weblate.org/en/) instance at [translate.woodpecker-ci.org](https://translate.woodpecker-ci.org).
|
||||
|
||||
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://woodpecker-ci.org/docs/next/development/getting-started#gitpod)
|
||||
An overview of the current translation state is available at <https://translate.woodpecker-ci.org/projects/woodpecker-ci/#languages>.
|
||||
|
||||
## 📣 Translate
|
||||
## Public Woodpecker Instances
|
||||
|
||||
We use an own [Weblate](https://weblate.org/en/) instance at [translate.woodpecker-ci.org](https://translate.woodpecker-ci.org).
|
||||
Woodpecker is used as the main CI/CD engine at [Codeberg](https://codeberg.org), an alternative Git hosting platform with a focus on privacy and free software development.
|
||||
|
||||
<a href="https://translate.woodpecker-ci.org/engage/woodpecker-ci/">
|
||||
<img src="https://translate.woodpecker-ci.org/widgets/woodpecker-ci/-/ui/multi-blue.svg" alt="Translation status" />
|
||||
</a>
|
||||
## Plugins
|
||||
|
||||
## 👋 Who uses Woodpecker?
|
||||
Woodpecker can be extended via plugins.
|
||||
The [plugin overview website](https://woodpecker-ci.org/plugins) helps browsing available plugins.
|
||||
It combines both plugins by the Woodpecker core team and community-maintained ones.
|
||||
|
||||
Woodpecker is used by [itself](https://ci.woodpecker-ci.org/woodpecker/woodpecker-ci/), multiple well-known companies, organizations like [Codeberg](https://codeberg.org), hobbyists and many others.
|
||||
## Star History
|
||||
|
||||
Leave a [comment](https://github.com/woodpecker-ci/woodpecker/discussions/2149) if you're using it as well.
|
||||
|
||||
Also consider using the topic `WoodpeckerCI` in your repository, so others can learn from your config and use the hashtag `#WoodpeckerCI` when talking about the project on social media!
|
||||
|
||||
Here are some places where people mention Woodpecker:
|
||||
|
||||
- [GitHub](https://github.com/topics/WoodpeckerCI)
|
||||
- [Codeberg](https://codeberg.org/explore/repos?q=woodpeckerci&topic=1)
|
||||
- [Twitter](https://twitter.com/search?q=%23WoodpeckerCI&src=typed_query)
|
||||
- [Fediverse](https://mastodon.social/tags/WoodpeckerCI)
|
||||
|
||||
## ✨ Stars over time
|
||||
|
||||
[![Stargazers over time](https://starchart.cc/woodpecker-ci/woodpecker.svg)](https://starchart.cc/woodpecker-ci/woodpecker)
|
||||
[![Star History Chart](https://api.star-history.com/svg?repos=woodpecker-ci/woodpecker&type=Date)](https://star-history.com/#woodpecker-ci/woodpecker&Date)
|
||||
|
||||
## License
|
||||
|
||||
Woodpecker is Apache 2.0 licensed with the source files in this repository having a header indicating which license they are under and what copyrights apply.
|
||||
Woodpecker is Apache 2.0 licensed.
|
||||
The source files have a header indicating which license they are under and what copyrights apply.
|
||||
|
||||
Files under the `docs/` folder are licensed under Creative Commons Attribution-ShareAlike 4.0 International Public License.
|
||||
Everything in `docs/` is licensed under the Creative Commons Attribution-ShareAlike 4.0 International Public License.
|
||||
|
|
|
@ -26,17 +26,12 @@ import (
|
|||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
|
||||
)
|
||||
|
||||
const (
|
||||
// Store not more than 1mb in a log-line as 4mb is the limit of a grpc message
|
||||
// and log-lines needs to be parsed by the browsers later on.
|
||||
maxLogLineLength = 1024 * 1024 // 1mb
|
||||
)
|
||||
|
||||
func (r *Runner) createLogger(_logger zerolog.Logger, uploads *sync.WaitGroup, workflow *rpc.Workflow) pipeline.Logger {
|
||||
return func(step *backend.Step, rc io.Reader) error {
|
||||
return func(step *backend.Step, rc io.ReadCloser) error {
|
||||
defer rc.Close()
|
||||
|
||||
logger := _logger.With().
|
||||
Str("image", step.Image).
|
||||
Str("workflowID", workflow.ID).
|
||||
Logger()
|
||||
|
||||
uploads.Add(1)
|
||||
|
@ -49,7 +44,7 @@ func (r *Runner) createLogger(_logger zerolog.Logger, uploads *sync.WaitGroup, w
|
|||
logger.Debug().Msg("log stream opened")
|
||||
|
||||
logStream := log.NewLineWriter(r.client, step.UUID, secrets...)
|
||||
if err := log.CopyLineByLine(logStream, rc, maxLogLineLength); err != nil {
|
||||
if err := log.CopyLineByLine(logStream, rc, pipeline.MaxLogLineLength); err != nil {
|
||||
logger.Error().Err(err).Msg("copy limited logStream part")
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@ import (
|
|||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc/proto"
|
||||
)
|
||||
|
||||
const authClientTimeout = time.Second * 5
|
||||
|
||||
type AuthClient struct {
|
||||
client proto.WoodpeckerAuthClient
|
||||
conn *grpc.ClientConn
|
||||
|
@ -39,8 +41,8 @@ func NewAuthGrpcClient(conn *grpc.ClientConn, agentToken string, agentID int64)
|
|||
return client
|
||||
}
|
||||
|
||||
func (c *AuthClient) Auth() (string, int64, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) //nolint:mnd
|
||||
func (c *AuthClient) Auth(ctx context.Context) (string, int64, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, authClientTimeout)
|
||||
defer cancel()
|
||||
|
||||
req := &proto.AuthRequest{
|
||||
|
|
|
@ -30,15 +30,12 @@ type AuthInterceptor struct {
|
|||
}
|
||||
|
||||
// NewAuthInterceptor returns a new auth interceptor.
|
||||
func NewAuthInterceptor(
|
||||
authClient *AuthClient,
|
||||
refreshDuration time.Duration,
|
||||
) (*AuthInterceptor, error) {
|
||||
func NewAuthInterceptor(ctx context.Context, authClient *AuthClient, refreshDuration time.Duration) (*AuthInterceptor, error) {
|
||||
interceptor := &AuthInterceptor{
|
||||
authClient: authClient,
|
||||
}
|
||||
|
||||
err := interceptor.scheduleRefreshToken(refreshDuration)
|
||||
err := interceptor.scheduleRefreshToken(ctx, refreshDuration)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -78,21 +75,26 @@ func (interceptor *AuthInterceptor) attachToken(ctx context.Context) context.Con
|
|||
return metadata.AppendToOutgoingContext(ctx, "token", interceptor.accessToken)
|
||||
}
|
||||
|
||||
func (interceptor *AuthInterceptor) scheduleRefreshToken(refreshDuration time.Duration) error {
|
||||
err := interceptor.refreshToken()
|
||||
func (interceptor *AuthInterceptor) scheduleRefreshToken(ctx context.Context, refreshInterval time.Duration) error {
|
||||
err := interceptor.refreshToken(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
wait := refreshDuration
|
||||
wait := refreshInterval
|
||||
|
||||
for {
|
||||
time.Sleep(wait)
|
||||
err := interceptor.refreshToken()
|
||||
if err != nil {
|
||||
wait = time.Second
|
||||
} else {
|
||||
wait = refreshDuration
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-time.After(wait):
|
||||
err := interceptor.refreshToken(ctx)
|
||||
if err != nil {
|
||||
wait = time.Second
|
||||
} else {
|
||||
wait = refreshInterval
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
@ -100,8 +102,8 @@ func (interceptor *AuthInterceptor) scheduleRefreshToken(refreshDuration time.Du
|
|||
return nil
|
||||
}
|
||||
|
||||
func (interceptor *AuthInterceptor) refreshToken() error {
|
||||
accessToken, _, err := interceptor.authClient.Auth()
|
||||
func (interceptor *AuthInterceptor) refreshToken(ctx context.Context) error {
|
||||
accessToken, _, err := interceptor.authClient.Auth(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -25,29 +25,44 @@ import (
|
|||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
grpcproto "google.golang.org/protobuf/proto"
|
||||
|
||||
backend "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc/proto"
|
||||
)
|
||||
|
||||
// Set grpc version on compile time to compare against server version response.
|
||||
const ClientGrpcVersion int32 = proto.Version
|
||||
const (
|
||||
// Set grpc version on compile time to compare against server version response.
|
||||
ClientGrpcVersion int32 = proto.Version
|
||||
|
||||
// Maximum size of an outgoing log message.
|
||||
// Picked to prevent it from going over GRPC size limit (4 MiB) with a large safety margin.
|
||||
maxLogBatchSize int = 1 * 1024 * 1024
|
||||
|
||||
// Maximum amount of time between sending consecutive batched log messages.
|
||||
// Controls the delay between the CI job generating a log record, and web users receiving it.
|
||||
maxLogFlushPeriod time.Duration = time.Second
|
||||
)
|
||||
|
||||
type client struct {
|
||||
client proto.WoodpeckerClient
|
||||
conn *grpc.ClientConn
|
||||
logs chan *proto.LogEntry
|
||||
}
|
||||
|
||||
// NewGrpcClient returns a new grpc Client.
|
||||
func NewGrpcClient(conn *grpc.ClientConn) rpc.Peer {
|
||||
func NewGrpcClient(ctx context.Context, conn *grpc.ClientConn) rpc.Peer {
|
||||
client := new(client)
|
||||
client.client = proto.NewWoodpeckerClient(conn)
|
||||
client.conn = conn
|
||||
client.logs = make(chan *proto.LogEntry, 10) // max memory use: 10 lines * 1 MiB
|
||||
go client.processLogs(ctx)
|
||||
return client
|
||||
}
|
||||
|
||||
func (c *client) Close() error {
|
||||
close(c.logs)
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
|
@ -72,28 +87,28 @@ func (c *client) Version(ctx context.Context) (*rpc.Version, error) {
|
|||
}
|
||||
|
||||
// Next returns the next workflow in the queue.
|
||||
func (c *client) Next(ctx context.Context, f rpc.Filter) (*rpc.Workflow, error) {
|
||||
func (c *client) Next(ctx context.Context, filter rpc.Filter) (*rpc.Workflow, error) {
|
||||
var res *proto.NextResponse
|
||||
var err error
|
||||
retry := c.newBackOff()
|
||||
req := new(proto.NextRequest)
|
||||
req.Filter = new(proto.Filter)
|
||||
req.Filter.Labels = f.Labels
|
||||
req.Filter.Labels = filter.Labels
|
||||
for {
|
||||
res, err = c.client.Next(ctx, req)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
|
||||
// TODO: remove after adding continuous data exchange by something like #536
|
||||
if strings.Contains(err.Error(), "\"too_many_pings\"") {
|
||||
// https://github.com/woodpecker-ci/woodpecker/issues/717#issuecomment-1049365104
|
||||
log.Trace().Err(err).Msg("grpc: to many keepalive pings without sending data")
|
||||
} else {
|
||||
log.Error().Err(err).Msgf("grpc error: done(): code: %v", status.Code(err))
|
||||
}
|
||||
|
||||
switch status.Code(err) {
|
||||
case codes.Canceled:
|
||||
if ctx.Err() != nil {
|
||||
// expected as context was canceled
|
||||
log.Debug().Err(err).Msgf("grpc error: next(): context canceled")
|
||||
return nil, nil
|
||||
}
|
||||
log.Error().Err(err).Msgf("grpc error: next(): code: %v", status.Code(err))
|
||||
return nil, err
|
||||
case
|
||||
codes.Aborted,
|
||||
codes.DataLoss,
|
||||
|
@ -101,14 +116,22 @@ func (c *client) Next(ctx context.Context, f rpc.Filter) (*rpc.Workflow, error)
|
|||
codes.Internal,
|
||||
codes.Unavailable:
|
||||
// non-fatal errors
|
||||
// TODO: remove after adding continuous data exchange by something like #536
|
||||
if strings.Contains(err.Error(), "\"too_many_pings\"") {
|
||||
// https://github.com/woodpecker-ci/woodpecker/issues/717#issuecomment-1049365104
|
||||
log.Trace().Err(err).Msg("grpc: to many keepalive pings without sending data")
|
||||
} else {
|
||||
log.Warn().Err(err).Msgf("grpc error: next(): code: %v", status.Code(err))
|
||||
}
|
||||
default:
|
||||
log.Error().Err(err).Msgf("grpc error: next(): code: %v", status.Code(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
select {
|
||||
case <-time.After(retry.NextBackOff()):
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,19 +150,25 @@ func (c *client) Next(ctx context.Context, f rpc.Filter) (*rpc.Workflow, error)
|
|||
}
|
||||
|
||||
// Wait blocks until the workflow is complete.
|
||||
func (c *client) Wait(ctx context.Context, id string) (err error) {
|
||||
func (c *client) Wait(ctx context.Context, workflowID string) (err error) {
|
||||
retry := c.newBackOff()
|
||||
req := new(proto.WaitRequest)
|
||||
req.Id = id
|
||||
req.Id = workflowID
|
||||
for {
|
||||
_, err = c.client.Wait(ctx, req)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
|
||||
log.Error().Err(err).Msgf("grpc error: wait(): code: %v", status.Code(err))
|
||||
|
||||
switch status.Code(err) {
|
||||
case codes.Canceled:
|
||||
if ctx.Err() != nil {
|
||||
// expected as context was canceled
|
||||
log.Debug().Err(err).Msgf("grpc error: wait(): context canceled")
|
||||
return nil
|
||||
}
|
||||
log.Error().Err(err).Msgf("grpc error: wait(): code: %v", status.Code(err))
|
||||
return err
|
||||
case
|
||||
codes.Aborted,
|
||||
codes.DataLoss,
|
||||
|
@ -147,7 +176,9 @@ func (c *client) Wait(ctx context.Context, id string) (err error) {
|
|||
codes.Internal,
|
||||
codes.Unavailable:
|
||||
// non-fatal errors
|
||||
log.Warn().Err(err).Msgf("grpc error: wait(): code: %v", status.Code(err))
|
||||
default:
|
||||
log.Error().Err(err).Msgf("grpc error: wait(): code: %v", status.Code(err))
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -161,17 +192,14 @@ func (c *client) Wait(ctx context.Context, id string) (err error) {
|
|||
}
|
||||
|
||||
// Init signals the workflow is initialized.
|
||||
func (c *client) Init(ctx context.Context, id string, state rpc.State) (err error) {
|
||||
func (c *client) Init(ctx context.Context, workflowID string, state rpc.WorkflowState) (err error) {
|
||||
retry := c.newBackOff()
|
||||
req := new(proto.InitRequest)
|
||||
req.Id = id
|
||||
req.State = new(proto.State)
|
||||
req.State.Error = state.Error
|
||||
req.State.ExitCode = int32(state.ExitCode)
|
||||
req.State.Exited = state.Exited
|
||||
req.State.Finished = state.Finished
|
||||
req.Id = workflowID
|
||||
req.State = new(proto.WorkflowState)
|
||||
req.State.Started = state.Started
|
||||
req.State.StepUuid = state.StepUUID
|
||||
req.State.Finished = state.Finished
|
||||
req.State.Error = state.Error
|
||||
for {
|
||||
_, err = c.client.Init(ctx, req)
|
||||
if err == nil {
|
||||
|
@ -181,6 +209,14 @@ func (c *client) Init(ctx context.Context, id string, state rpc.State) (err erro
|
|||
log.Error().Err(err).Msgf("grpc error: init(): code: %v", status.Code(err))
|
||||
|
||||
switch status.Code(err) {
|
||||
case codes.Canceled:
|
||||
if ctx.Err() != nil {
|
||||
// expected as context was canceled
|
||||
log.Debug().Err(err).Msgf("grpc error: init(): context canceled")
|
||||
return nil
|
||||
}
|
||||
log.Error().Err(err).Msgf("grpc error: init(): code: %v", status.Code(err))
|
||||
return err
|
||||
case
|
||||
codes.Aborted,
|
||||
codes.DataLoss,
|
||||
|
@ -188,7 +224,9 @@ func (c *client) Init(ctx context.Context, id string, state rpc.State) (err erro
|
|||
codes.Internal,
|
||||
codes.Unavailable:
|
||||
// non-fatal errors
|
||||
log.Warn().Err(err).Msgf("grpc error: init(): code: %v", status.Code(err))
|
||||
default:
|
||||
log.Error().Err(err).Msgf("grpc error: init(): code: %v", status.Code(err))
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -201,18 +239,15 @@ func (c *client) Init(ctx context.Context, id string, state rpc.State) (err erro
|
|||
return nil
|
||||
}
|
||||
|
||||
// Done signals the work is complete.
|
||||
func (c *client) Done(ctx context.Context, id string, state rpc.State) (err error) {
|
||||
// Done signals the workflow is complete.
|
||||
func (c *client) Done(ctx context.Context, workflowID string, state rpc.WorkflowState) (err error) {
|
||||
retry := c.newBackOff()
|
||||
req := new(proto.DoneRequest)
|
||||
req.Id = id
|
||||
req.State = new(proto.State)
|
||||
req.State.Error = state.Error
|
||||
req.State.ExitCode = int32(state.ExitCode)
|
||||
req.State.Exited = state.Exited
|
||||
req.State.Finished = state.Finished
|
||||
req.Id = workflowID
|
||||
req.State = new(proto.WorkflowState)
|
||||
req.State.Started = state.Started
|
||||
req.State.StepUuid = state.StepUUID
|
||||
req.State.Finished = state.Finished
|
||||
req.State.Error = state.Error
|
||||
for {
|
||||
_, err = c.client.Done(ctx, req)
|
||||
if err == nil {
|
||||
|
@ -222,6 +257,14 @@ func (c *client) Done(ctx context.Context, id string, state rpc.State) (err erro
|
|||
log.Error().Err(err).Msgf("grpc error: done(): code: %v", status.Code(err))
|
||||
|
||||
switch status.Code(err) {
|
||||
case codes.Canceled:
|
||||
if ctx.Err() != nil {
|
||||
// expected as context was canceled
|
||||
log.Debug().Err(err).Msgf("grpc error: done(): context canceled")
|
||||
return nil
|
||||
}
|
||||
log.Error().Err(err).Msgf("grpc error: done(): code: %v", status.Code(err))
|
||||
return err
|
||||
case
|
||||
codes.Aborted,
|
||||
codes.DataLoss,
|
||||
|
@ -229,7 +272,9 @@ func (c *client) Done(ctx context.Context, id string, state rpc.State) (err erro
|
|||
codes.Internal,
|
||||
codes.Unavailable:
|
||||
// non-fatal errors
|
||||
log.Warn().Err(err).Msgf("grpc error: done(): code: %v", status.Code(err))
|
||||
default:
|
||||
log.Error().Err(err).Msgf("grpc error: done(): code: %v", status.Code(err))
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -243,10 +288,10 @@ func (c *client) Done(ctx context.Context, id string, state rpc.State) (err erro
|
|||
}
|
||||
|
||||
// Extend extends the workflow deadline.
|
||||
func (c *client) Extend(ctx context.Context, id string) (err error) {
|
||||
func (c *client) Extend(ctx context.Context, workflowID string) (err error) {
|
||||
retry := c.newBackOff()
|
||||
req := new(proto.ExtendRequest)
|
||||
req.Id = id
|
||||
req.Id = workflowID
|
||||
for {
|
||||
_, err = c.client.Extend(ctx, req)
|
||||
if err == nil {
|
||||
|
@ -256,6 +301,14 @@ func (c *client) Extend(ctx context.Context, id string) (err error) {
|
|||
log.Error().Err(err).Msgf("grpc error: extend(): code: %v", status.Code(err))
|
||||
|
||||
switch status.Code(err) {
|
||||
case codes.Canceled:
|
||||
if ctx.Err() != nil {
|
||||
// expected as context was canceled
|
||||
log.Debug().Err(err).Msgf("grpc error: extend(): context canceled")
|
||||
return nil
|
||||
}
|
||||
log.Error().Err(err).Msgf("grpc error: extend(): code: %v", status.Code(err))
|
||||
return err
|
||||
case
|
||||
codes.Aborted,
|
||||
codes.DataLoss,
|
||||
|
@ -263,7 +316,9 @@ func (c *client) Extend(ctx context.Context, id string) (err error) {
|
|||
codes.Internal,
|
||||
codes.Unavailable:
|
||||
// non-fatal errors
|
||||
log.Warn().Err(err).Msgf("grpc error: extend(): code: %v", status.Code(err))
|
||||
default:
|
||||
log.Error().Err(err).Msgf("grpc error: extend(): code: %v", status.Code(err))
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -277,17 +332,17 @@ func (c *client) Extend(ctx context.Context, id string) (err error) {
|
|||
}
|
||||
|
||||
// Update updates the workflow state.
|
||||
func (c *client) Update(ctx context.Context, id string, state rpc.State) (err error) {
|
||||
func (c *client) Update(ctx context.Context, workflowID string, state rpc.StepState) (err error) {
|
||||
retry := c.newBackOff()
|
||||
req := new(proto.UpdateRequest)
|
||||
req.Id = id
|
||||
req.State = new(proto.State)
|
||||
req.State.Error = state.Error
|
||||
req.State.ExitCode = int32(state.ExitCode)
|
||||
req.State.Exited = state.Exited
|
||||
req.State.Finished = state.Finished
|
||||
req.State.Started = state.Started
|
||||
req.Id = workflowID
|
||||
req.State = new(proto.StepState)
|
||||
req.State.StepUuid = state.StepUUID
|
||||
req.State.Started = state.Started
|
||||
req.State.Finished = state.Finished
|
||||
req.State.Exited = state.Exited
|
||||
req.State.ExitCode = int32(state.ExitCode)
|
||||
req.State.Error = state.Error
|
||||
for {
|
||||
_, err = c.client.Update(ctx, req)
|
||||
if err == nil {
|
||||
|
@ -297,6 +352,14 @@ func (c *client) Update(ctx context.Context, id string, state rpc.State) (err er
|
|||
log.Error().Err(err).Msgf("grpc error: update(): code: %v", status.Code(err))
|
||||
|
||||
switch status.Code(err) {
|
||||
case codes.Canceled:
|
||||
if ctx.Err() != nil {
|
||||
// expected as context was canceled
|
||||
log.Debug().Err(err).Msgf("grpc error: update(): context canceled")
|
||||
return nil
|
||||
}
|
||||
log.Error().Err(err).Msgf("grpc error: update(): code: %v", status.Code(err))
|
||||
return err
|
||||
case
|
||||
codes.Aborted,
|
||||
codes.DataLoss,
|
||||
|
@ -304,7 +367,9 @@ func (c *client) Update(ctx context.Context, id string, state rpc.State) (err er
|
|||
codes.Internal,
|
||||
codes.Unavailable:
|
||||
// non-fatal errors
|
||||
log.Warn().Err(err).Msgf("grpc error: update(): code: %v", status.Code(err))
|
||||
default:
|
||||
log.Error().Err(err).Msgf("grpc error: update(): code: %v", status.Code(err))
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -317,25 +382,82 @@ func (c *client) Update(ctx context.Context, id string, state rpc.State) (err er
|
|||
return nil
|
||||
}
|
||||
|
||||
// Log writes the workflow log entry.
|
||||
func (c *client) Log(ctx context.Context, logEntry *rpc.LogEntry) (err error) {
|
||||
retry := c.newBackOff()
|
||||
req := new(proto.LogRequest)
|
||||
req.LogEntry = new(proto.LogEntry)
|
||||
req.LogEntry.StepUuid = logEntry.StepUUID
|
||||
req.LogEntry.Data = logEntry.Data
|
||||
req.LogEntry.Line = int32(logEntry.Line)
|
||||
req.LogEntry.Time = logEntry.Time
|
||||
req.LogEntry.Type = int32(logEntry.Type)
|
||||
// EnqueueLog queues the log entry to be written in a batch later.
|
||||
func (c *client) EnqueueLog(logEntry *rpc.LogEntry) {
|
||||
c.logs <- &proto.LogEntry{
|
||||
StepUuid: logEntry.StepUUID,
|
||||
Data: logEntry.Data,
|
||||
Line: int32(logEntry.Line),
|
||||
Time: logEntry.Time,
|
||||
Type: int32(logEntry.Type),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *client) processLogs(ctx context.Context) {
|
||||
var entries []*proto.LogEntry
|
||||
var bytes int
|
||||
|
||||
send := func() {
|
||||
if len(entries) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
log.Debug().
|
||||
Int("entries", len(entries)).
|
||||
Int("bytes", bytes).
|
||||
Msg("log drain: sending queued logs")
|
||||
|
||||
if err := c.sendLogs(ctx, entries); err != nil {
|
||||
log.Error().Err(err).Msg("log drain: could not send logs to server")
|
||||
}
|
||||
|
||||
// even if send failed, we don't have infinite memory; retry has already been used
|
||||
entries = entries[:0]
|
||||
bytes = 0
|
||||
}
|
||||
|
||||
// ctx.Done() is covered by the log channel being closed
|
||||
for {
|
||||
_, err = c.client.Log(ctx, req)
|
||||
select {
|
||||
case entry, ok := <-c.logs:
|
||||
if !ok {
|
||||
log.Info().Msg("log drain: channel closed")
|
||||
send()
|
||||
return
|
||||
}
|
||||
|
||||
entries = append(entries, entry)
|
||||
bytes += grpcproto.Size(entry) // cspell:words grpcproto
|
||||
|
||||
if bytes >= maxLogBatchSize {
|
||||
send()
|
||||
}
|
||||
|
||||
case <-time.After(maxLogFlushPeriod):
|
||||
send()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *client) sendLogs(ctx context.Context, entries []*proto.LogEntry) error {
|
||||
req := &proto.LogRequest{LogEntries: entries}
|
||||
retry := c.newBackOff()
|
||||
|
||||
for {
|
||||
_, err := c.client.Log(ctx, req)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
|
||||
log.Error().Err(err).Msgf("grpc error: log(): code: %v", status.Code(err))
|
||||
|
||||
switch status.Code(err) {
|
||||
case codes.Canceled:
|
||||
if ctx.Err() != nil {
|
||||
// expected as context was canceled
|
||||
log.Debug().Err(err).Msgf("grpc error: log(): context canceled")
|
||||
return nil
|
||||
}
|
||||
log.Error().Err(err).Msgf("grpc error: log(): code: %v", status.Code(err))
|
||||
return err
|
||||
case
|
||||
codes.Aborted,
|
||||
codes.DataLoss,
|
||||
|
@ -343,7 +465,9 @@ func (c *client) Log(ctx context.Context, logEntry *rpc.LogEntry) (err error) {
|
|||
codes.Internal,
|
||||
codes.Unavailable:
|
||||
// non-fatal errors
|
||||
log.Warn().Err(err).Msgf("grpc error: log(): code: %v", status.Code(err))
|
||||
default:
|
||||
log.Error().Err(err).Msgf("grpc error: log(): code: %v", status.Code(err))
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -383,6 +507,14 @@ func (c *client) ReportHealth(ctx context.Context) (err error) {
|
|||
return nil
|
||||
}
|
||||
switch status.Code(err) {
|
||||
case codes.Canceled:
|
||||
if ctx.Err() != nil {
|
||||
// expected as context was canceled
|
||||
log.Debug().Err(err).Msgf("grpc error: report_health(): context canceled")
|
||||
return nil
|
||||
}
|
||||
log.Error().Err(err).Msgf("grpc error: report_health(): code: %v", status.Code(err))
|
||||
return err
|
||||
case
|
||||
codes.Aborted,
|
||||
codes.DataLoss,
|
||||
|
@ -390,7 +522,9 @@ func (c *client) ReportHealth(ctx context.Context) (err error) {
|
|||
codes.Internal,
|
||||
codes.Unavailable:
|
||||
// non-fatal errors
|
||||
log.Warn().Err(err).Msgf("grpc error: report_health(): code: %v", status.Code(err))
|
||||
default:
|
||||
log.Error().Err(err).Msgf("grpc error: report_health(): code: %v", status.Code(err))
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
104
agent/runner.go
104
agent/runner.go
|
@ -23,12 +23,12 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/tevino/abool/v2"
|
||||
"google.golang.org/grpc/metadata"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline"
|
||||
backend "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/shared/constant"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/shared/utils"
|
||||
)
|
||||
|
||||
|
@ -50,41 +50,41 @@ func NewRunner(workEngine rpc.Peer, f rpc.Filter, h string, state *State, backen
|
|||
}
|
||||
}
|
||||
|
||||
func (r *Runner) Run(runnerCtx context.Context) error { //nolint:contextcheck
|
||||
func (r *Runner) Run(runnerCtx, shutdownCtx context.Context) error { //nolint:contextcheck
|
||||
log.Debug().Msg("request next execution")
|
||||
|
||||
meta, _ := metadata.FromOutgoingContext(runnerCtx)
|
||||
ctxMeta := metadata.NewOutgoingContext(context.Background(), meta)
|
||||
|
||||
// get the next workflow from the queue
|
||||
work, err := r.client.Next(runnerCtx, r.filter)
|
||||
workflow, err := r.client.Next(runnerCtx, r.filter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if work == nil {
|
||||
if workflow == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
timeout := time.Hour
|
||||
if minutes := work.Timeout; minutes != 0 {
|
||||
if minutes := workflow.Timeout; minutes != 0 {
|
||||
timeout = time.Duration(minutes) * time.Minute
|
||||
}
|
||||
|
||||
repoName := extractRepositoryName(work.Config) // hack
|
||||
pipelineNumber := extractPipelineNumber(work.Config) // hack
|
||||
repoName := extractRepositoryName(workflow.Config) // hack
|
||||
pipelineNumber := extractPipelineNumber(workflow.Config) // hack
|
||||
|
||||
r.counter.Add(
|
||||
work.ID,
|
||||
workflow.ID,
|
||||
timeout,
|
||||
repoName,
|
||||
pipelineNumber,
|
||||
)
|
||||
defer r.counter.Done(work.ID)
|
||||
defer r.counter.Done(workflow.ID)
|
||||
|
||||
logger := log.With().
|
||||
Str("repo", repoName).
|
||||
Str("pipeline", pipelineNumber).
|
||||
Str("id", work.ID).
|
||||
Str("workflow_id", workflow.ID).
|
||||
Logger()
|
||||
|
||||
logger.Debug().Msg("received execution")
|
||||
|
@ -99,17 +99,16 @@ func (r *Runner) Run(runnerCtx context.Context) error { //nolint:contextcheck
|
|||
logger.Error().Msg("Received sigterm termination signal")
|
||||
})
|
||||
|
||||
canceled := abool.New()
|
||||
canceled := false
|
||||
go func() {
|
||||
logger.Debug().Msg("listen for cancel signal")
|
||||
|
||||
if err := r.client.Wait(workflowCtx, work.ID); err != nil {
|
||||
canceled.SetTo(true)
|
||||
if err := r.client.Wait(workflowCtx, workflow.ID); err != nil {
|
||||
canceled = true
|
||||
logger.Warn().Err(err).Msg("cancel signal received")
|
||||
|
||||
cancel()
|
||||
} else {
|
||||
logger.Debug().Msg("stop listening for cancel signal")
|
||||
logger.Debug().Msg("done listening for cancel signal")
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -118,81 +117,74 @@ func (r *Runner) Run(runnerCtx context.Context) error { //nolint:contextcheck
|
|||
select {
|
||||
case <-workflowCtx.Done():
|
||||
logger.Debug().Msg("pipeline done")
|
||||
|
||||
return
|
||||
case <-time.After(time.Minute):
|
||||
logger.Debug().Msg("pipeline lease renewed")
|
||||
|
||||
if err := r.client.Extend(workflowCtx, work.ID); err != nil {
|
||||
case <-time.After(constant.TaskTimeout / 3):
|
||||
logger.Debug().Msg("pipeline lease renewed")
|
||||
if err := r.client.Extend(workflowCtx, workflow.ID); err != nil {
|
||||
log.Error().Err(err).Msg("extending pipeline deadline failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
state := rpc.State{}
|
||||
state := rpc.WorkflowState{}
|
||||
state.Started = time.Now().Unix()
|
||||
|
||||
err = r.client.Init(runnerCtx, work.ID, state)
|
||||
err = r.client.Init(runnerCtx, workflow.ID, state)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("pipeline initialization failed")
|
||||
logger.Error().Err(err).Msg("workflow initialization failed")
|
||||
// TODO: should we return here?
|
||||
}
|
||||
|
||||
var uploads sync.WaitGroup
|
||||
//nolint:contextcheck
|
||||
err = pipeline.New(work.Config,
|
||||
err = pipeline.New(workflow.Config,
|
||||
pipeline.WithContext(workflowCtx),
|
||||
pipeline.WithTaskUUID(fmt.Sprint(work.ID)),
|
||||
pipeline.WithLogger(r.createLogger(logger, &uploads, work)),
|
||||
pipeline.WithTracer(r.createTracer(ctxMeta, logger, work)),
|
||||
pipeline.WithTaskUUID(fmt.Sprint(workflow.ID)),
|
||||
pipeline.WithLogger(r.createLogger(logger, &uploads, workflow)),
|
||||
pipeline.WithTracer(r.createTracer(ctxMeta, &uploads, logger, workflow)),
|
||||
pipeline.WithBackend(*r.backend),
|
||||
pipeline.WithDescription(map[string]string{
|
||||
"ID": work.ID,
|
||||
"Repo": repoName,
|
||||
"Pipeline": pipelineNumber,
|
||||
"workflow_id": workflow.ID,
|
||||
"repo": repoName,
|
||||
"pipeline_number": pipelineNumber,
|
||||
}),
|
||||
).Run(runnerCtx)
|
||||
|
||||
state.Finished = time.Now().Unix()
|
||||
state.Exited = true
|
||||
|
||||
if canceled.IsSet() {
|
||||
state.Error = ""
|
||||
state.ExitCode = pipeline.ExitCodeKilled
|
||||
} else if err != nil {
|
||||
pExitError := &pipeline.ExitError{}
|
||||
switch {
|
||||
case errors.As(err, &pExitError):
|
||||
state.ExitCode = pExitError.Code
|
||||
case errors.Is(err, pipeline.ErrCancel):
|
||||
state.Error = ""
|
||||
state.ExitCode = pipeline.ExitCodeKilled
|
||||
canceled.SetTo(true)
|
||||
default:
|
||||
state.ExitCode = 1
|
||||
state.Error = err.Error()
|
||||
}
|
||||
if errors.Is(err, pipeline.ErrCancel) {
|
||||
canceled = true
|
||||
} else if canceled {
|
||||
err = errors.Join(err, pipeline.ErrCancel)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
state.Error = err.Error()
|
||||
}
|
||||
|
||||
logger.Debug().
|
||||
Str("error", state.Error).
|
||||
Int("exit_code", state.ExitCode).
|
||||
Bool("canceled", canceled.IsSet()).
|
||||
Msg("pipeline complete")
|
||||
Bool("canceled", canceled).
|
||||
Msg("workflow finished")
|
||||
|
||||
logger.Debug().Msg("uploading logs")
|
||||
logger.Debug().Msg("uploading logs and traces / states ...")
|
||||
uploads.Wait()
|
||||
logger.Debug().Msg("uploading logs complete")
|
||||
logger.Debug().Msg("uploaded logs and traces / states")
|
||||
|
||||
logger.Debug().
|
||||
Str("error", state.Error).
|
||||
Int("exit_code", state.ExitCode).
|
||||
Msg("updating pipeline status")
|
||||
Msg("updating workflow status")
|
||||
|
||||
if err := r.client.Done(runnerCtx, work.ID, state); err != nil {
|
||||
logger.Error().Err(err).Msg("updating pipeline status failed")
|
||||
doneCtx := runnerCtx
|
||||
if doneCtx.Err() != nil {
|
||||
doneCtx = shutdownCtx
|
||||
}
|
||||
if err := r.client.Done(doneCtx, workflow.ID, state); err != nil {
|
||||
logger.Error().Err(err).Msg("updating workflow status failed")
|
||||
} else {
|
||||
logger.Debug().Msg("updating pipeline status complete")
|
||||
logger.Debug().Msg("updating workflow status complete")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"context"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
|
@ -26,17 +27,19 @@ import (
|
|||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
|
||||
)
|
||||
|
||||
func (r *Runner) createTracer(ctxMeta context.Context, logger zerolog.Logger, workflow *rpc.Workflow) pipeline.TraceFunc {
|
||||
func (r *Runner) createTracer(ctxMeta context.Context, uploads *sync.WaitGroup, logger zerolog.Logger, workflow *rpc.Workflow) pipeline.TraceFunc {
|
||||
return func(state *pipeline.State) error {
|
||||
uploads.Add(1)
|
||||
|
||||
stepLogger := logger.With().
|
||||
Str("image", state.Pipeline.Step.Image).
|
||||
Str("workflowID", workflow.ID).
|
||||
Str("workflow_id", workflow.ID).
|
||||
Err(state.Process.Error).
|
||||
Int("exit_code", state.Process.ExitCode).
|
||||
Bool("exited", state.Process.Exited).
|
||||
Logger()
|
||||
|
||||
stepState := rpc.State{
|
||||
stepState := rpc.StepState{
|
||||
StepUUID: state.Pipeline.Step.UUID,
|
||||
Exited: state.Process.Exited,
|
||||
ExitCode: state.Process.ExitCode,
|
||||
|
@ -57,6 +60,7 @@ func (r *Runner) createTracer(ctxMeta context.Context, logger zerolog.Logger, wo
|
|||
}
|
||||
|
||||
stepLogger.Debug().Msg("update step status complete")
|
||||
uploads.Done()
|
||||
}()
|
||||
if state.Process.Exited {
|
||||
return nil
|
||||
|
@ -68,21 +72,12 @@ func (r *Runner) createTracer(ctxMeta context.Context, logger zerolog.Logger, wo
|
|||
// TODO: find better way to update this state and move it to pipeline to have the same env in cli-exec
|
||||
state.Pipeline.Step.Environment["CI_MACHINE"] = r.hostname
|
||||
|
||||
state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "success"
|
||||
state.Pipeline.Step.Environment["CI_PIPELINE_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10)
|
||||
state.Pipeline.Step.Environment["CI_PIPELINE_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
state.Pipeline.Step.Environment["CI_PIPELINE_STARTED"] = strconv.FormatInt(state.Pipeline.Started, 10)
|
||||
|
||||
state.Pipeline.Step.Environment["CI_STEP_STATUS"] = "success"
|
||||
state.Pipeline.Step.Environment["CI_STEP_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10)
|
||||
state.Pipeline.Step.Environment["CI_STEP_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
state.Pipeline.Step.Environment["CI_STEP_STARTED"] = strconv.FormatInt(state.Pipeline.Started, 10)
|
||||
|
||||
state.Pipeline.Step.Environment["CI_SYSTEM_PLATFORM"] = runtime.GOOS + "/" + runtime.GOARCH
|
||||
|
||||
if state.Pipeline.Error != nil {
|
||||
state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "failure"
|
||||
state.Pipeline.Step.Environment["CI_STEP_STATUS"] = "failure"
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright 2021 Woodpecker Authors
|
||||
// Copyright 2024 Woodpecker Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -12,16 +12,19 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package migration
|
||||
package admin
|
||||
|
||||
import (
|
||||
"src.techknowlogick.com/xormigrate"
|
||||
"xorm.io/xorm"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/admin/registry"
|
||||
)
|
||||
|
||||
var alterTableReposDropCounter = xormigrate.Migration{
|
||||
ID: "alter-table-drop-counter",
|
||||
MigrateSession: func(sess *xorm.Session) error {
|
||||
return dropTableColumns(sess, "repos", "repo_counter")
|
||||
// Command exports the admin command set.
|
||||
var Command = &cli.Command{
|
||||
Name: "admin",
|
||||
Usage: "administer server settings",
|
||||
Commands: []*cli.Command{
|
||||
registry.Command,
|
||||
},
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2023 Woodpecker Authors
|
||||
// Copyright 2024 Woodpecker Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
@ -15,14 +15,14 @@
|
|||
package registry
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// Command exports the registry command set.
|
||||
var Command = &cli.Command{
|
||||
Name: "registry",
|
||||
Usage: "manage registries",
|
||||
Subcommands: []*cli.Command{
|
||||
Usage: "manage global registries",
|
||||
Commands: []*cli.Command{
|
||||
registryCreateCmd,
|
||||
registryDeleteCmd,
|
||||
registryUpdateCmd,
|
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
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/shared/logger"
|
||||
)
|
||||
|
||||
var GlobalFlags = append([]cli.Flag{
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_CONFIG"},
|
||||
Sources: cli.EnvVars("WOODPECKER_CONFIG"),
|
||||
Name: "config",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "path to config file",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_SERVER"},
|
||||
Sources: cli.EnvVars("WOODPECKER_SERVER"),
|
||||
Name: "server",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "server address",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_TOKEN"},
|
||||
Sources: cli.EnvVars("WOODPECKER_TOKEN"),
|
||||
Name: "token",
|
||||
Aliases: []string{"t"},
|
||||
Usage: "server auth token",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
EnvVars: []string{"WOODPECKER_DISABLE_UPDATE_CHECK"},
|
||||
Sources: cli.EnvVars("WOODPECKER_DISABLE_UPDATE_CHECK"),
|
||||
Name: "disable-update-check",
|
||||
Usage: "disable update check",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
EnvVars: []string{"WOODPECKER_SKIP_VERIFY"},
|
||||
Sources: cli.EnvVars("WOODPECKER_SKIP_VERIFY"),
|
||||
Name: "skip-verify",
|
||||
Usage: "skip ssl verification",
|
||||
Hidden: true,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"SOCKS_PROXY"},
|
||||
Sources: cli.EnvVars("SOCKS_PROXY"),
|
||||
Name: "socks-proxy",
|
||||
Usage: "socks proxy address",
|
||||
Hidden: true,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
EnvVars: []string{"SOCKS_PROXY_OFF"},
|
||||
Sources: cli.EnvVars("SOCKS_PROXY_OFF"),
|
||||
Name: "socks-proxy-off",
|
||||
Usage: "socks proxy ignored",
|
||||
Hidden: true,
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal/config"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/update"
|
||||
|
@ -17,12 +17,12 @@ var (
|
|||
cancelWaitForUpdate context.CancelCauseFunc
|
||||
)
|
||||
|
||||
func Before(c *cli.Context) error {
|
||||
if err := setupGlobalLogger(c); err != nil {
|
||||
func Before(ctx context.Context, c *cli.Command) error {
|
||||
if err := setupGlobalLogger(ctx, c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
go func(context.Context) {
|
||||
if c.Bool("disable-update-check") {
|
||||
return
|
||||
}
|
||||
|
@ -37,23 +37,23 @@ func Before(c *cli.Context) error {
|
|||
|
||||
log.Debug().Msg("Checking for updates ...")
|
||||
|
||||
newVersion, err := update.CheckForUpdate(waitForUpdateCheck, false)
|
||||
newVersion, err := update.CheckForUpdate(waitForUpdateCheck, false) //nolint:contextcheck
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("Failed to check for updates")
|
||||
return
|
||||
}
|
||||
|
||||
if newVersion != nil {
|
||||
log.Warn().Msgf("A new version of woodpecker-cli is available: %s. Update by running: %s update", newVersion.Version, c.App.Name)
|
||||
log.Warn().Msgf("A new version of woodpecker-cli is available: %s. Update by running: %s update", newVersion.Version, c.Root().Name)
|
||||
} else {
|
||||
log.Debug().Msgf("No update required")
|
||||
}
|
||||
}()
|
||||
}(ctx)
|
||||
|
||||
return config.Load(c)
|
||||
return config.Load(ctx, c)
|
||||
}
|
||||
|
||||
func After(_ *cli.Context) error {
|
||||
func After(_ context.Context, _ *cli.Command) error {
|
||||
if waitForUpdateCheck != nil {
|
||||
select {
|
||||
case <-waitForUpdateCheck.Done():
|
||||
|
|
|
@ -15,11 +15,12 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/shared/constant"
|
||||
)
|
||||
|
@ -37,16 +38,16 @@ func DetectPipelineConfig() (isDir bool, config string, _ error) {
|
|||
return false, "", fmt.Errorf("could not detect pipeline config")
|
||||
}
|
||||
|
||||
func RunPipelineFunc(c *cli.Context, fileFunc, dirFunc func(*cli.Context, string) error) error {
|
||||
func RunPipelineFunc(ctx context.Context, c *cli.Command, fileFunc, dirFunc func(context.Context, *cli.Command, string) error) error {
|
||||
if c.Args().Len() == 0 {
|
||||
isDir, path, err := DetectPipelineConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isDir {
|
||||
return dirFunc(c, path)
|
||||
return dirFunc(ctx, c, path)
|
||||
}
|
||||
return fileFunc(c, path)
|
||||
return fileFunc(ctx, c, path)
|
||||
}
|
||||
|
||||
multiArgs := c.Args().Len() > 1
|
||||
|
@ -59,11 +60,11 @@ func RunPipelineFunc(c *cli.Context, fileFunc, dirFunc func(*cli.Context, string
|
|||
fmt.Println("#", fi.Name())
|
||||
}
|
||||
if fi.IsDir() {
|
||||
if err := dirFunc(c, arg); err != nil {
|
||||
if err := dirFunc(ctx, c, arg); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := fileFunc(c, arg); err != nil {
|
||||
if err := fileFunc(ctx, c, arg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,11 +15,13 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"context"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/shared/logger"
|
||||
)
|
||||
|
||||
func setupGlobalLogger(c *cli.Context) error {
|
||||
return logger.SetupGlobalLogger(c, false)
|
||||
func setupGlobalLogger(ctx context.Context, c *cli.Command) error {
|
||||
return logger.SetupGlobalLogger(ctx, c, false)
|
||||
}
|
||||
|
|
|
@ -15,14 +15,14 @@
|
|||
package cron
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// Command exports the cron command set.
|
||||
var Command = &cli.Command{
|
||||
Name: "cron",
|
||||
Usage: "manage cron jobs",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
cronCreateCmd,
|
||||
cronDeleteCmd,
|
||||
cronUpdateCmd,
|
||||
|
|
|
@ -15,10 +15,11 @@
|
|||
package cron
|
||||
|
||||
import (
|
||||
"context"
|
||||
"html/template"
|
||||
"os"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -50,9 +51,9 @@ var cronCreateCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func cronCreate(c *cli.Context) error {
|
||||
func cronCreate(ctx context.Context, c *cli.Command) error {
|
||||
var (
|
||||
jobName = c.String("name")
|
||||
cronName = c.String("name")
|
||||
branch = c.String("branch")
|
||||
schedule = c.String("schedule")
|
||||
repoIDOrFullName = c.String("repository")
|
||||
|
@ -62,7 +63,7 @@ func cronCreate(c *cli.Context) error {
|
|||
repoIDOrFullName = c.Args().First()
|
||||
}
|
||||
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -73,7 +74,7 @@ func cronCreate(c *cli.Context) error {
|
|||
}
|
||||
|
||||
cron := &woodpecker.Cron{
|
||||
Name: jobName,
|
||||
Name: cronName,
|
||||
Branch: branch,
|
||||
Schedule: schedule,
|
||||
}
|
||||
|
|
|
@ -15,10 +15,11 @@
|
|||
package cron
|
||||
|
||||
import (
|
||||
"context"
|
||||
"html/template"
|
||||
"os"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -40,16 +41,16 @@ var cronInfoCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func cronInfo(c *cli.Context) error {
|
||||
func cronInfo(ctx context.Context, c *cli.Command) error {
|
||||
var (
|
||||
jobID = c.Int64("id")
|
||||
cronID = c.Int("id")
|
||||
repoIDOrFullName = c.String("repository")
|
||||
format = c.String("format") + "\n"
|
||||
)
|
||||
if repoIDOrFullName == "" {
|
||||
repoIDOrFullName = c.Args().First()
|
||||
}
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -58,7 +59,7 @@ func cronInfo(c *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
cron, err := client.CronGet(repoID, jobID)
|
||||
cron, err := client.CronGet(repoID, cronID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,10 +15,11 @@
|
|||
package cron
|
||||
|
||||
import (
|
||||
"context"
|
||||
"html/template"
|
||||
"os"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -35,7 +36,7 @@ var cronListCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func cronList(c *cli.Context) error {
|
||||
func cronList(ctx context.Context, c *cli.Command) error {
|
||||
var (
|
||||
format = c.String("format") + "\n"
|
||||
repoIDOrFullName = c.String("repository")
|
||||
|
@ -43,7 +44,7 @@ func cronList(c *cli.Context) error {
|
|||
if repoIDOrFullName == "" {
|
||||
repoIDOrFullName = c.Args().First()
|
||||
}
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,9 +15,10 @@
|
|||
package cron
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -38,15 +39,15 @@ var cronDeleteCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func cronDelete(c *cli.Context) error {
|
||||
func cronDelete(ctx context.Context, c *cli.Command) error {
|
||||
var (
|
||||
jobID = c.Int64("id")
|
||||
cronID = c.Int("id")
|
||||
repoIDOrFullName = c.String("repository")
|
||||
)
|
||||
if repoIDOrFullName == "" {
|
||||
repoIDOrFullName = c.Args().First()
|
||||
}
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -54,7 +55,7 @@ func cronDelete(c *cli.Context) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = client.CronDelete(repoID, jobID)
|
||||
err = client.CronDelete(repoID, cronID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,10 +15,11 @@
|
|||
package cron
|
||||
|
||||
import (
|
||||
"context"
|
||||
"html/template"
|
||||
"os"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -53,10 +54,10 @@ var cronUpdateCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func cronUpdate(c *cli.Context) error {
|
||||
func cronUpdate(ctx context.Context, c *cli.Command) error {
|
||||
var (
|
||||
repoIDOrFullName = c.String("repository")
|
||||
jobID = c.Int64("id")
|
||||
cronID = c.Int("id")
|
||||
jobName = c.String("name")
|
||||
branch = c.String("branch")
|
||||
schedule = c.String("schedule")
|
||||
|
@ -65,7 +66,7 @@ func cronUpdate(c *cli.Context) error {
|
|||
if repoIDOrFullName == "" {
|
||||
repoIDOrFullName = c.Args().First()
|
||||
}
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -74,7 +75,7 @@ func cronUpdate(c *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
cron := &woodpecker.Cron{
|
||||
ID: jobID,
|
||||
ID: cronID,
|
||||
Name: jobName,
|
||||
Branch: branch,
|
||||
Schedule: schedule,
|
||||
|
|
|
@ -15,12 +15,13 @@
|
|||
package deploy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -30,7 +31,7 @@ import (
|
|||
// Command exports the deploy command.
|
||||
var Command = &cli.Command{
|
||||
Name: "deploy",
|
||||
Usage: "deploy code",
|
||||
Usage: "trigger a pipeline with the 'deployment' event",
|
||||
ArgsUsage: "<repo-id|repo-full-name> <pipeline> <environment>",
|
||||
Action: deploy,
|
||||
Flags: []cli.Flag{
|
||||
|
@ -38,7 +39,6 @@ var Command = &cli.Command{
|
|||
&cli.StringFlag{
|
||||
Name: "branch",
|
||||
Usage: "branch filter",
|
||||
Value: "main",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "event",
|
||||
|
@ -58,8 +58,8 @@ var Command = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func deploy(c *cli.Context) error {
|
||||
client, err := internal.NewClient(c)
|
||||
func deploy(ctx context.Context, c *cli.Command) error {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -74,6 +74,15 @@ func deploy(c *cli.Context) error {
|
|||
event := c.String("event")
|
||||
status := c.String("status")
|
||||
|
||||
if branch == "" {
|
||||
repo, err := client.Repo(repoID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
branch = repo.DefaultBranch
|
||||
}
|
||||
|
||||
pipelineArg := c.Args().Get(1)
|
||||
var number int64
|
||||
if pipelineArg == "last" {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2022 Woodpecker Authors
|
||||
// Copyright 2024 Woodpecker Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
@ -12,16 +12,13 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package migration
|
||||
//go:build test
|
||||
// +build test
|
||||
|
||||
import (
|
||||
"src.techknowlogick.com/xormigrate"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
package exec
|
||||
|
||||
var dropFiles = xormigrate.Migration{
|
||||
ID: "drop-files",
|
||||
MigrateSession: func(sess *xorm.Session) error {
|
||||
return sess.DropTable("files")
|
||||
},
|
||||
import "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/dummy"
|
||||
|
||||
func init() { //nolint:gochecknoinits
|
||||
backends = append(backends, dummy.New())
|
||||
}
|
|
@ -26,20 +26,22 @@ import (
|
|||
|
||||
"github.com/drone/envsubst"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/lint"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/docker"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/kubernetes"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/local"
|
||||
backendTypes "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
|
||||
backend_types "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/compiler"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/linter"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/matrix"
|
||||
pipelineLog "go.woodpecker-ci.org/woodpecker/v2/pipeline/log"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/shared/constant"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/shared/utils"
|
||||
)
|
||||
|
||||
|
@ -52,11 +54,17 @@ var Command = &cli.Command{
|
|||
Flags: utils.MergeSlices(flags, docker.Flags, kubernetes.Flags, local.Flags),
|
||||
}
|
||||
|
||||
func run(c *cli.Context) error {
|
||||
return common.RunPipelineFunc(c, execFile, execDir)
|
||||
var backends = []backend_types.Backend{
|
||||
kubernetes.New(),
|
||||
docker.New(),
|
||||
local.New(),
|
||||
}
|
||||
|
||||
func execDir(c *cli.Context, dir string) error {
|
||||
func run(ctx context.Context, c *cli.Command) error {
|
||||
return common.RunPipelineFunc(ctx, c, execFile, execDir)
|
||||
}
|
||||
|
||||
func execDir(ctx context.Context, c *cli.Command, dir string) error {
|
||||
// TODO: respect pipeline dependency
|
||||
repoPath := c.String("repo-path")
|
||||
if repoPath != "" {
|
||||
|
@ -75,7 +83,7 @@ func execDir(c *cli.Context, dir string) error {
|
|||
// check if it is a regular file (not dir)
|
||||
if info.Mode().IsRegular() && (strings.HasSuffix(info.Name(), ".yaml") || strings.HasSuffix(info.Name(), ".yml")) {
|
||||
fmt.Println("#", info.Name())
|
||||
_ = runExec(c, path, repoPath) // TODO: should we drop errors or store them and report back?
|
||||
_ = runExec(ctx, c, path, repoPath) // TODO: should we drop errors or store them and report back?
|
||||
fmt.Println("")
|
||||
return nil
|
||||
}
|
||||
|
@ -84,7 +92,7 @@ func execDir(c *cli.Context, dir string) error {
|
|||
})
|
||||
}
|
||||
|
||||
func execFile(c *cli.Context, file string) error {
|
||||
func execFile(ctx context.Context, c *cli.Command, file string) error {
|
||||
repoPath := c.String("repo-path")
|
||||
if repoPath != "" {
|
||||
repoPath, _ = filepath.Abs(repoPath)
|
||||
|
@ -94,10 +102,10 @@ func execFile(c *cli.Context, file string) error {
|
|||
if runtime.GOOS == "windows" {
|
||||
repoPath = convertPathForWindows(repoPath)
|
||||
}
|
||||
return runExec(c, file, repoPath)
|
||||
return runExec(ctx, c, file, repoPath)
|
||||
}
|
||||
|
||||
func runExec(c *cli.Context, file, repoPath string) error {
|
||||
func runExec(ctx context.Context, c *cli.Command, file, repoPath string) error {
|
||||
dat, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -112,7 +120,7 @@ func runExec(c *cli.Context, file, repoPath string) error {
|
|||
axes = append(axes, matrix.Axis{})
|
||||
}
|
||||
for _, axis := range axes {
|
||||
err := execWithAxis(c, file, repoPath, axis)
|
||||
err := execWithAxis(ctx, c, file, repoPath, axis)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -120,8 +128,11 @@ func runExec(c *cli.Context, file, repoPath string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error {
|
||||
metadata := metadataFromContext(c, axis)
|
||||
func execWithAxis(ctx context.Context, c *cli.Command, file, repoPath string, axis matrix.Axis) error {
|
||||
metadata, err := metadataFromContext(ctx, c, axis)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create metadata: %w", err)
|
||||
}
|
||||
environ := metadata.Environ()
|
||||
var secrets []compiler.Secret
|
||||
for key, val := range metadata.Workflow.Matrix {
|
||||
|
@ -177,19 +188,30 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
|
|||
volumes = append(volumes, repoPath+":"+path.Join(workspaceBase, workspacePath))
|
||||
}
|
||||
|
||||
privilegedPlugins := c.StringSlice("plugins-privileged")
|
||||
|
||||
// lint the yaml file
|
||||
if err := linter.New(linter.WithTrusted(true)).Lint([]*linter.WorkflowConfig{{
|
||||
err = linter.New(
|
||||
linter.WithTrusted(true),
|
||||
linter.PrivilegedPlugins(privilegedPlugins),
|
||||
linter.WithTrustedClonePlugins(constant.TrustedClonePlugins),
|
||||
).Lint([]*linter.WorkflowConfig{{
|
||||
File: path.Base(file),
|
||||
RawConfig: confStr,
|
||||
Workflow: conf,
|
||||
}}); err != nil {
|
||||
return err
|
||||
}})
|
||||
if err != nil {
|
||||
str, err := lint.FormatLintError(file, err)
|
||||
fmt.Print(str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// compiles the yaml file
|
||||
compiled, err := compiler.New(
|
||||
compiler.WithEscalated(
|
||||
c.StringSlice("privileged")...,
|
||||
privilegedPlugins...,
|
||||
),
|
||||
compiler.WithVolumes(volumes...),
|
||||
compiler.WithWorkspace(
|
||||
|
@ -223,12 +245,7 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
|
|||
return err
|
||||
}
|
||||
|
||||
backendCtx := context.WithValue(c.Context, backendTypes.CliContext, c)
|
||||
backends := []backendTypes.Backend{
|
||||
kubernetes.New(),
|
||||
docker.New(),
|
||||
local.New(),
|
||||
}
|
||||
backendCtx := context.WithValue(ctx, backend_types.CliCommand, c)
|
||||
backendEngine, err := backend.FindBackend(backendCtx, backends, c.String("backend-engine"))
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -238,21 +255,21 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
|
|||
return err
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), c.Duration("timeout"))
|
||||
pipelineCtx, cancel := context.WithTimeout(context.Background(), c.Duration("timeout"))
|
||||
defer cancel()
|
||||
ctx = utils.WithContextSigtermCallback(ctx, func() {
|
||||
fmt.Println("ctrl+c received, terminating process")
|
||||
pipelineCtx = utils.WithContextSigtermCallback(pipelineCtx, func() {
|
||||
fmt.Printf("ctrl+c received, terminating current pipeline '%s'\n", confStr)
|
||||
})
|
||||
|
||||
return pipeline.New(compiled,
|
||||
pipeline.WithContext(ctx),
|
||||
pipeline.WithContext(pipelineCtx), //nolint:contextcheck
|
||||
pipeline.WithTracer(pipeline.DefaultTracer),
|
||||
pipeline.WithLogger(defaultLogger),
|
||||
pipeline.WithBackend(backendEngine),
|
||||
pipeline.WithDescription(map[string]string{
|
||||
"CLI": "exec",
|
||||
}),
|
||||
).Run(c.Context)
|
||||
).Run(ctx)
|
||||
}
|
||||
|
||||
// convertPathForWindows converts a path to use slash separators
|
||||
|
@ -274,8 +291,7 @@ func convertPathForWindows(path string) string {
|
|||
return filepath.ToSlash(path)
|
||||
}
|
||||
|
||||
const maxLogLineLength = 1024 * 1024 // 1mb
|
||||
var defaultLogger = pipeline.Logger(func(step *backendTypes.Step, rc io.Reader) error {
|
||||
var defaultLogger = pipeline.Logger(func(step *backend_types.Step, rc io.ReadCloser) error {
|
||||
logWriter := NewLineWriter(step.Name, step.UUID)
|
||||
return pipelineLog.CopyLineByLine(logWriter, rc, maxLogLineLength)
|
||||
return pipelineLog.CopyLineByLine(logWriter, rc, pipeline.MaxLogLineLength)
|
||||
})
|
||||
|
|
|
@ -17,53 +17,51 @@ package exec
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/shared/constant"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
var flags = []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
EnvVars: []string{"WOODPECKER_LOCAL"},
|
||||
Sources: cli.EnvVars("WOODPECKER_LOCAL"),
|
||||
Name: "local",
|
||||
Usage: "run from local directory",
|
||||
Value: true,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_REPO_PATH"},
|
||||
Sources: cli.EnvVars("WOODPECKER_REPO_PATH"),
|
||||
Name: "repo-path",
|
||||
Usage: "path to local repository",
|
||||
},
|
||||
&cli.DurationFlag{
|
||||
EnvVars: []string{"WOODPECKER_TIMEOUT"},
|
||||
Sources: cli.EnvVars("WOODPECKER_TIMEOUT"),
|
||||
Name: "timeout",
|
||||
Usage: "pipeline timeout",
|
||||
Value: time.Hour,
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
EnvVars: []string{"WOODPECKER_VOLUMES"},
|
||||
Sources: cli.EnvVars("WOODPECKER_VOLUMES"),
|
||||
Name: "volumes",
|
||||
Usage: "pipeline volumes",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
EnvVars: []string{"WOODPECKER_NETWORKS"},
|
||||
Sources: cli.EnvVars("WOODPECKER_NETWORKS"),
|
||||
Name: "network",
|
||||
Usage: "external networks",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_PREFIX"},
|
||||
Sources: cli.EnvVars("WOODPECKER_PREFIX"),
|
||||
Name: "prefix",
|
||||
Value: "woodpecker",
|
||||
Usage: "prefix used for containers, volumes, networks, ... created by woodpecker",
|
||||
Hidden: true,
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "privileged",
|
||||
Usage: "privileged plugins",
|
||||
Value: cli.NewStringSlice(constant.PrivilegedPlugins...),
|
||||
Sources: cli.EnvVars("WOODPECKER_PLUGINS_PRIVILEGED"),
|
||||
Name: "plugins-privileged",
|
||||
Usage: "Allow plugins to run in privileged mode, if environment variable is defined but empty there will be none",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_BACKEND"},
|
||||
Sources: cli.EnvVars("WOODPECKER_BACKEND"),
|
||||
Name: "backend-engine",
|
||||
Usage: "backend engine to run pipelines on",
|
||||
Value: "auto-detect",
|
||||
|
@ -73,17 +71,17 @@ var flags = []cli.Flag{
|
|||
// backend options for pipeline compiler
|
||||
//
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_BACKEND_NO_PROXY", "NO_PROXY", "no_proxy"},
|
||||
Sources: cli.EnvVars("WOODPECKER_BACKEND_NO_PROXY", "NO_PROXY", "no_proxy"),
|
||||
Usage: "if set, pass the environment variable down as \"NO_PROXY\" to steps",
|
||||
Name: "backend-no-proxy",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_BACKEND_HTTP_PROXY", "HTTP_PROXY", "http_proxy"},
|
||||
Sources: cli.EnvVars("WOODPECKER_BACKEND_HTTP_PROXY", "HTTP_PROXY", "http_proxy"),
|
||||
Usage: "if set, pass the environment variable down as \"HTTP_PROXY\" to steps",
|
||||
Name: "backend-http-proxy",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_BACKEND_HTTPS_PROXY", "HTTPS_PROXY", "https_proxy"},
|
||||
Sources: cli.EnvVars("WOODPECKER_BACKEND_HTTPS_PROXY", "HTTPS_PROXY", "https_proxy"),
|
||||
Usage: "if set, pass the environment variable down as \"HTTPS_PROXY\" to steps",
|
||||
Name: "backend-https-proxy",
|
||||
},
|
||||
|
@ -97,12 +95,12 @@ var flags = []cli.Flag{
|
|||
// workspace default
|
||||
//
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_WORKSPACE_BASE"},
|
||||
Sources: cli.EnvVars("CI_WORKSPACE_BASE"),
|
||||
Name: "workspace-base",
|
||||
Value: "/woodpecker",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_WORKSPACE_PATH"},
|
||||
Sources: cli.EnvVars("CI_WORKSPACE_PATH"),
|
||||
Name: "workspace-path",
|
||||
Value: "src",
|
||||
},
|
||||
|
@ -110,218 +108,246 @@ var flags = []cli.Flag{
|
|||
// netrc parameters
|
||||
//
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_NETRC_USERNAME"},
|
||||
Sources: cli.EnvVars("CI_NETRC_USERNAME"),
|
||||
Name: "netrc-username",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_NETRC_PASSWORD"},
|
||||
Sources: cli.EnvVars("CI_NETRC_PASSWORD"),
|
||||
Name: "netrc-password",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_NETRC_MACHINE"},
|
||||
Sources: cli.EnvVars("CI_NETRC_MACHINE"),
|
||||
Name: "netrc-machine",
|
||||
},
|
||||
//
|
||||
// metadata parameters
|
||||
//
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_SYSTEM_PLATFORM"},
|
||||
Sources: cli.EnvVars("CI_SYSTEM_PLATFORM"),
|
||||
Name: "system-platform",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_SYSTEM_NAME"},
|
||||
Sources: cli.EnvVars("CI_SYSTEM_HOST"),
|
||||
Name: "system-host",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_SYSTEM_NAME"),
|
||||
Name: "system-name",
|
||||
Value: "woodpecker",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_SYSTEM_URL"},
|
||||
Sources: cli.EnvVars("CI_SYSTEM_URL"),
|
||||
Name: "system-url",
|
||||
Value: "https://github.com/woodpecker-ci/woodpecker",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_REPO"},
|
||||
Sources: cli.EnvVars("CI_REPO"),
|
||||
Name: "repo",
|
||||
Usage: "full repo name",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_REPO_REMOTE_ID"},
|
||||
Sources: cli.EnvVars("CI_REPO_REMOTE_ID"),
|
||||
Name: "repo-remote-id",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_REPO_URL"},
|
||||
Sources: cli.EnvVars("CI_REPO_URL"),
|
||||
Name: "repo-url",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_REPO_CLONE_URL"},
|
||||
Sources: cli.EnvVars("CI_REPO_SCM"),
|
||||
Name: "repo-scm",
|
||||
Value: "git",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_REPO_DEFAULT_BRANCH"),
|
||||
Name: "repo-default-branch",
|
||||
Value: "main",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_REPO_CLONE_URL"),
|
||||
Name: "repo-clone-url",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_REPO_CLONE_SSH_URL"},
|
||||
Sources: cli.EnvVars("CI_REPO_CLONE_SSH_URL"),
|
||||
Name: "repo-clone-ssh-url",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_REPO_PRIVATE"},
|
||||
Sources: cli.EnvVars("CI_REPO_PRIVATE"),
|
||||
Name: "repo-private",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
EnvVars: []string{"CI_REPO_TRUSTED"},
|
||||
Sources: cli.EnvVars("CI_REPO_TRUSTED"),
|
||||
Name: "repo-trusted",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
EnvVars: []string{"CI_PIPELINE_NUMBER"},
|
||||
Sources: cli.EnvVars("CI_PIPELINE_NUMBER"),
|
||||
Name: "pipeline-number",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
EnvVars: []string{"CI_PIPELINE_PARENT"},
|
||||
Sources: cli.EnvVars("CI_PIPELINE_PARENT"),
|
||||
Name: "pipeline-parent",
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
EnvVars: []string{"CI_PIPELINE_CREATED"},
|
||||
&cli.IntFlag{
|
||||
Sources: cli.EnvVars("CI_PIPELINE_CREATED"),
|
||||
Name: "pipeline-created",
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
EnvVars: []string{"CI_PIPELINE_STARTED"},
|
||||
&cli.IntFlag{
|
||||
Sources: cli.EnvVars("CI_PIPELINE_STARTED"),
|
||||
Name: "pipeline-started",
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
EnvVars: []string{"CI_PIPELINE_FINISHED"},
|
||||
Name: "pipeline-finished",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PIPELINE_STATUS"},
|
||||
Name: "pipeline-status",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PIPELINE_EVENT"},
|
||||
Sources: cli.EnvVars("CI_PIPELINE_EVENT"),
|
||||
Name: "pipeline-event",
|
||||
Value: "manual",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PIPELINE_URL"},
|
||||
Sources: cli.EnvVars("CI_PIPELINE_FORGE_URL"),
|
||||
Name: "pipeline-url",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PIPELINE_TARGET"},
|
||||
Name: "pipeline-target",
|
||||
Sources: cli.EnvVars("CI_PIPELINE_DEPLOY_TARGET"),
|
||||
Name: "pipeline-deploy-to",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PIPELINE_TASK"},
|
||||
Name: "pipeline-task",
|
||||
Sources: cli.EnvVars("CI_PIPELINE_DEPLOY_TASK"),
|
||||
Name: "pipeline-deploy-task",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_COMMIT_SHA"},
|
||||
Sources: cli.EnvVars("CI_PIPELINE_FILES"),
|
||||
Usage: "either json formatted list of strings, or comma separated string list",
|
||||
Name: "pipeline-files",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_COMMIT_SHA"),
|
||||
Name: "commit-sha",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_COMMIT_REF"},
|
||||
Sources: cli.EnvVars("CI_COMMIT_REF"),
|
||||
Name: "commit-ref",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_COMMIT_REFSPEC"},
|
||||
Sources: cli.EnvVars("CI_COMMIT_REFSPEC"),
|
||||
Name: "commit-refspec",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_COMMIT_BRANCH"},
|
||||
Sources: cli.EnvVars("CI_COMMIT_BRANCH"),
|
||||
Name: "commit-branch",
|
||||
Value: "main",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_COMMIT_MESSAGE"},
|
||||
Sources: cli.EnvVars("CI_COMMIT_MESSAGE"),
|
||||
Name: "commit-message",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_COMMIT_AUTHOR_NAME"},
|
||||
Sources: cli.EnvVars("CI_COMMIT_AUTHOR"),
|
||||
Name: "commit-author-name",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_COMMIT_AUTHOR_AVATAR"},
|
||||
Sources: cli.EnvVars("CI_COMMIT_AUTHOR_AVATAR"),
|
||||
Name: "commit-author-avatar",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_COMMIT_AUTHOR_EMAIL"},
|
||||
Sources: cli.EnvVars("CI_COMMIT_AUTHOR_EMAIL"),
|
||||
Name: "commit-author-email",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Sources: cli.EnvVars("CI_COMMIT_PULL_REQUEST_LABELS"),
|
||||
Name: "commit-pull-labels",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Sources: cli.EnvVars("CI_COMMIT_PRERELEASE"),
|
||||
Name: "commit-release-is-pre",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
EnvVars: []string{"CI_PREV_PIPELINE_NUMBER"},
|
||||
Sources: cli.EnvVars("CI_PREV_PIPELINE_NUMBER"),
|
||||
Name: "prev-pipeline-number",
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
EnvVars: []string{"CI_PREV_PIPELINE_CREATED"},
|
||||
&cli.IntFlag{
|
||||
Sources: cli.EnvVars("CI_PREV_PIPELINE_CREATED"),
|
||||
Name: "prev-pipeline-created",
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
EnvVars: []string{"CI_PREV_PIPELINE_STARTED"},
|
||||
&cli.IntFlag{
|
||||
Sources: cli.EnvVars("CI_PREV_PIPELINE_STARTED"),
|
||||
Name: "prev-pipeline-started",
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
EnvVars: []string{"CI_PREV_PIPELINE_FINISHED"},
|
||||
&cli.IntFlag{
|
||||
Sources: cli.EnvVars("CI_PREV_PIPELINE_FINISHED"),
|
||||
Name: "prev-pipeline-finished",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PREV_PIPELINE_STATUS"},
|
||||
Sources: cli.EnvVars("CI_PREV_PIPELINE_STATUS"),
|
||||
Name: "prev-pipeline-status",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PREV_PIPELINE_EVENT"},
|
||||
Sources: cli.EnvVars("CI_PREV_PIPELINE_EVENT"),
|
||||
Name: "prev-pipeline-event",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PREV_PIPELINE_URL"},
|
||||
Sources: cli.EnvVars("CI_PREV_PIPELINE_FORGE_URL"),
|
||||
Name: "prev-pipeline-url",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PREV_COMMIT_SHA"},
|
||||
Sources: cli.EnvVars("CI_PREV_PIPELINE_DEPLOY_TARGET"),
|
||||
Name: "prev-pipeline-deploy-to",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_PREV_PIPELINE_DEPLOY_TASK"),
|
||||
Name: "prev-pipeline-deploy-task",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("CI_PREV_COMMIT_SHA"),
|
||||
Name: "prev-commit-sha",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PREV_COMMIT_REF"},
|
||||
Sources: cli.EnvVars("CI_PREV_COMMIT_REF"),
|
||||
Name: "prev-commit-ref",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PREV_COMMIT_REFSPEC"},
|
||||
Sources: cli.EnvVars("CI_PREV_COMMIT_REFSPEC"),
|
||||
Name: "prev-commit-refspec",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PREV_COMMIT_BRANCH"},
|
||||
Sources: cli.EnvVars("CI_PREV_COMMIT_BRANCH"),
|
||||
Name: "prev-commit-branch",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PREV_COMMIT_MESSAGE"},
|
||||
Sources: cli.EnvVars("CI_PREV_COMMIT_MESSAGE"),
|
||||
Name: "prev-commit-message",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PREV_COMMIT_AUTHOR_NAME"},
|
||||
Sources: cli.EnvVars("CI_PREV_COMMIT_AUTHOR"),
|
||||
Name: "prev-commit-author-name",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PREV_COMMIT_AUTHOR_AVATAR"},
|
||||
Sources: cli.EnvVars("CI_PREV_COMMIT_AUTHOR_AVATAR"),
|
||||
Name: "prev-commit-author-avatar",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_PREV_COMMIT_AUTHOR_EMAIL"},
|
||||
Sources: cli.EnvVars("CI_PREV_COMMIT_AUTHOR_EMAIL"),
|
||||
Name: "prev-commit-author-email",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
EnvVars: []string{"CI_WORKFLOW_NAME"},
|
||||
Sources: cli.EnvVars("CI_WORKFLOW_NAME"),
|
||||
Name: "workflow-name",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
EnvVars: []string{"CI_WORKFLOW_NUMBER"},
|
||||
Sources: cli.EnvVars("CI_WORKFLOW_NUMBER"),
|
||||
Name: "workflow-number",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
EnvVars: []string{"CI_STEP_NAME"},
|
||||
Sources: cli.EnvVars("CI_STEP_NAME"),
|
||||
Name: "step-name",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
EnvVars: []string{"CI_ENV"},
|
||||
Sources: cli.EnvVars("CI_ENV"),
|
||||
Name: "env",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_FORGE_TYPE"},
|
||||
Sources: cli.EnvVars("CI_FORGE_TYPE"),
|
||||
Name: "forge-type",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"CI_FORGE_URL"},
|
||||
Sources: cli.EnvVars("CI_FORGE_URL"),
|
||||
Name: "forge-url",
|
||||
},
|
||||
}
|
||||
|
|
|
@ -15,10 +15,13 @@
|
|||
package exec
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/metadata"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/matrix"
|
||||
|
@ -26,7 +29,7 @@ import (
|
|||
)
|
||||
|
||||
// return the metadata from the cli context.
|
||||
func metadataFromContext(c *cli.Context, axis matrix.Axis) metadata.Metadata {
|
||||
func metadataFromContext(_ context.Context, c *cli.Command, axis matrix.Axis) (metadata.Metadata, error) {
|
||||
platform := c.String("system-platform")
|
||||
if platform == "" {
|
||||
platform = runtime.GOOS + "/" + runtime.GOARCH
|
||||
|
@ -40,28 +43,42 @@ func metadataFromContext(c *cli.Context, axis matrix.Axis) metadata.Metadata {
|
|||
repoName = fullRepoName[idx+1:]
|
||||
}
|
||||
|
||||
var changedFiles []string
|
||||
changedFilesRaw := c.String("pipeline-files")
|
||||
if len(changedFilesRaw) != 0 && changedFilesRaw[0] == '[' {
|
||||
if err := json.Unmarshal([]byte(changedFilesRaw), &changedFiles); err != nil {
|
||||
return metadata.Metadata{}, fmt.Errorf("pipeline-files detected json but could not parse it: %w", err)
|
||||
}
|
||||
} else {
|
||||
for _, file := range strings.Split(changedFilesRaw, ",") {
|
||||
changedFiles = append(changedFiles, strings.TrimSpace(file))
|
||||
}
|
||||
}
|
||||
|
||||
return metadata.Metadata{
|
||||
Repo: metadata.Repo{
|
||||
Name: repoName,
|
||||
Owner: repoOwner,
|
||||
RemoteID: c.String("repo-remote-id"),
|
||||
ForgeURL: c.String("repo-url"),
|
||||
SCM: c.String("repo-scm"),
|
||||
Branch: c.String("repo-default-branch"),
|
||||
CloneURL: c.String("repo-clone-url"),
|
||||
CloneSSHURL: c.String("repo-clone-ssh-url"),
|
||||
Private: c.Bool("repo-private"),
|
||||
Trusted: c.Bool("repo-trusted"),
|
||||
},
|
||||
Curr: metadata.Pipeline{
|
||||
Number: c.Int64("pipeline-number"),
|
||||
Parent: c.Int64("pipeline-parent"),
|
||||
Created: c.Int64("pipeline-created"),
|
||||
Started: c.Int64("pipeline-started"),
|
||||
Finished: c.Int64("pipeline-finished"),
|
||||
Status: c.String("pipeline-status"),
|
||||
Event: c.String("pipeline-event"),
|
||||
ForgeURL: c.String("pipeline-url"),
|
||||
Target: c.String("pipeline-target"),
|
||||
Task: c.String("pipeline-task"),
|
||||
Number: c.Int("pipeline-number"),
|
||||
Parent: c.Int("pipeline-parent"),
|
||||
Created: c.Int("pipeline-created"),
|
||||
Started: c.Int("pipeline-started"),
|
||||
Finished: c.Int("pipeline-finished"),
|
||||
Status: c.String("pipeline-status"),
|
||||
Event: c.String("pipeline-event"),
|
||||
ForgeURL: c.String("pipeline-url"),
|
||||
DeployTo: c.String("pipeline-deploy-to"),
|
||||
DeployTask: c.String("pipeline-deploy-task"),
|
||||
Commit: metadata.Commit{
|
||||
Sha: c.String("commit-sha"),
|
||||
Ref: c.String("commit-ref"),
|
||||
|
@ -73,13 +90,16 @@ func metadataFromContext(c *cli.Context, axis matrix.Axis) metadata.Metadata {
|
|||
Email: c.String("commit-author-email"),
|
||||
Avatar: c.String("commit-author-avatar"),
|
||||
},
|
||||
PullRequestLabels: c.StringSlice("commit-pull-labels"),
|
||||
IsPrerelease: c.Bool("commit-release-is-pre"),
|
||||
ChangedFiles: changedFiles,
|
||||
},
|
||||
},
|
||||
Prev: metadata.Pipeline{
|
||||
Number: c.Int64("prev-pipeline-number"),
|
||||
Created: c.Int64("prev-pipeline-created"),
|
||||
Started: c.Int64("prev-pipeline-started"),
|
||||
Finished: c.Int64("prev-pipeline-finished"),
|
||||
Number: c.Int("prev-pipeline-number"),
|
||||
Created: c.Int("prev-pipeline-created"),
|
||||
Started: c.Int("prev-pipeline-started"),
|
||||
Finished: c.Int("prev-pipeline-finished"),
|
||||
Status: c.String("prev-pipeline-status"),
|
||||
Event: c.String("prev-pipeline-event"),
|
||||
ForgeURL: c.String("prev-pipeline-url"),
|
||||
|
@ -98,16 +118,17 @@ func metadataFromContext(c *cli.Context, axis matrix.Axis) metadata.Metadata {
|
|||
},
|
||||
Workflow: metadata.Workflow{
|
||||
Name: c.String("workflow-name"),
|
||||
Number: c.Int("workflow-number"),
|
||||
Number: int(c.Int("workflow-number")),
|
||||
Matrix: axis,
|
||||
},
|
||||
Step: metadata.Step{
|
||||
Name: c.String("step-name"),
|
||||
Number: c.Int("step-number"),
|
||||
Number: int(c.Int("step-number")),
|
||||
},
|
||||
Sys: metadata.System{
|
||||
Name: c.String("system-name"),
|
||||
URL: c.String("system-url"),
|
||||
Host: c.String("system-host"),
|
||||
Platform: platform,
|
||||
Version: version.Version,
|
||||
},
|
||||
|
@ -115,5 +136,5 @@ func metadataFromContext(c *cli.Context, axis matrix.Axis) metadata.Metadata {
|
|||
Type: c.String("forge-type"),
|
||||
URL: c.String("forge-url"),
|
||||
},
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -15,10 +15,11 @@
|
|||
package info
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -33,8 +34,8 @@ var Command = &cli.Command{
|
|||
Flags: []cli.Flag{common.FormatFlag(tmplInfo, true)},
|
||||
}
|
||||
|
||||
func info(c *cli.Context) error {
|
||||
client, err := internal.NewClient(c)
|
||||
func info(ctx context.Context, c *cli.Command) error {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
|
@ -8,7 +9,7 @@ import (
|
|||
|
||||
"github.com/adrg/xdg"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
"github.com/zalando/go-keyring"
|
||||
)
|
||||
|
||||
|
@ -32,12 +33,12 @@ func (c *Config) MergeIfNotSet(c2 *Config) {
|
|||
|
||||
var skipSetupForCommands = []string{"setup", "help", "h", "version", "update", "lint", "exec", ""}
|
||||
|
||||
func Load(c *cli.Context) error {
|
||||
func Load(ctx context.Context, c *cli.Command) error {
|
||||
if firstArg := c.Args().First(); slices.Contains(skipSetupForCommands, firstArg) {
|
||||
return nil
|
||||
}
|
||||
|
||||
config, err := Get(c, c.String("config"))
|
||||
config, err := Get(ctx, c, c.String("config"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -80,11 +81,11 @@ func getConfigPath(configPath string) (string, error) {
|
|||
return configPath, nil
|
||||
}
|
||||
|
||||
func Get(ctx *cli.Context, _configPath string) (*Config, error) {
|
||||
c := &Config{
|
||||
LogLevel: ctx.String("log-level"),
|
||||
Token: ctx.String("token"),
|
||||
ServerURL: ctx.String("server"),
|
||||
func Get(_ context.Context, c *cli.Command, _configPath string) (*Config, error) {
|
||||
conf := &Config{
|
||||
LogLevel: c.String("log-level"),
|
||||
Token: c.String("token"),
|
||||
ServerURL: c.String("server"),
|
||||
}
|
||||
|
||||
configPath, err := getConfigPath(_configPath)
|
||||
|
@ -109,33 +110,33 @@ func Get(ctx *cli.Context, _configPath string) (*Config, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.MergeIfNotSet(configFromFile)
|
||||
conf.MergeIfNotSet(configFromFile)
|
||||
log.Debug().Msg("Loaded config from file")
|
||||
}
|
||||
|
||||
// if server or token are explicitly set, use them
|
||||
if ctx.IsSet("server") || ctx.IsSet("token") {
|
||||
return c, nil
|
||||
if c.IsSet("server") || c.IsSet("token") {
|
||||
return conf, nil
|
||||
}
|
||||
|
||||
// load token from keyring
|
||||
service := ctx.App.Name
|
||||
secret, err := keyring.Get(service, c.ServerURL)
|
||||
service := c.Root().Name
|
||||
secret, err := keyring.Get(service, conf.ServerURL)
|
||||
if errors.Is(err, keyring.ErrUnsupportedPlatform) {
|
||||
log.Warn().Msg("Keyring is not supported on this platform")
|
||||
return c, nil
|
||||
return conf, nil
|
||||
}
|
||||
if errors.Is(err, keyring.ErrNotFound) {
|
||||
log.Warn().Msg("Token not found in keyring")
|
||||
return c, nil
|
||||
return conf, nil
|
||||
}
|
||||
c.Token = secret
|
||||
conf.Token = secret
|
||||
|
||||
return c, nil
|
||||
return conf, nil
|
||||
}
|
||||
|
||||
func Save(ctx *cli.Context, _configPath string, c *Config) error {
|
||||
config, err := json.Marshal(c)
|
||||
func Save(_ context.Context, c *cli.Command, _configPath string, conf *Config) error {
|
||||
config, err := json.Marshal(conf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -146,8 +147,8 @@ func Save(ctx *cli.Context, _configPath string, c *Config) error {
|
|||
}
|
||||
|
||||
// save token to keyring
|
||||
service := ctx.App.Name
|
||||
err = keyring.Set(service, c.ServerURL, c.Token)
|
||||
service := c.Root().Name
|
||||
err = keyring.Set(service, conf.ServerURL, conf.Token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,15 +15,18 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
vsc_url "github.com/gitsight/go-vcsurl"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
"golang.org/x/net/proxy"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
|
@ -31,7 +34,7 @@ import (
|
|||
)
|
||||
|
||||
// NewClient returns a new client from the CLI context.
|
||||
func NewClient(c *cli.Context) (woodpecker.Client, error) {
|
||||
func NewClient(ctx context.Context, c *cli.Command) (woodpecker.Client, error) {
|
||||
var (
|
||||
skip = c.Bool("skip-verify")
|
||||
socks = c.String("socks-proxy")
|
||||
|
@ -61,8 +64,7 @@ func NewClient(c *cli.Context) (woodpecker.Client, error) {
|
|||
}
|
||||
|
||||
config := new(oauth2.Config)
|
||||
client := config.Client(
|
||||
c.Context,
|
||||
client := config.Client(ctx,
|
||||
&oauth2.Token{
|
||||
AccessToken: token,
|
||||
},
|
||||
|
@ -90,8 +92,52 @@ func NewClient(c *cli.Context) (woodpecker.Client, error) {
|
|||
return woodpecker.NewClient(server, client), nil
|
||||
}
|
||||
|
||||
func getRepoFromGit(remoteName string) (string, error) {
|
||||
cmd := exec.Command("git", "remote", "get-url", remoteName)
|
||||
stdout, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("could not get remote url: %w", err)
|
||||
}
|
||||
|
||||
gitRemote := strings.TrimSpace(string(stdout))
|
||||
|
||||
log.Debug().Str("git-remote", gitRemote).Msg("extracted remote url from git")
|
||||
|
||||
if len(gitRemote) == 0 {
|
||||
return "", fmt.Errorf("no repository provided")
|
||||
}
|
||||
|
||||
u, err := vsc_url.Parse(gitRemote)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("could not parse git remote url: %w", err)
|
||||
}
|
||||
|
||||
repoFullName := u.FullName
|
||||
log.Debug().Str("repo", repoFullName).Msg("extracted repository from remote url")
|
||||
|
||||
return repoFullName, nil
|
||||
}
|
||||
|
||||
// ParseRepo parses the repository owner and name from a string.
|
||||
func ParseRepo(client woodpecker.Client, str string) (repoID int64, err error) {
|
||||
if str == "" {
|
||||
str, err = getRepoFromGit("upstream")
|
||||
if err != nil {
|
||||
log.Debug().Err(err).Msg("could not get repository from git upstream remote")
|
||||
}
|
||||
}
|
||||
|
||||
if str == "" {
|
||||
str, err = getRepoFromGit("origin")
|
||||
if err != nil {
|
||||
log.Debug().Err(err).Msg("could not get repository from git origin remote")
|
||||
}
|
||||
}
|
||||
|
||||
if str == "" {
|
||||
return 0, fmt.Errorf("no repository provided")
|
||||
}
|
||||
|
||||
if strings.Contains(str, "/") {
|
||||
repo, err := client.RepoLookup(str)
|
||||
if err != nil {
|
||||
|
@ -115,3 +161,40 @@ func ParseKeyPair(p []string) map[string]string {
|
|||
}
|
||||
return params
|
||||
}
|
||||
|
||||
/*
|
||||
ParseStep parses the step id form a string which may either be the step PID (step number) or a step name.
|
||||
These rules apply:
|
||||
|
||||
- Step PID take precedence over step name when searching for a match.
|
||||
- First match is used, when there are multiple steps with the same name.
|
||||
|
||||
Strictly speaking, this is not parsing, but a lookup.
|
||||
*/
|
||||
func ParseStep(client woodpecker.Client, repoID, number int64, stepArg string) (stepID int64, err error) {
|
||||
pipeline, err := client.Pipeline(repoID, number)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
stepPID, err := strconv.ParseInt(stepArg, 10, 64)
|
||||
if err == nil {
|
||||
for _, wf := range pipeline.Workflows {
|
||||
for _, step := range wf.Children {
|
||||
if int64(step.PID) == stepPID {
|
||||
return step.ID, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, wf := range pipeline.Workflows {
|
||||
for _, step := range wf.Children {
|
||||
if step.Name == stepArg {
|
||||
return step.ID, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("no step with number or name '%s' found", stepArg)
|
||||
}
|
||||
|
|
|
@ -15,20 +15,19 @@
|
|||
package lint
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
term_env "github.com/muesli/termenv"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
pipeline_errors "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/linter"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/shared/constant"
|
||||
)
|
||||
|
||||
// Command exports the info command.
|
||||
|
@ -37,13 +36,26 @@ var Command = &cli.Command{
|
|||
Usage: "lint a pipeline configuration file",
|
||||
ArgsUsage: "[path/to/.woodpecker.yaml]",
|
||||
Action: lint,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringSliceFlag{
|
||||
Sources: cli.EnvVars("WOODPECKER_PLUGINS_PRIVILEGED"),
|
||||
Name: "plugins-privileged",
|
||||
Usage: "Allow plugins to run in privileged mode, if environment variable is defined but empty there will be none",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Sources: cli.EnvVars("WOODPECKER_PLUGINS_TRUSTED_CLONE"),
|
||||
Name: "plugins-trusted-clone",
|
||||
Usage: "Plugins witch are trusted to handle the netrc info in clone steps",
|
||||
Value: constant.TrustedClonePlugins,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func lint(c *cli.Context) error {
|
||||
return common.RunPipelineFunc(c, lintFile, lintDir)
|
||||
func lint(ctx context.Context, c *cli.Command) error {
|
||||
return common.RunPipelineFunc(ctx, c, lintFile, lintDir)
|
||||
}
|
||||
|
||||
func lintDir(c *cli.Context, dir string) error {
|
||||
func lintDir(ctx context.Context, c *cli.Command, dir string) error {
|
||||
var errorStrings []string
|
||||
if err := filepath.Walk(dir, func(path string, info os.FileInfo, e error) error {
|
||||
if e != nil {
|
||||
|
@ -53,7 +65,7 @@ func lintDir(c *cli.Context, dir string) error {
|
|||
// check if it is a regular file (not dir)
|
||||
if info.Mode().IsRegular() && (strings.HasSuffix(info.Name(), ".yaml") || strings.HasSuffix(info.Name(), ".yml")) {
|
||||
fmt.Println("#", info.Name())
|
||||
if err := lintFile(c, path); err != nil {
|
||||
if err := lintFile(ctx, c, path); err != nil {
|
||||
errorStrings = append(errorStrings, err.Error())
|
||||
}
|
||||
fmt.Println("")
|
||||
|
@ -71,9 +83,7 @@ func lintDir(c *cli.Context, dir string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func lintFile(_ *cli.Context, file string) error {
|
||||
output := term_env.NewOutput(os.Stdout)
|
||||
|
||||
func lintFile(_ context.Context, c *cli.Command, file string) error {
|
||||
fi, err := os.Open(file)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -87,7 +97,7 @@ func lintFile(_ *cli.Context, file string) error {
|
|||
|
||||
rawConfig := string(buf)
|
||||
|
||||
c, err := yaml.ParseString(rawConfig)
|
||||
parsedConfig, err := yaml.ParseString(rawConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -95,40 +105,23 @@ func lintFile(_ *cli.Context, file string) error {
|
|||
config := &linter.WorkflowConfig{
|
||||
File: path.Base(file),
|
||||
RawConfig: rawConfig,
|
||||
Workflow: c,
|
||||
Workflow: parsedConfig,
|
||||
}
|
||||
|
||||
// TODO: lint multiple files at once to allow checks for sth like "depends_on" to work
|
||||
err = linter.New(linter.WithTrusted(true)).Lint([]*linter.WorkflowConfig{config})
|
||||
err = linter.New(
|
||||
linter.WithTrusted(true),
|
||||
linter.PrivilegedPlugins(c.StringSlice("plugins-privileged")),
|
||||
linter.WithTrustedClonePlugins(c.StringSlice("plugins-trusted-clone")),
|
||||
).Lint([]*linter.WorkflowConfig{config})
|
||||
if err != nil {
|
||||
fmt.Printf("🔥 %s has warnings / errors:\n", output.String(config.File).Underline())
|
||||
str, err := FormatLintError(config.File, err)
|
||||
|
||||
hasErrors := false
|
||||
for _, err := range pipeline_errors.GetPipelineErrors(err) {
|
||||
line := " "
|
||||
|
||||
if err.IsWarning {
|
||||
line = fmt.Sprintf("%s ⚠️ ", line)
|
||||
} else {
|
||||
line = fmt.Sprintf("%s ❌", line)
|
||||
hasErrors = true
|
||||
}
|
||||
|
||||
if data := pipeline_errors.GetLinterData(err); data != nil {
|
||||
line = fmt.Sprintf("%s %s\t%s", line, output.String(data.Field).Bold(), err.Message)
|
||||
} else {
|
||||
line = fmt.Sprintf("%s %s", line, err.Message)
|
||||
}
|
||||
|
||||
// TODO: use table output
|
||||
fmt.Printf("%s\n", line)
|
||||
if str != "" {
|
||||
fmt.Print(str)
|
||||
}
|
||||
|
||||
if hasErrors {
|
||||
return errors.New("config has errors")
|
||||
}
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("✅ Config is valid")
|
||||
|
|
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
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// Command exports the log command set.
|
||||
var Command = &cli.Command{
|
||||
Name: "log",
|
||||
Usage: "manage logs",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
logPurgeCmd,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -15,10 +15,11 @@
|
|||
package log
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
)
|
||||
|
@ -26,44 +27,52 @@ import (
|
|||
var logPurgeCmd = &cli.Command{
|
||||
Name: "purge",
|
||||
Usage: "purge a log",
|
||||
ArgsUsage: "<repo-id|repo-full-name> <pipeline> [step]",
|
||||
ArgsUsage: "<repo-id|repo-full-name> <pipeline> [step-number|step-name]",
|
||||
Action: logPurge,
|
||||
}
|
||||
|
||||
func logPurge(c *cli.Context) (err error) {
|
||||
client, err := internal.NewClient(c)
|
||||
func logPurge(ctx context.Context, c *cli.Command) (err error) {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
repoIDOrFullName := c.Args().First()
|
||||
if len(repoIDOrFullName) == 0 {
|
||||
return fmt.Errorf("missing required argument repo-id / repo-full-name")
|
||||
}
|
||||
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("invalid repo '%s': %w", repoIDOrFullName, err)
|
||||
}
|
||||
number, err := strconv.ParseInt(c.Args().Get(1), 10, 64)
|
||||
|
||||
pipelineArg := c.Args().Get(1)
|
||||
if len(pipelineArg) == 0 {
|
||||
return fmt.Errorf("missing required argument pipeline")
|
||||
}
|
||||
number, err := strconv.ParseInt(pipelineArg, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stepArg := c.Args().Get(2) //nolint:mnd
|
||||
// TODO: Add lookup by name: stepID, err := internal.ParseStep(client, repoID, stepIDOrName)
|
||||
var stepID int64
|
||||
if len(stepArg) != 0 {
|
||||
stepID, err = strconv.ParseInt(stepArg, 10, 64)
|
||||
stepID, err = internal.ParseStep(client, repoID, number, stepArg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if stepID > 0 {
|
||||
fmt.Printf("Purging logs for pipeline %s#%d step %d\n", repoIDOrFullName, number, stepID)
|
||||
err = client.StepLogsPurge(repoID, number, stepID)
|
||||
} else {
|
||||
fmt.Printf("Purging logs for pipeline %s#%d\n", repoIDOrFullName, number)
|
||||
err = client.LogsPurge(repoID, number)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Purging logs for pipeline %s#%d\n", repoIDOrFullName, number)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -15,9 +15,11 @@
|
|||
package loglevel
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
|
@ -31,8 +33,8 @@ var Command = &cli.Command{
|
|||
Action: logLevel,
|
||||
}
|
||||
|
||||
func logLevel(c *cli.Context) error {
|
||||
client, err := internal.NewClient(c)
|
||||
func logLevel(ctx context.Context, c *cli.Command) error {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright 2022 Woodpecker Authors
|
||||
// Copyright 2024 Woodpecker Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -12,16 +12,19 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package migration
|
||||
package org
|
||||
|
||||
import (
|
||||
"src.techknowlogick.com/xormigrate"
|
||||
"xorm.io/xorm"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/org/registry"
|
||||
)
|
||||
|
||||
var removeActiveFromUsers = xormigrate.Migration{
|
||||
ID: "remove-active-from-users",
|
||||
MigrateSession: func(sess *xorm.Session) error {
|
||||
return dropTableColumns(sess, "users", "user_active")
|
||||
// Command exports the org command set.
|
||||
var Command = &cli.Command{
|
||||
Name: "org",
|
||||
Usage: "manage organizations",
|
||||
Commands: []*cli.Command{
|
||||
registry.Command,
|
||||
},
|
||||
}
|
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
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
)
|
||||
|
@ -30,9 +31,9 @@ var pipelineApproveCmd = &cli.Command{
|
|||
Action: pipelineApprove,
|
||||
}
|
||||
|
||||
func pipelineApprove(c *cli.Context) (err error) {
|
||||
func pipelineApprove(ctx context.Context, c *cli.Command) (err error) {
|
||||
repoIDOrFullName := c.Args().First()
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,9 +15,10 @@
|
|||
package pipeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -42,9 +43,9 @@ var pipelineCreateCmd = &cli.Command{
|
|||
}...),
|
||||
}
|
||||
|
||||
func pipelineCreate(c *cli.Context) error {
|
||||
func pipelineCreate(ctx context.Context, c *cli.Command) error {
|
||||
repoIDOrFullName := c.Args().First()
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,10 +15,11 @@
|
|||
package pipeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
)
|
||||
|
@ -30,9 +31,9 @@ var pipelineDeclineCmd = &cli.Command{
|
|||
Action: pipelineDecline,
|
||||
}
|
||||
|
||||
func pipelineDecline(c *cli.Context) (err error) {
|
||||
func pipelineDecline(ctx context.Context, c *cli.Command) (err error) {
|
||||
repoIDOrFullName := c.Args().First()
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,9 +15,10 @@
|
|||
package pipeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -32,9 +33,9 @@ var pipelineInfoCmd = &cli.Command{
|
|||
Flags: common.OutputFlags("table"),
|
||||
}
|
||||
|
||||
func pipelineInfo(c *cli.Context) error {
|
||||
func pipelineInfo(ctx context.Context, c *cli.Command) error {
|
||||
repoIDOrFullName := c.Args().First()
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,10 +15,11 @@
|
|||
package pipeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
)
|
||||
|
@ -31,14 +32,14 @@ var pipelineKillCmd = &cli.Command{
|
|||
Hidden: true,
|
||||
}
|
||||
|
||||
func pipelineKill(c *cli.Context) (err error) {
|
||||
func pipelineKill(ctx context.Context, c *cli.Command) (err error) {
|
||||
number, err := strconv.ParseInt(c.Args().Get(1), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
repoIDOrFullName := c.Args().First()
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
package pipeline
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"context"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -36,9 +38,9 @@ var pipelineLastCmd = &cli.Command{
|
|||
}...),
|
||||
}
|
||||
|
||||
func pipelineLast(c *cli.Context) error {
|
||||
func pipelineLast(ctx context.Context, c *cli.Command) error {
|
||||
repoIDOrFullName := c.Args().First()
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
package pipeline
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"context"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -49,19 +51,19 @@ var pipelineListCmd = &cli.Command{
|
|||
}...),
|
||||
}
|
||||
|
||||
func List(c *cli.Context) error {
|
||||
client, err := internal.NewClient(c)
|
||||
func List(ctx context.Context, c *cli.Command) error {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resources, err := pipelineList(c, client)
|
||||
resources, err := pipelineList(ctx, c, client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return pipelineOutput(c, resources)
|
||||
}
|
||||
|
||||
func pipelineList(c *cli.Context, client woodpecker.Client) ([]woodpecker.Pipeline, error) {
|
||||
func pipelineList(_ context.Context, c *cli.Command, client woodpecker.Client) ([]woodpecker.Pipeline, error) {
|
||||
resources := make([]woodpecker.Pipeline, 0)
|
||||
|
||||
repoIDOrFullName := c.Args().First()
|
||||
|
@ -78,7 +80,7 @@ func pipelineList(c *cli.Context, client woodpecker.Client) ([]woodpecker.Pipeli
|
|||
branch := c.String("branch")
|
||||
event := c.String("event")
|
||||
status := c.String("status")
|
||||
limit := c.Int("limit")
|
||||
limit := int(c.Int("limit"))
|
||||
|
||||
var count int
|
||||
for _, pipeline := range pipelines {
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
package pipeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker/mocks"
|
||||
|
@ -109,12 +110,10 @@ func TestPipelineList(t *testing.T) {
|
|||
mockClient.On("PipelineList", mock.Anything).Return(tt.pipelines, tt.pipelineErr)
|
||||
mockClient.On("RepoLookup", mock.Anything).Return(&woodpecker.Repo{ID: tt.repoID}, nil)
|
||||
|
||||
app := &cli.App{Writer: io.Discard}
|
||||
c := cli.NewContext(app, nil, nil)
|
||||
|
||||
command := pipelineListCmd
|
||||
command.Action = func(c *cli.Context) error {
|
||||
pipelines, err := pipelineList(c, mockClient)
|
||||
command.Writer = io.Discard
|
||||
command.Action = func(ctx context.Context, c *cli.Command) error {
|
||||
pipelines, err := pipelineList(ctx, c, mockClient)
|
||||
if tt.wantErr != nil {
|
||||
assert.EqualError(t, err, tt.wantErr.Error())
|
||||
return nil
|
||||
|
@ -126,7 +125,7 @@ func TestPipelineList(t *testing.T) {
|
|||
return nil
|
||||
}
|
||||
|
||||
_ = command.Run(c, tt.args...)
|
||||
_ = command.Run(context.Background(), tt.args)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,52 +15,98 @@
|
|||
package pipeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"text/template"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var pipelineLogsCmd = &cli.Command{
|
||||
Name: "logs",
|
||||
Usage: "show pipeline logs",
|
||||
ArgsUsage: "<repo-id|repo-full-name> [pipeline] [stepID]",
|
||||
ArgsUsage: "<repo-id|repo-full-name> <pipeline> [step-number|step-name]",
|
||||
Action: pipelineLogs,
|
||||
}
|
||||
|
||||
func pipelineLogs(c *cli.Context) error {
|
||||
func pipelineLogs(ctx context.Context, c *cli.Command) error {
|
||||
repoIDOrFullName := c.Args().First()
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(repoIDOrFullName) == 0 {
|
||||
return fmt.Errorf("missing required argument repo-id / repo-full-name")
|
||||
}
|
||||
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("invalid repo '%s': %w ", repoIDOrFullName, err)
|
||||
}
|
||||
|
||||
numberArgIndex := 1
|
||||
number, err := strconv.ParseInt(c.Args().Get(numberArgIndex), 10, 64)
|
||||
pipelineArg := c.Args().Get(1)
|
||||
if len(pipelineArg) == 0 {
|
||||
return fmt.Errorf("missing required argument pipeline")
|
||||
}
|
||||
number, err := strconv.ParseInt(pipelineArg, 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid pipeline '%s': %w", pipelineArg, err)
|
||||
}
|
||||
|
||||
stepArg := c.Args().Get(2) //nolint:mnd
|
||||
if len(stepArg) == 0 {
|
||||
return showPipelineLog(client, repoID, number)
|
||||
}
|
||||
|
||||
step, err := internal.ParseStep(client, repoID, number, stepArg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid step '%s': %w", stepArg, err)
|
||||
}
|
||||
return showStepLog(client, repoID, number, step)
|
||||
}
|
||||
|
||||
func showPipelineLog(client woodpecker.Client, repoID, number int64) error {
|
||||
pipeline, err := client.Pipeline(repoID, number)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stepArgIndex := 2
|
||||
step, err := strconv.ParseInt(c.Args().Get(stepArgIndex), 10, 64)
|
||||
tmpl, err := template.New("_").Parse(tmplPipelineLogs + "\n")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, workflow := range pipeline.Workflows {
|
||||
for _, step := range workflow.Children {
|
||||
if err := tmpl.Execute(os.Stdout, map[string]any{"workflow": workflow, "step": step}); err != nil {
|
||||
return err
|
||||
}
|
||||
err := showStepLog(client, repoID, number, step.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func showStepLog(client woodpecker.Client, repoID, number, step int64) error {
|
||||
logs, err := client.StepLogEntries(repoID, number, step)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, log := range logs {
|
||||
fmt.Print(string(log.Data))
|
||||
fmt.Println(string(log.Data))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// template for pipeline ps information.
|
||||
var tmplPipelineLogs = "\x1b[33m{{ .workflow.Name }} > {{ .step.Name }} (#{{ .step.PID }}):\x1b[0m"
|
||||
|
|
|
@ -20,7 +20,7 @@ import (
|
|||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/output"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
|
@ -30,7 +30,7 @@ import (
|
|||
var Command = &cli.Command{
|
||||
Name: "pipeline",
|
||||
Usage: "manage pipelines",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
pipelineListCmd,
|
||||
pipelineLastCmd,
|
||||
pipelineLogsCmd,
|
||||
|
@ -46,7 +46,7 @@ var Command = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func pipelineOutput(c *cli.Context, resources []woodpecker.Pipeline, fd ...io.Writer) error {
|
||||
func pipelineOutput(c *cli.Command, resources []woodpecker.Pipeline, fd ...io.Writer) error {
|
||||
outFmt, outOpt := output.ParseOutputOptions(c.String("output"))
|
||||
noHeader := c.Bool("output-no-headers")
|
||||
|
||||
|
@ -77,7 +77,7 @@ func pipelineOutput(c *cli.Context, resources []woodpecker.Pipeline, fd ...io.Wr
|
|||
fallthrough
|
||||
default:
|
||||
table := output.NewTable(out)
|
||||
cols := []string{"Number", "Status", "Event", "Branch", "Commit", "Author"}
|
||||
cols := []string{"Number", "Status", "Event", "Branch", "Message", "Author"}
|
||||
|
||||
if len(outOpt) > 0 {
|
||||
cols = outOpt
|
||||
|
|
|
@ -2,11 +2,12 @@ package pipeline
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
|
@ -22,7 +23,7 @@ func TestPipelineOutput(t *testing.T) {
|
|||
{
|
||||
name: "table output with default columns",
|
||||
args: []string{},
|
||||
expected: "NUMBER STATUS EVENT BRANCH COMMIT AUTHOR\n1 success push main abcdef John Doe\n",
|
||||
expected: "NUMBER STATUS EVENT BRANCH MESSAGE AUTHOR\n1 success push main message John Doe\n",
|
||||
},
|
||||
{
|
||||
name: "table output with custom columns",
|
||||
|
@ -32,7 +33,7 @@ func TestPipelineOutput(t *testing.T) {
|
|||
{
|
||||
name: "table output with no header",
|
||||
args: []string{"output", "--output-no-headers"},
|
||||
expected: "1 success push main abcdef John Doe\n",
|
||||
expected: "1 success push main message John Doe\n",
|
||||
},
|
||||
{
|
||||
name: "go-template output",
|
||||
|
@ -48,39 +49,38 @@ func TestPipelineOutput(t *testing.T) {
|
|||
|
||||
pipelines := []woodpecker.Pipeline{
|
||||
{
|
||||
Number: 1,
|
||||
Status: "success",
|
||||
Event: "push",
|
||||
Branch: "main",
|
||||
Commit: "abcdef",
|
||||
Author: "John Doe",
|
||||
Number: 1,
|
||||
Status: "success",
|
||||
Event: "push",
|
||||
Branch: "main",
|
||||
Message: "message",
|
||||
Author: "John Doe",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
app := &cli.App{Writer: io.Discard}
|
||||
c := cli.NewContext(app, nil, nil)
|
||||
command := &cli.Command{
|
||||
Writer: io.Discard,
|
||||
Name: "output",
|
||||
Flags: common.OutputFlags("table"),
|
||||
Action: func(_ context.Context, c *cli.Command) error {
|
||||
var buf bytes.Buffer
|
||||
err := pipelineOutput(c, pipelines, &buf)
|
||||
|
||||
command := &cli.Command{}
|
||||
command.Name = "output"
|
||||
command.Flags = common.OutputFlags("table")
|
||||
command.Action = func(c *cli.Context) error {
|
||||
var buf bytes.Buffer
|
||||
err := pipelineOutput(c, pipelines, &buf)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.expected, buf.String())
|
||||
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.expected, buf.String())
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
_ = command.Run(c, tt.args...)
|
||||
_ = command.Run(context.Background(), tt.args)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,11 +15,13 @@
|
|||
package pipeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"text/template"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -28,20 +30,20 @@ import (
|
|||
var pipelinePsCmd = &cli.Command{
|
||||
Name: "ps",
|
||||
Usage: "show pipeline steps",
|
||||
ArgsUsage: "<repo-id|repo-full-name> [pipeline]",
|
||||
ArgsUsage: "<repo-id|repo-full-name> <pipeline>",
|
||||
Action: pipelinePs,
|
||||
Flags: []cli.Flag{common.FormatFlag(tmplPipelinePs)},
|
||||
}
|
||||
|
||||
func pipelinePs(c *cli.Context) error {
|
||||
func pipelinePs(ctx context.Context, c *cli.Command) error {
|
||||
repoIDOrFullName := c.Args().First()
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("invalid repo '%s': %w", repoIDOrFullName, err)
|
||||
}
|
||||
|
||||
pipelineArg := c.Args().Get(1)
|
||||
|
@ -58,7 +60,7 @@ func pipelinePs(c *cli.Context) error {
|
|||
} else {
|
||||
number, err = strconv.ParseInt(pipelineArg, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("invalid pipeline '%s': %w", pipelineArg, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,9 +74,9 @@ func pipelinePs(c *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
for _, step := range pipeline.Workflows {
|
||||
for _, child := range step.Children {
|
||||
if err := tmpl.Execute(os.Stdout, child); err != nil {
|
||||
for _, workflow := range pipeline.Workflows {
|
||||
for _, step := range workflow.Children {
|
||||
if err := tmpl.Execute(os.Stdout, map[string]any{"workflow": workflow, "step": step}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -83,8 +85,11 @@ func pipelinePs(c *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Template for pipeline ps information.
|
||||
var tmplPipelinePs = "\x1b[33mStep #{{ .PID }} \x1b[0m" + `
|
||||
Step: {{ .Name }}
|
||||
State: {{ .State }}
|
||||
// template for pipeline ps information.
|
||||
var tmplPipelinePs = "\x1b[33m{{ .workflow.Name }} > {{ .step.Name }} (#{{ .step.PID }}):\x1b[0m" + `
|
||||
Step: {{ .step.Name }}
|
||||
Started: {{ .step.Started }}
|
||||
Stopped: {{ .step.Stopped }}
|
||||
Type: {{ .step.Type }}
|
||||
State: {{ .step.State }}
|
||||
`
|
||||
|
|
|
@ -15,11 +15,12 @@
|
|||
package pipeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -33,8 +34,8 @@ var pipelineQueueCmd = &cli.Command{
|
|||
Flags: []cli.Flag{common.FormatFlag(tmplPipelineQueue)},
|
||||
}
|
||||
|
||||
func pipelineQueue(c *cli.Context) error {
|
||||
client, err := internal.NewClient(c)
|
||||
func pipelineQueue(ctx context.Context, c *cli.Command) error {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,11 +15,12 @@
|
|||
package pipeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
)
|
||||
|
@ -38,9 +39,9 @@ var pipelineStartCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func pipelineStart(c *cli.Context) (err error) {
|
||||
func pipelineStart(ctx context.Context, c *cli.Command) (err error) {
|
||||
repoIDOrFullName := c.Args().First()
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,10 +15,11 @@
|
|||
package pipeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
)
|
||||
|
@ -30,9 +31,9 @@ var pipelineStopCmd = &cli.Command{
|
|||
Action: pipelineStop,
|
||||
}
|
||||
|
||||
func pipelineStop(c *cli.Context) (err error) {
|
||||
func pipelineStop(ctx context.Context, c *cli.Command) (err error) {
|
||||
repoIDOrFullName := c.Args().First()
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
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
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -48,21 +49,14 @@ var registryCreateCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func registryCreate(c *cli.Context) error {
|
||||
func registryCreate(ctx context.Context, c *cli.Command) error {
|
||||
var (
|
||||
hostname = c.String("hostname")
|
||||
username = c.String("username")
|
||||
password = c.String("password")
|
||||
repoIDOrFullName = c.String("repository")
|
||||
hostname = c.String("hostname")
|
||||
username = c.String("username")
|
||||
password = c.String("password")
|
||||
)
|
||||
if repoIDOrFullName == "" {
|
||||
repoIDOrFullName = c.Args().First()
|
||||
}
|
||||
client, err := internal.NewClient(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
|
||||
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -79,8 +73,12 @@ func registryCreate(c *cli.Context) error {
|
|||
}
|
||||
registry.Password = string(out)
|
||||
}
|
||||
if _, err := client.RegistryCreate(repoID, registry); err != nil {
|
||||
|
||||
repoID, err := parseTargetArgs(client, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
_, err = client.RegistryCreate(repoID, registry)
|
||||
return err
|
||||
}
|
|
@ -15,10 +15,11 @@
|
|||
package registry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"html/template"
|
||||
"os"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -40,27 +41,27 @@ var registryInfoCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func registryInfo(c *cli.Context) error {
|
||||
func registryInfo(ctx context.Context, c *cli.Command) error {
|
||||
var (
|
||||
hostname = c.String("hostname")
|
||||
repoIDOrFullName = c.String("repository")
|
||||
format = c.String("format") + "\n"
|
||||
hostname = c.String("hostname")
|
||||
format = c.String("format") + "\n"
|
||||
)
|
||||
if repoIDOrFullName == "" {
|
||||
repoIDOrFullName = c.Args().First()
|
||||
}
|
||||
client, err := internal.NewClient(c)
|
||||
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
|
||||
|
||||
repoID, err := parseTargetArgs(client, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
registry, err := client.Registry(repoID, hostname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpl, err := template.New("_").Parse(format)
|
||||
if err != nil {
|
||||
return err
|
|
@ -15,10 +15,11 @@
|
|||
package registry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"html/template"
|
||||
"os"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -35,26 +36,24 @@ var registryListCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func registryList(c *cli.Context) error {
|
||||
var (
|
||||
format = c.String("format") + "\n"
|
||||
repoIDOrFullName = c.String("repository")
|
||||
)
|
||||
if repoIDOrFullName == "" {
|
||||
repoIDOrFullName = c.Args().First()
|
||||
}
|
||||
client, err := internal.NewClient(c)
|
||||
func registryList(ctx context.Context, c *cli.Command) error {
|
||||
format := c.String("format") + "\n"
|
||||
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
|
||||
|
||||
repoID, err := parseTargetArgs(client, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
list, err := client.RegistryList(repoID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpl, err := template.New("_").Parse(format)
|
||||
if err != nil {
|
||||
return err
|
|
@ -15,7 +15,9 @@
|
|||
package registry
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"context"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -36,21 +38,18 @@ var registryDeleteCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func registryDelete(c *cli.Context) error {
|
||||
var (
|
||||
hostname = c.String("hostname")
|
||||
repoIDOrFullName = c.String("repository")
|
||||
)
|
||||
if repoIDOrFullName == "" {
|
||||
repoIDOrFullName = c.Args().First()
|
||||
}
|
||||
client, err := internal.NewClient(c)
|
||||
func registryDelete(ctx context.Context, c *cli.Command) error {
|
||||
hostname := c.String("hostname")
|
||||
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
|
||||
|
||||
repoID, err := parseTargetArgs(client, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return client.RegistryDelete(repoID, hostname)
|
||||
}
|
|
@ -15,10 +15,11 @@
|
|||
package registry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -48,24 +49,18 @@ var registryUpdateCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func registryUpdate(c *cli.Context) error {
|
||||
func registryUpdate(ctx context.Context, c *cli.Command) error {
|
||||
var (
|
||||
hostname = c.String("hostname")
|
||||
username = c.String("username")
|
||||
password = c.String("password")
|
||||
repoIDOrFullName = c.String("repository")
|
||||
hostname = c.String("hostname")
|
||||
username = c.String("username")
|
||||
password = c.String("password")
|
||||
)
|
||||
if repoIDOrFullName == "" {
|
||||
repoIDOrFullName = c.Args().First()
|
||||
}
|
||||
client, err := internal.NewClient(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
|
||||
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
registry := &woodpecker.Registry{
|
||||
Address: hostname,
|
||||
Username: username,
|
||||
|
@ -79,6 +74,12 @@ func registryUpdate(c *cli.Context) error {
|
|||
}
|
||||
registry.Password = string(out)
|
||||
}
|
||||
|
||||
repoID, err := parseTargetArgs(client, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = client.RegistryUpdate(repoID, registry)
|
||||
return err
|
||||
}
|
|
@ -15,14 +15,16 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/repo/registry"
|
||||
)
|
||||
|
||||
// Command exports the repository command.
|
||||
var Command = &cli.Command{
|
||||
Name: "repo",
|
||||
Usage: "manage repositories",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
repoListCmd,
|
||||
repoInfoCmd,
|
||||
repoAddCmd,
|
||||
|
@ -31,5 +33,6 @@ var Command = &cli.Command{
|
|||
repoRepairCmd,
|
||||
repoChownCmd,
|
||||
repoSyncCmd,
|
||||
registry.Command,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -15,10 +15,11 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
)
|
||||
|
@ -30,14 +31,14 @@ var repoAddCmd = &cli.Command{
|
|||
Action: repoAdd,
|
||||
}
|
||||
|
||||
func repoAdd(c *cli.Context) error {
|
||||
func repoAdd(ctx context.Context, c *cli.Command) error {
|
||||
_forgeRemoteID := c.Args().First()
|
||||
forgeRemoteID, err := strconv.Atoi(_forgeRemoteID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid forge remote id: %s", _forgeRemoteID)
|
||||
}
|
||||
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,9 +15,10 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
)
|
||||
|
@ -29,9 +30,9 @@ var repoChownCmd = &cli.Command{
|
|||
Action: repoChown,
|
||||
}
|
||||
|
||||
func repoChown(c *cli.Context) error {
|
||||
func repoChown(ctx context.Context, c *cli.Command) error {
|
||||
repoIDOrFullName := c.Args().First()
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,10 +15,11 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -32,9 +33,9 @@ var repoInfoCmd = &cli.Command{
|
|||
Flags: []cli.Flag{common.FormatFlag(tmplRepoInfo)},
|
||||
}
|
||||
|
||||
func repoInfo(c *cli.Context) error {
|
||||
func repoInfo(ctx context.Context, c *cli.Command) error {
|
||||
repoIDOrFullName := c.Args().First()
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,10 +15,11 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -38,8 +39,8 @@ var repoListCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func repoList(c *cli.Context) error {
|
||||
client, err := internal.NewClient(c)
|
||||
func repoList(ctx context.Context, c *cli.Command) error {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,9 +15,10 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
)
|
||||
|
@ -29,9 +30,9 @@ var repoRepairCmd = &cli.Command{
|
|||
Action: repoRepair,
|
||||
}
|
||||
|
||||
func repoRepair(c *cli.Context) error {
|
||||
func repoRepair(ctx context.Context, c *cli.Command) error {
|
||||
repoIDOrFullName := c.Args().First()
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,9 +15,10 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
)
|
||||
|
@ -29,9 +30,9 @@ var repoRemoveCmd = &cli.Command{
|
|||
Action: repoRemove,
|
||||
}
|
||||
|
||||
func repoRemove(c *cli.Context) error {
|
||||
func repoRemove(ctx context.Context, c *cli.Command) error {
|
||||
repoIDOrFullName := c.Args().First()
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,10 +15,11 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -33,8 +34,8 @@ var repoSyncCmd = &cli.Command{
|
|||
}
|
||||
|
||||
// TODO: remove this and add an option to the list cmd as we do not store the remote repo list anymore
|
||||
func repoSync(c *cli.Context) error {
|
||||
client, err := internal.NewClient(c)
|
||||
func repoSync(ctx context.Context, c *cli.Command) error {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,10 +15,11 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
|
@ -61,9 +62,9 @@ var repoUpdateCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func repoUpdate(c *cli.Context) error {
|
||||
func repoUpdate(ctx context.Context, c *cli.Command) error {
|
||||
repoIDOrFullName := c.Args().First()
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -78,7 +79,7 @@ func repoUpdate(c *cli.Context) error {
|
|||
timeout = c.Duration("timeout")
|
||||
trusted = c.Bool("trusted")
|
||||
gated = c.Bool("gated")
|
||||
pipelineCounter = c.Int("pipeline-counter")
|
||||
pipelineCounter = int(c.Int("pipeline-counter"))
|
||||
unsafe = c.Bool("unsafe")
|
||||
)
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
|
@ -29,7 +29,7 @@ import (
|
|||
var Command = &cli.Command{
|
||||
Name: "secret",
|
||||
Usage: "manage secrets",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
secretCreateCmd,
|
||||
secretDeleteCmd,
|
||||
secretUpdateCmd,
|
||||
|
@ -38,7 +38,7 @@ var Command = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func parseTargetArgs(client woodpecker.Client, c *cli.Context) (global bool, orgID, repoID int64, err error) {
|
||||
func parseTargetArgs(client woodpecker.Client, c *cli.Command) (global bool, orgID, repoID int64, err error) {
|
||||
if c.Bool("global") {
|
||||
return true, -1, -1, nil
|
||||
}
|
||||
|
|
|
@ -15,10 +15,11 @@
|
|||
package secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -56,8 +57,8 @@ var secretCreateCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func secretCreate(c *cli.Context) error {
|
||||
client, err := internal.NewClient(c)
|
||||
func secretCreate(ctx context.Context, c *cli.Command) error {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,10 +15,12 @@
|
|||
package secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"os"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -45,12 +47,17 @@ var secretInfoCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func secretInfo(c *cli.Context) error {
|
||||
func secretInfo(ctx context.Context, c *cli.Command) error {
|
||||
var (
|
||||
secretName = c.String("name")
|
||||
format = c.String("format") + "\n"
|
||||
)
|
||||
client, err := internal.NewClient(c)
|
||||
|
||||
if secretName == "" {
|
||||
return fmt.Errorf("secret name is missing")
|
||||
}
|
||||
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,11 +15,12 @@
|
|||
package secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"html/template"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -42,10 +43,10 @@ var secretListCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func secretList(c *cli.Context) error {
|
||||
func secretList(ctx context.Context, c *cli.Command) error {
|
||||
format := c.String("format") + "\n"
|
||||
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
package secret
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"context"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -40,10 +42,10 @@ var secretDeleteCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func secretDelete(c *cli.Context) error {
|
||||
func secretDelete(ctx context.Context, c *cli.Command) error {
|
||||
secretName := c.String("name")
|
||||
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,10 +15,11 @@
|
|||
package secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -56,8 +57,8 @@ var secretUpdateCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func secretUpdate(c *cli.Context) error {
|
||||
client, err := internal.NewClient(c)
|
||||
func secretUpdate(ctx context.Context, c *cli.Command) error {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
package setup
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal/config"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/setup/ui"
|
||||
|
@ -15,7 +16,6 @@ import (
|
|||
var Command = &cli.Command{
|
||||
Name: "setup",
|
||||
Usage: "setup the woodpecker-cli for the first time",
|
||||
Args: true,
|
||||
ArgsUsage: "[server]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
|
@ -30,8 +30,8 @@ var Command = &cli.Command{
|
|||
Action: setup,
|
||||
}
|
||||
|
||||
func setup(c *cli.Context) error {
|
||||
_config, err := config.Get(c, c.String("config"))
|
||||
func setup(ctx context.Context, c *cli.Command) error {
|
||||
_config, err := config.Get(ctx, c, c.String("config"))
|
||||
if err != nil {
|
||||
return err
|
||||
} else if _config != nil {
|
||||
|
@ -68,7 +68,7 @@ func setup(c *cli.Context) error {
|
|||
|
||||
token := c.String("token")
|
||||
if token == "" {
|
||||
token, err = receiveTokenFromUI(c.Context, serverURL)
|
||||
token, err = receiveTokenFromUI(ctx, serverURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ func setup(c *cli.Context) error {
|
|||
}
|
||||
}
|
||||
|
||||
err = config.Save(c, c.String("config"), &config.Config{
|
||||
err = config.Save(ctx, c, c.String("config"), &config.Config{
|
||||
ServerURL: serverURL,
|
||||
Token: token,
|
||||
LogLevel: "info",
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
package update
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// Command exports the update command.
|
||||
|
@ -22,10 +23,10 @@ var Command = &cli.Command{
|
|||
Action: update,
|
||||
}
|
||||
|
||||
func update(c *cli.Context) error {
|
||||
func update(ctx context.Context, c *cli.Command) error {
|
||||
log.Info().Msg("Checking for updates ...")
|
||||
|
||||
newVersion, err := CheckForUpdate(c.Context, c.Bool("force"))
|
||||
newVersion, err := CheckForUpdate(ctx, c.Bool("force"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -38,7 +39,7 @@ func update(c *cli.Context) error {
|
|||
log.Info().Msgf("New version %s is available! Updating ...", newVersion.Version)
|
||||
|
||||
var tarFilePath string
|
||||
tarFilePath, err = downloadNewVersion(c.Context, newVersion.AssetURL)
|
||||
tarFilePath, err = downloadNewVersion(ctx, newVersion.AssetURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,14 +15,14 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// Command exports the user command set.
|
||||
var Command = &cli.Command{
|
||||
Name: "user",
|
||||
Usage: "manage users",
|
||||
Subcommands: []*cli.Command{
|
||||
Commands: []*cli.Command{
|
||||
userListCmd,
|
||||
userInfoCmd,
|
||||
userAddCmd,
|
||||
|
|
|
@ -15,9 +15,10 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
|
@ -30,10 +31,10 @@ var userAddCmd = &cli.Command{
|
|||
Action: userAdd,
|
||||
}
|
||||
|
||||
func userAdd(c *cli.Context) error {
|
||||
func userAdd(ctx context.Context, c *cli.Command) error {
|
||||
login := c.Args().First()
|
||||
|
||||
client, err := internal.NewClient(c)
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,11 +15,12 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -33,8 +34,8 @@ var userInfoCmd = &cli.Command{
|
|||
Flags: []cli.Flag{common.FormatFlag(tmplUserInfo)},
|
||||
}
|
||||
|
||||
func userInfo(c *cli.Context) error {
|
||||
client, err := internal.NewClient(c)
|
||||
func userInfo(ctx context.Context, c *cli.Command) error {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,10 +15,11 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -32,8 +33,8 @@ var userListCmd = &cli.Command{
|
|||
Flags: []cli.Flag{common.FormatFlag(tmplUserList)},
|
||||
}
|
||||
|
||||
func userList(c *cli.Context) error {
|
||||
client, err := internal.NewClient(c)
|
||||
func userList(ctx context.Context, c *cli.Command) error {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue