mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-05-11 10:42:40 +00:00
Compare commits
6 commits
908f37fd9e
...
d4342b7240
Author | SHA1 | Date | |
---|---|---|---|
d4342b7240 | |||
2d66cfcce2 | |||
263d759896 | |||
b3e4c43f8d | |||
fbef1004b7 | |||
bb49ff957a |
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -13,7 +13,7 @@
|
|||
*.so
|
||||
*.dylib
|
||||
vendor/
|
||||
__debug_bin
|
||||
__debug_bin*
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
# don't lint build output (make sure it's set to your correct build folder name)
|
||||
dist
|
||||
coverage/
|
||||
package.json
|
||||
tsconfig.eslint.json
|
||||
tsconfig.json
|
||||
src/assets/locales/
|
||||
components.d.ts
|
161
web/.eslintrc.js
161
web/.eslintrc.js
|
@ -1,161 +0,0 @@
|
|||
// cSpell:ignore TSES
|
||||
// @ts-check
|
||||
/** @type {import('@typescript-eslint/experimental-utils').TSESLint.Linter.Config} */
|
||||
|
||||
/* eslint-env node */
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
},
|
||||
reportUnusedDisableDirectives: true,
|
||||
|
||||
parser: 'vue-eslint-parser',
|
||||
parserOptions: {
|
||||
project: ['./tsconfig.eslint.json'],
|
||||
tsconfigRootDir: __dirname,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore see https://github.com/vuejs/vue-eslint-parser#parseroptionsparser
|
||||
parser: '@typescript-eslint/parser',
|
||||
sourceType: 'module',
|
||||
extraFileExtensions: ['.vue'],
|
||||
},
|
||||
|
||||
plugins: ['@typescript-eslint', 'import', 'simple-import-sort'],
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'airbnb-base',
|
||||
'airbnb-typescript/base',
|
||||
'plugin:import/errors',
|
||||
'plugin:import/warnings',
|
||||
'plugin:import/typescript',
|
||||
'plugin:promise/recommended',
|
||||
'plugin:vue/vue3-recommended',
|
||||
'plugin:prettier/recommended',
|
||||
'plugin:vue-scoped-css/recommended',
|
||||
],
|
||||
|
||||
rules: {
|
||||
// enable scope analysis rules
|
||||
'no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'error',
|
||||
'no-use-before-define': 'off',
|
||||
'@typescript-eslint/no-use-before-define': 'error',
|
||||
'no-shadow': 'off',
|
||||
'@typescript-eslint/no-shadow': 'error',
|
||||
'no-redeclare': 'off',
|
||||
'@typescript-eslint/no-redeclare': 'error',
|
||||
|
||||
// make typescript eslint rules even more strict
|
||||
'@typescript-eslint/no-explicit-any': 'error',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-non-null-assertion': 'error',
|
||||
// SOURCE: https://github.com/iamturns/eslint-config-airbnb-typescript/blob/4aec5702be5b4e74e0e2f40bc78b4bc961681de1/lib/shared.js#L41
|
||||
'@typescript-eslint/naming-convention': [
|
||||
'error',
|
||||
// Allow camelCase variables (23.2), PascalCase variables (23.8), and UPPER_CASE variables (23.10)
|
||||
{
|
||||
selector: 'variable',
|
||||
format: ['camelCase', 'PascalCase', 'UPPER_CASE'],
|
||||
leadingUnderscore: 'allow',
|
||||
},
|
||||
// Allow camelCase functions (23.2), and PascalCase functions (23.8)
|
||||
{
|
||||
selector: 'function',
|
||||
format: ['camelCase', 'PascalCase'],
|
||||
},
|
||||
// Airbnb recommends PascalCase for classes (23.3), and although Airbnb does not make TypeScript recommendations, we are assuming this rule would similarly apply to anything "type like", including interfaces, type aliases, and enums
|
||||
{
|
||||
selector: 'typeLike',
|
||||
format: ['PascalCase'],
|
||||
},
|
||||
],
|
||||
|
||||
'import/no-unresolved': 'off', // disable as this is handled by tsc itself
|
||||
'import/first': 'error',
|
||||
'import/newline-after-import': 'error',
|
||||
'import/no-cycle': 'error',
|
||||
'import/no-relative-parent-imports': 'error',
|
||||
'import/no-duplicates': 'error',
|
||||
'import/no-extraneous-dependencies': 'error',
|
||||
'import/extensions': 'off',
|
||||
'import/prefer-default-export': 'off',
|
||||
|
||||
'simple-import-sort/imports': 'error',
|
||||
'simple-import-sort/exports': 'error',
|
||||
|
||||
'promise/prefer-await-to-then': 'error',
|
||||
'promise/prefer-await-to-callbacks': 'error',
|
||||
|
||||
'no-underscore-dangle': 'off',
|
||||
'no-else-return': ['error', { allowElseIf: false }],
|
||||
'no-return-assign': ['error', 'always'],
|
||||
'no-return-await': 'error',
|
||||
'no-useless-return': 'error',
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
patterns: ['src', 'dist'],
|
||||
},
|
||||
],
|
||||
'no-console': 'warn',
|
||||
'no-useless-concat': 'error',
|
||||
'prefer-const': 'error',
|
||||
'spaced-comment': ['error', 'always'],
|
||||
'object-shorthand': ['error', 'always'],
|
||||
'no-useless-rename': 'error',
|
||||
eqeqeq: 'error',
|
||||
|
||||
'vue/attribute-hyphenation': 'error',
|
||||
// enable in accordance with https://github.com/prettier/eslint-config-prettier#vuehtml-self-closing
|
||||
'vue/html-self-closing': [
|
||||
'error',
|
||||
{
|
||||
html: {
|
||||
void: 'any',
|
||||
},
|
||||
},
|
||||
],
|
||||
'vue/no-static-inline-styles': 'error',
|
||||
'vue/v-on-function-call': 'error',
|
||||
'vue/no-useless-v-bind': 'error',
|
||||
'vue/no-useless-mustaches': 'error',
|
||||
'vue/no-useless-concat': 'error',
|
||||
'vue/no-boolean-default': 'error',
|
||||
'vue/html-button-has-type': 'error',
|
||||
'vue/component-name-in-template-casing': 'error',
|
||||
'vue/match-component-file-name': [
|
||||
'error',
|
||||
{
|
||||
extensions: ['vue'],
|
||||
shouldMatchCase: true,
|
||||
},
|
||||
],
|
||||
'vue/require-name-property': 'error',
|
||||
'vue/v-for-delimiter-style': 'error',
|
||||
'vue/no-empty-component-block': 'error',
|
||||
'vue/no-duplicate-attr-inheritance': 'error',
|
||||
'vue/no-unused-properties': [
|
||||
'error',
|
||||
{
|
||||
groups: ['props', 'data', 'computed', 'methods', 'setup'],
|
||||
},
|
||||
],
|
||||
'vue/new-line-between-multi-line-property': 'error',
|
||||
'vue/padding-line-between-blocks': 'error',
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'vue/no-reserved-component-names': 'off',
|
||||
|
||||
// css rules
|
||||
'vue-scoped-css/no-unused-selector': 'error',
|
||||
'vue-scoped-css/no-parsing-error': 'error',
|
||||
'vue-scoped-css/require-scoped': 'error',
|
||||
|
||||
// enable in accordance with https://github.com/prettier/eslint-config-prettier#curly
|
||||
curly: ['error', 'all'],
|
||||
|
||||
// risky because of https://github.com/prettier/eslint-plugin-prettier#arrow-body-style-and-prefer-arrow-callback-issue
|
||||
'arrow-body-style': 'error',
|
||||
'prefer-arrow-callback': 'error',
|
||||
},
|
||||
};
|
199
web/eslint.config.js
Normal file
199
web/eslint.config.js
Normal file
|
@ -0,0 +1,199 @@
|
|||
// cSpell:ignore TSES
|
||||
// @ts-check
|
||||
|
||||
import simpleImportSort from 'eslint-plugin-simple-import-sort';
|
||||
//import eslintImport from 'eslint-plugin-import';
|
||||
//import eslintTypescript from '@typescript-eslint/eslint-plugin';
|
||||
import vueParser from 'vue-eslint-parser';
|
||||
import globals from 'globals';
|
||||
import js from '@eslint/js';
|
||||
import airBnbBase from 'eslint-config-airbnb-base';
|
||||
//import airBnbTS from 'eslint-config-airbnb-typescript/base';
|
||||
import eslintVue from 'eslint-plugin-vue';
|
||||
import eslintVueScopedCSS from 'eslint-plugin-vue-scoped-css';
|
||||
import eslintPrettier from 'eslint-plugin-prettier/recommended';
|
||||
import eslintPromise from 'eslint-plugin-promise';
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
// TODO check eslint-env
|
||||
/* eslint-env node */
|
||||
|
||||
export default tseslint.config(
|
||||
{
|
||||
ignores: [
|
||||
'dist/**',
|
||||
'package.json',
|
||||
'tsconfig.eslint.json',
|
||||
'tsconfig.json',
|
||||
'src/assets/locales/**',
|
||||
'src/assets/dayjsLocales/**',
|
||||
'components.d.ts',
|
||||
],
|
||||
},
|
||||
js.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
|
||||
//airBnbBase,
|
||||
//airBnbTS,
|
||||
//eslintImport, used these 'plugin:import/errors', 'plugin:import/warnings', 'plugin:import/typescript'
|
||||
...eslintVue.configs['flat/recommended'],
|
||||
...eslintVueScopedCSS.configs['flat/recommended'],
|
||||
eslintPrettier,
|
||||
//eslintPromise.configs.recommended,
|
||||
{
|
||||
files: ['**/*.js', '**/*.ts', '**/*.vue'],
|
||||
|
||||
languageOptions: {
|
||||
parser: vueParser,
|
||||
parserOptions: {
|
||||
project: ['./tsconfig.eslint.json'],
|
||||
tsconfigRootDir: path.dirname(fileURLToPath(import.meta.url)),
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore see https://github.com/vuejs/vue-eslint-parser#parseroptionsparser
|
||||
parser: tseslint.parser,
|
||||
extraFileExtensions: ['.vue', '.json'],
|
||||
},
|
||||
sourceType: 'module',
|
||||
globals: globals.browser,
|
||||
},
|
||||
|
||||
linterOptions: {
|
||||
reportUnusedDisableDirectives: 'warn',
|
||||
},
|
||||
|
||||
plugins: {
|
||||
//TODO 'import': eslintImport,
|
||||
'simple-import-sort': simpleImportSort,
|
||||
//TODO promise: eslintPromise,
|
||||
vue: eslintVue,
|
||||
'vue-scoped-css': eslintVueScopedCSS,
|
||||
},
|
||||
|
||||
rules: {
|
||||
// enable scope analysis rules
|
||||
'no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'error',
|
||||
'no-use-before-define': 'off',
|
||||
'@typescript-eslint/no-use-before-define': 'error',
|
||||
'no-shadow': 'off',
|
||||
'@typescript-eslint/no-shadow': 'error',
|
||||
'no-redeclare': 'off',
|
||||
'@typescript-eslint/no-redeclare': 'error',
|
||||
|
||||
// make typescript eslint rules even more strict
|
||||
'@typescript-eslint/no-explicit-any': 'error',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-non-null-assertion': 'error',
|
||||
// SOURCE: https://github.com/iamturns/eslint-config-airbnb-typescript/blob/4aec5702be5b4e74e0e2f40bc78b4bc961681de1/lib/shared.js#L41
|
||||
'@typescript-eslint/naming-convention': [
|
||||
'error',
|
||||
// Allow camelCase variables (23.2), PascalCase variables (23.8), and UPPER_CASE variables (23.10)
|
||||
{
|
||||
selector: 'variable',
|
||||
format: ['camelCase', 'PascalCase', 'UPPER_CASE'],
|
||||
leadingUnderscore: 'allow',
|
||||
},
|
||||
// Allow camelCase functions (23.2), and PascalCase functions (23.8)
|
||||
{
|
||||
selector: 'function',
|
||||
format: ['camelCase', 'PascalCase'],
|
||||
},
|
||||
// Airbnb recommends PascalCase for classes (23.3), and although Airbnb does not make TypeScript recommendations, we are assuming this rule would similarly apply to anything "type like", including interfaces, type aliases, and enums
|
||||
{
|
||||
selector: 'typeLike',
|
||||
format: ['PascalCase'],
|
||||
},
|
||||
],
|
||||
|
||||
//'import/no-unresolved': 'off', // disable as this is handled by tsc itself
|
||||
//'import/first': 'error',
|
||||
//'import/newline-after-import': 'error',
|
||||
//'import/no-cycle': 'error',
|
||||
//'import/no-relative-parent-imports': 'error',
|
||||
//'import/no-duplicates': 'error',
|
||||
//'import/no-extraneous-dependencies': 'error',
|
||||
//'import/extensions': 'off',
|
||||
//'import/prefer-default-export': 'off',
|
||||
|
||||
'simple-import-sort/imports': 'error',
|
||||
'simple-import-sort/exports': 'error',
|
||||
|
||||
//'promise/prefer-await-to-then': 'error',
|
||||
//'promise/prefer-await-to-callbacks': 'error',
|
||||
|
||||
'no-underscore-dangle': 'off',
|
||||
'no-else-return': ['error', { allowElseIf: false }],
|
||||
'no-return-assign': ['error', 'always'],
|
||||
'no-return-await': 'error',
|
||||
'no-useless-return': 'error',
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
patterns: ['src', 'dist'],
|
||||
},
|
||||
],
|
||||
'no-console': 'warn',
|
||||
'no-useless-concat': 'error',
|
||||
'prefer-const': 'error',
|
||||
'spaced-comment': ['error', 'always'],
|
||||
'object-shorthand': ['error', 'always'],
|
||||
'no-useless-rename': 'error',
|
||||
eqeqeq: 'error',
|
||||
|
||||
'vue/attribute-hyphenation': 'error',
|
||||
// enable in accordance with https://github.com/prettier/eslint-config-prettier#vuehtml-self-closing
|
||||
'vue/html-self-closing': [
|
||||
'error',
|
||||
{
|
||||
html: {
|
||||
void: 'any',
|
||||
},
|
||||
},
|
||||
],
|
||||
'vue/no-static-inline-styles': 'error',
|
||||
'vue/v-on-function-call': 'error',
|
||||
'vue/no-useless-v-bind': 'error',
|
||||
'vue/no-useless-mustaches': 'error',
|
||||
'vue/no-useless-concat': 'error',
|
||||
'vue/no-boolean-default': 'error',
|
||||
'vue/html-button-has-type': 'error',
|
||||
'vue/component-name-in-template-casing': 'error',
|
||||
'vue/match-component-file-name': [
|
||||
'error',
|
||||
{
|
||||
extensions: ['vue'],
|
||||
shouldMatchCase: true,
|
||||
},
|
||||
],
|
||||
'vue/require-name-property': 'error',
|
||||
'vue/v-for-delimiter-style': 'error',
|
||||
'vue/no-empty-component-block': 'error',
|
||||
'vue/no-duplicate-attr-inheritance': 'error',
|
||||
'vue/no-unused-properties': [
|
||||
'error',
|
||||
{
|
||||
groups: ['props', 'data', 'computed', 'methods', 'setup'],
|
||||
},
|
||||
],
|
||||
'vue/new-line-between-multi-line-property': 'error',
|
||||
'vue/padding-line-between-blocks': 'error',
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'vue/no-reserved-component-names': 'off',
|
||||
|
||||
// css rules
|
||||
'vue-scoped-css/no-unused-selector': 'error',
|
||||
'vue-scoped-css/no-parsing-error': 'error',
|
||||
'vue-scoped-css/require-scoped': 'error',
|
||||
|
||||
// enable in accordance with https://github.com/prettier/eslint-config-prettier#curly
|
||||
curly: ['error', 'all'],
|
||||
|
||||
// risky because of https://github.com/prettier/eslint-plugin-prettier#arrow-body-style-and-prefer-arrow-callback-issue
|
||||
'arrow-body-style': 'error',
|
||||
'prefer-arrow-callback': 'error',
|
||||
},
|
||||
},
|
||||
);
|
|
@ -3,6 +3,7 @@
|
|||
"author": "Woodpecker CI",
|
||||
"version": "0.0.0",
|
||||
"license": "Apache-2.0",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
|
@ -10,7 +11,7 @@
|
|||
"start": "vite",
|
||||
"build": "vite build --base=/BASE_PATH",
|
||||
"serve": "vite preview",
|
||||
"lint": "eslint --max-warnings 0 --ext .js,.ts,.vue,.json .",
|
||||
"lint": "eslint --max-warnings 0 .",
|
||||
"format": "prettier --write .",
|
||||
"format:check": "prettier -c .",
|
||||
"typecheck": "vue-tsc --noEmit",
|
||||
|
@ -34,6 +35,7 @@
|
|||
"vue-router": "^4.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.0.0",
|
||||
"@iconify/json": "^2.2.171",
|
||||
"@types/lodash": "^4.14.202",
|
||||
"@types/node": "^20.11.5",
|
||||
|
@ -44,7 +46,7 @@
|
|||
"@typescript-eslint/parser": "^7.0.0",
|
||||
"@vitejs/plugin-vue": "^5.0.3",
|
||||
"@vue/compiler-sfc": "^3.4.15",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint": "^9.0.0",
|
||||
"eslint-config-airbnb-base": "^15.0.0",
|
||||
"eslint-config-airbnb-typescript": "^18.0.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
|
@ -54,10 +56,12 @@
|
|||
"eslint-plugin-simple-import-sort": "^12.0.0",
|
||||
"eslint-plugin-vue": "^9.20.1",
|
||||
"eslint-plugin-vue-scoped-css": "^2.7.2",
|
||||
"globals": "^15.0.0",
|
||||
"prettier": "^3.2.4",
|
||||
"replace-in-file": "^7.1.0",
|
||||
"tinycolor2": "^1.6.0",
|
||||
"typescript": "5.4.5",
|
||||
"typescript-eslint": "^7.6.0",
|
||||
"unplugin-icons": "^0.18.2",
|
||||
"unplugin-vue-components": "^0.26.0",
|
||||
"vite": "^5.0.12",
|
||||
|
|
5494
web/pnpm-lock.yaml
5494
web/pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"include": [".eslintrc.js", "jest.config.ts", "vite.config.ts", "windi.config.ts", "src", "test", "components.d.ts"]
|
||||
"include": ["eslint.config.js", ".eslintrc.js", "jest.config.ts", "vite.config.ts", "windi.config.ts", "src", "test", "components.d.ts"]
|
||||
}
|
||||
|
|
50
woodpecker-go/woodpecker/agent.go
Normal file
50
woodpecker-go/woodpecker/agent.go
Normal file
|
@ -0,0 +1,50 @@
|
|||
package woodpecker
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
pathAgents = "%s/api/agents"
|
||||
pathAgent = "%s/api/agents/%d"
|
||||
pathAgentTasks = "%s/api/agents/%d/tasks"
|
||||
)
|
||||
|
||||
// AgentCreate creates a new agent.
|
||||
func (c *client) AgentCreate(in *Agent) (*Agent, error) {
|
||||
out := new(Agent)
|
||||
uri := fmt.Sprintf(pathAgents, c.addr)
|
||||
return out, c.post(uri, in, out)
|
||||
}
|
||||
|
||||
// AgentList returns a list of all registered agents.
|
||||
func (c *client) AgentList() ([]*Agent, error) {
|
||||
out := make([]*Agent, 0, 5)
|
||||
uri := fmt.Sprintf(pathAgents, c.addr)
|
||||
return out, c.get(uri, &out)
|
||||
}
|
||||
|
||||
// Agent returns an agent by id.
|
||||
func (c *client) Agent(agentID int64) (*Agent, error) {
|
||||
out := new(Agent)
|
||||
uri := fmt.Sprintf(pathAgent, c.addr, agentID)
|
||||
return out, c.get(uri, out)
|
||||
}
|
||||
|
||||
// AgentUpdate updates the agent with the provided Agent struct.
|
||||
func (c *client) AgentUpdate(in *Agent) (*Agent, error) {
|
||||
out := new(Agent)
|
||||
uri := fmt.Sprintf(pathAgent, c.addr, in.ID)
|
||||
return out, c.patch(uri, in, out)
|
||||
}
|
||||
|
||||
// AgentDelete deletes the agent with the given id.
|
||||
func (c *client) AgentDelete(agentID int64) error {
|
||||
uri := fmt.Sprintf(pathAgent, c.addr, agentID)
|
||||
return c.delete(uri)
|
||||
}
|
||||
|
||||
// AgentTasksList returns a list of all tasks for the agent with the given id.
|
||||
func (c *client) AgentTasksList(agentID int64) ([]*Task, error) {
|
||||
out := make([]*Task, 0, 5)
|
||||
uri := fmt.Sprintf(pathAgentTasks, c.addr, agentID)
|
||||
return out, c.get(uri, &out)
|
||||
}
|
511
woodpecker-go/woodpecker/agent_test.go
Normal file
511
woodpecker-go/woodpecker/agent_test.go
Normal file
|
@ -0,0 +1,511 @@
|
|||
package woodpecker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestClient_AgentCreate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
handler http.HandlerFunc
|
||||
input *Agent
|
||||
expected *Agent
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
_, err := fmt.Fprint(w, `{"id":1,"name":"new_agent","backend":"local","capacity":2,"version":"1.0.0"}`)
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
input: &Agent{Name: "new_agent", Backend: "local", Capacity: 2, Version: "1.0.0"},
|
||||
expected: &Agent{ID: 1, Name: "new_agent", Backend: "local", Capacity: 2, Version: "1.0.0"},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "invalid input",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
},
|
||||
input: &Agent{},
|
||||
expected: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "server error",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
},
|
||||
input: &Agent{Name: "new_agent", Backend: "local", Capacity: 2, Version: "1.0.0"},
|
||||
expected: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ts := httptest.NewServer(tt.handler)
|
||||
defer ts.Close()
|
||||
|
||||
client := NewClient(ts.URL, http.DefaultClient)
|
||||
agent, err := client.AgentCreate(tt.input)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, agent, tt.expected)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_AgentList(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
handler http.HandlerFunc
|
||||
expected []*Agent
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
handler: func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err := fmt.Fprint(w, `[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "agent-1",
|
||||
"backend": "local",
|
||||
"capacity": 2,
|
||||
"version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "agent-2",
|
||||
"backend": "kubernetes",
|
||||
"capacity": 4,
|
||||
"version": "1.0.0"
|
||||
}
|
||||
]`)
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
expected: []*Agent{
|
||||
{
|
||||
ID: 1,
|
||||
Name: "agent-1",
|
||||
Backend: "local",
|
||||
Capacity: 2,
|
||||
Version: "1.0.0",
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
Name: "agent-2",
|
||||
Backend: "kubernetes",
|
||||
Capacity: 4,
|
||||
Version: "1.0.0",
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "server error",
|
||||
handler: func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
},
|
||||
expected: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid response",
|
||||
handler: func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err := fmt.Fprint(w, `invalid json`)
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
expected: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ts := httptest.NewServer(tt.handler)
|
||||
defer ts.Close()
|
||||
|
||||
client := NewClient(ts.URL, http.DefaultClient)
|
||||
agents, err := client.AgentList()
|
||||
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.expected, agents)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_Agent(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
handler http.HandlerFunc
|
||||
agentID int64
|
||||
expected *Agent
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err := fmt.Fprint(w, `{"id":1,"name":"agent-1","backend":"local","capacity":2,"version":"1.0.0"}`)
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
agentID: 1,
|
||||
expected: &Agent{ID: 1, Name: "agent-1", Backend: "local", Capacity: 2, Version: "1.0.0"},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "not found",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
},
|
||||
agentID: 999,
|
||||
expected: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "server error",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
},
|
||||
agentID: 1,
|
||||
expected: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid response",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err := fmt.Fprint(w, `invalid json`)
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
agentID: 1,
|
||||
expected: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ts := httptest.NewServer(tt.handler)
|
||||
defer ts.Close()
|
||||
|
||||
client := NewClient(ts.URL, http.DefaultClient)
|
||||
agent, err := client.Agent(tt.agentID)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.expected, agent)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_AgentUpdate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
handler http.HandlerFunc
|
||||
input *Agent
|
||||
expected *Agent
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPatch {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err := fmt.Fprint(w, `{"id":1,"name":"updated_agent"}`)
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
input: &Agent{ID: 1, Name: "existing_agent"},
|
||||
expected: &Agent{ID: 1, Name: "updated_agent"},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "not found",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPatch {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
},
|
||||
input: &Agent{ID: 999, Name: "nonexistent_agent"},
|
||||
expected: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid input",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPatch {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
},
|
||||
input: &Agent{},
|
||||
expected: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "server error",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPatch {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
},
|
||||
input: &Agent{ID: 1, Name: "existing_agent"},
|
||||
expected: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ts := httptest.NewServer(tt.handler)
|
||||
defer ts.Close()
|
||||
|
||||
client := NewClient(ts.URL, http.DefaultClient)
|
||||
agent, err := client.AgentUpdate(tt.input)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, agent, tt.expected)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_AgentDelete(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
handler http.HandlerFunc
|
||||
agentID int64
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodDelete {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
},
|
||||
agentID: 1,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "not found",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodDelete {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
},
|
||||
agentID: 999,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "server error",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodDelete {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
},
|
||||
agentID: 1,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ts := httptest.NewServer(tt.handler)
|
||||
defer ts.Close()
|
||||
|
||||
client := NewClient(ts.URL, http.DefaultClient)
|
||||
err := client.AgentDelete(tt.agentID)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_AgentTasksList(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
handler http.HandlerFunc
|
||||
agentID int64
|
||||
expected []*Task
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err := fmt.Fprint(w, `[
|
||||
{
|
||||
"id": "4696",
|
||||
"data": "",
|
||||
"labels": {
|
||||
"platform": "linux/amd64",
|
||||
"repo": "woodpecker-ci/woodpecker"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "4697",
|
||||
"data": "",
|
||||
"labels": {
|
||||
"platform": "linux/arm64",
|
||||
"repo": "woodpecker-ci/woodpecker"
|
||||
}
|
||||
}
|
||||
]`)
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
agentID: 1,
|
||||
expected: []*Task{
|
||||
{
|
||||
ID: "4696",
|
||||
Data: []byte{},
|
||||
Labels: map[string]string{
|
||||
"platform": "linux/amd64",
|
||||
"repo": "woodpecker-ci/woodpecker",
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "4697",
|
||||
Data: []byte{},
|
||||
Labels: map[string]string{
|
||||
"platform": "linux/arm64",
|
||||
"repo": "woodpecker-ci/woodpecker",
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "not found",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
},
|
||||
agentID: 999,
|
||||
expected: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "server error",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
},
|
||||
agentID: 1,
|
||||
expected: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid response",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err := fmt.Fprint(w, `invalid json`)
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
agentID: 1,
|
||||
expected: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ts := httptest.NewServer(tt.handler)
|
||||
defer ts.Close()
|
||||
|
||||
client := NewClient(ts.URL, http.DefaultClient)
|
||||
tasks, err := client.AgentTasksList(tt.agentID)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.expected, tasks)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -26,41 +26,8 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
pathSelf = "%s/api/user"
|
||||
pathRepos = "%s/api/user/repos"
|
||||
pathRepoPost = "%s/api/repos?forge_remote_id=%d"
|
||||
pathRepo = "%s/api/repos/%d"
|
||||
pathRepoLookup = "%s/api/repos/lookup/%s"
|
||||
pathRepoMove = "%s/api/repos/%d/move?to=%s"
|
||||
pathChown = "%s/api/repos/%d/chown"
|
||||
pathRepair = "%s/api/repos/%d/repair"
|
||||
pathPipelines = "%s/api/repos/%d/pipelines"
|
||||
pathPipeline = "%s/api/repos/%d/pipelines/%v"
|
||||
pathPipelineLogs = "%s/api/repos/%d/logs/%d"
|
||||
pathStepLogs = "%s/api/repos/%d/logs/%d/%d"
|
||||
pathApprove = "%s/api/repos/%d/pipelines/%d/approve"
|
||||
pathDecline = "%s/api/repos/%d/pipelines/%d/decline"
|
||||
pathStop = "%s/api/repos/%d/pipelines/%d/cancel"
|
||||
pathRepoSecrets = "%s/api/repos/%d/secrets"
|
||||
pathRepoSecret = "%s/api/repos/%d/secrets/%s"
|
||||
pathRepoRegistries = "%s/api/repos/%d/registry"
|
||||
pathRepoRegistry = "%s/api/repos/%d/registry/%s"
|
||||
pathRepoCrons = "%s/api/repos/%d/cron"
|
||||
pathRepoCron = "%s/api/repos/%d/cron/%d"
|
||||
pathOrg = "%s/api/orgs/%d"
|
||||
pathOrgLookup = "%s/api/orgs/lookup/%s"
|
||||
pathOrgSecrets = "%s/api/orgs/%d/secrets"
|
||||
pathOrgSecret = "%s/api/orgs/%d/secrets/%s"
|
||||
pathGlobalSecrets = "%s/api/secrets"
|
||||
pathGlobalSecret = "%s/api/secrets/%s"
|
||||
pathUsers = "%s/api/users"
|
||||
pathUser = "%s/api/users/%s"
|
||||
pathPipelineQueue = "%s/api/pipelines"
|
||||
pathQueue = "%s/api/queue"
|
||||
pathLogLevel = "%s/api/log-level"
|
||||
pathAgents = "%s/api/agents"
|
||||
pathAgent = "%s/api/agents/%d"
|
||||
pathAgentTasks = "%s/api/agents/%d/tasks"
|
||||
pathLogLevel = "%s/api/log-level"
|
||||
|
||||
// TODO: implement endpoints
|
||||
// pathFeed = "%s/api/user/feed"
|
||||
// pathVersion = "%s/version"
|
||||
|
@ -91,422 +58,6 @@ func (c *client) SetAddress(addr string) {
|
|||
c.addr = addr
|
||||
}
|
||||
|
||||
// Self returns the currently authenticated user.
|
||||
func (c *client) Self() (*User, error) {
|
||||
out := new(User)
|
||||
uri := fmt.Sprintf(pathSelf, c.addr)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// User returns a user by login.
|
||||
func (c *client) User(login string) (*User, error) {
|
||||
out := new(User)
|
||||
uri := fmt.Sprintf(pathUser, c.addr, login)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// UserList returns a list of all registered users.
|
||||
func (c *client) UserList() ([]*User, error) {
|
||||
var out []*User
|
||||
uri := fmt.Sprintf(pathUsers, c.addr)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// UserPost creates a new user account.
|
||||
func (c *client) UserPost(in *User) (*User, error) {
|
||||
out := new(User)
|
||||
uri := fmt.Sprintf(pathUsers, c.addr)
|
||||
err := c.post(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// UserPatch updates a user account.
|
||||
func (c *client) UserPatch(in *User) (*User, error) {
|
||||
out := new(User)
|
||||
uri := fmt.Sprintf(pathUser, c.addr, in.Login)
|
||||
err := c.patch(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// UserDel deletes a user account.
|
||||
func (c *client) UserDel(login string) error {
|
||||
uri := fmt.Sprintf(pathUser, c.addr, login)
|
||||
err := c.delete(uri)
|
||||
return err
|
||||
}
|
||||
|
||||
// Repo returns a repository by id.
|
||||
func (c *client) Repo(repoID int64) (*Repo, error) {
|
||||
out := new(Repo)
|
||||
uri := fmt.Sprintf(pathRepo, c.addr, repoID)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// RepoLookup returns a repository by name.
|
||||
func (c *client) RepoLookup(fullName string) (*Repo, error) {
|
||||
out := new(Repo)
|
||||
uri := fmt.Sprintf(pathRepoLookup, c.addr, fullName)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// RepoList returns a list of all repositories to which
|
||||
// the user has explicit access in the host system.
|
||||
func (c *client) RepoList() ([]*Repo, error) {
|
||||
var out []*Repo
|
||||
uri := fmt.Sprintf(pathRepos, c.addr)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// RepoListOpts returns a list of all repositories to which
|
||||
// the user has explicit access in the host system.
|
||||
func (c *client) RepoListOpts(all bool) ([]*Repo, error) {
|
||||
var out []*Repo
|
||||
uri := fmt.Sprintf(pathRepos+"?all=%v", c.addr, all)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// RepoPost activates a repository.
|
||||
func (c *client) RepoPost(forgeRemoteID int64) (*Repo, error) {
|
||||
out := new(Repo)
|
||||
uri := fmt.Sprintf(pathRepoPost, c.addr, forgeRemoteID)
|
||||
err := c.post(uri, nil, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// RepoChown updates a repository owner.
|
||||
func (c *client) RepoChown(repoID int64) (*Repo, error) {
|
||||
out := new(Repo)
|
||||
uri := fmt.Sprintf(pathChown, c.addr, repoID)
|
||||
err := c.post(uri, nil, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// RepoRepair repairs the repository hooks.
|
||||
func (c *client) RepoRepair(repoID int64) error {
|
||||
uri := fmt.Sprintf(pathRepair, c.addr, repoID)
|
||||
return c.post(uri, nil, nil)
|
||||
}
|
||||
|
||||
// RepoPatch updates a repository.
|
||||
func (c *client) RepoPatch(repoID int64, in *RepoPatch) (*Repo, error) {
|
||||
out := new(Repo)
|
||||
uri := fmt.Sprintf(pathRepo, c.addr, repoID)
|
||||
err := c.patch(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// RepoDel deletes a repository.
|
||||
func (c *client) RepoDel(repoID int64) error {
|
||||
uri := fmt.Sprintf(pathRepo, c.addr, repoID)
|
||||
err := c.delete(uri)
|
||||
return err
|
||||
}
|
||||
|
||||
// RepoMove moves a repository
|
||||
func (c *client) RepoMove(repoID int64, newFullName string) error {
|
||||
uri := fmt.Sprintf(pathRepoMove, c.addr, repoID, newFullName)
|
||||
return c.post(uri, nil, nil)
|
||||
}
|
||||
|
||||
// Pipeline returns a repository pipeline by pipeline-id.
|
||||
func (c *client) Pipeline(repoID, pipeline int64) (*Pipeline, error) {
|
||||
out := new(Pipeline)
|
||||
uri := fmt.Sprintf(pathPipeline, c.addr, repoID, pipeline)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// Pipeline returns the latest repository pipeline by branch.
|
||||
func (c *client) PipelineLast(repoID int64, branch string) (*Pipeline, error) {
|
||||
out := new(Pipeline)
|
||||
uri := fmt.Sprintf(pathPipeline, c.addr, repoID, "latest")
|
||||
if len(branch) != 0 {
|
||||
uri += "?branch=" + branch
|
||||
}
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// PipelineList returns a list of recent pipelines for the
|
||||
// the specified repository.
|
||||
func (c *client) PipelineList(repoID int64) ([]*Pipeline, error) {
|
||||
var out []*Pipeline
|
||||
uri := fmt.Sprintf(pathPipelines, c.addr, repoID)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *client) PipelineCreate(repoID int64, options *PipelineOptions) (*Pipeline, error) {
|
||||
var out *Pipeline
|
||||
uri := fmt.Sprintf(pathPipelines, c.addr, repoID)
|
||||
err := c.post(uri, options, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// PipelineQueue returns a list of enqueued pipelines.
|
||||
func (c *client) PipelineQueue() ([]*Feed, error) {
|
||||
var out []*Feed
|
||||
uri := fmt.Sprintf(pathPipelineQueue, c.addr)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// PipelineStart re-starts a stopped pipeline.
|
||||
func (c *client) PipelineStart(repoID, pipeline int64, params map[string]string) (*Pipeline, error) {
|
||||
out := new(Pipeline)
|
||||
val := mapValues(params)
|
||||
uri := fmt.Sprintf(pathPipeline, c.addr, repoID, pipeline)
|
||||
err := c.post(uri+"?"+val.Encode(), nil, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// PipelineStop cancels the running step.
|
||||
func (c *client) PipelineStop(repoID, pipeline int64) error {
|
||||
uri := fmt.Sprintf(pathStop, c.addr, repoID, pipeline)
|
||||
err := c.post(uri, nil, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// PipelineApprove approves a blocked pipeline.
|
||||
func (c *client) PipelineApprove(repoID, pipeline int64) (*Pipeline, error) {
|
||||
out := new(Pipeline)
|
||||
uri := fmt.Sprintf(pathApprove, c.addr, repoID, pipeline)
|
||||
err := c.post(uri, nil, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// PipelineDecline declines a blocked pipeline.
|
||||
func (c *client) PipelineDecline(repoID, pipeline int64) (*Pipeline, error) {
|
||||
out := new(Pipeline)
|
||||
uri := fmt.Sprintf(pathDecline, c.addr, repoID, pipeline)
|
||||
err := c.post(uri, nil, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// PipelineKill force kills the running pipeline.
|
||||
func (c *client) PipelineKill(repoID, pipeline int64) error {
|
||||
uri := fmt.Sprintf(pathPipeline, c.addr, repoID, pipeline)
|
||||
err := c.delete(uri)
|
||||
return err
|
||||
}
|
||||
|
||||
// LogsPurge purges the pipeline all steps logs for the specified pipeline.
|
||||
func (c *client) LogsPurge(repoID, pipeline int64) error {
|
||||
uri := fmt.Sprintf(pathPipelineLogs, c.addr, repoID, pipeline)
|
||||
err := c.delete(uri)
|
||||
return err
|
||||
}
|
||||
|
||||
// StepLogEntries returns the pipeline logs for the specified step.
|
||||
func (c *client) StepLogEntries(repoID, num, step int64) ([]*LogEntry, error) {
|
||||
uri := fmt.Sprintf(pathStepLogs, c.addr, repoID, num, step)
|
||||
var out []*LogEntry
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// StepLogsPurge purges the pipeline logs for the specified step.
|
||||
func (c *client) StepLogsPurge(repoID, pipelineNumber, stepID int64) error {
|
||||
uri := fmt.Sprintf(pathStepLogs, c.addr, repoID, pipelineNumber, stepID)
|
||||
err := c.delete(uri)
|
||||
return err
|
||||
}
|
||||
|
||||
// Deploy triggers a deployment for an existing pipeline using the
|
||||
// specified target environment.
|
||||
func (c *client) Deploy(repoID, pipeline int64, env string, params map[string]string) (*Pipeline, error) {
|
||||
out := new(Pipeline)
|
||||
val := mapValues(params)
|
||||
val.Set("event", EventDeploy)
|
||||
val.Set("deploy_to", env)
|
||||
uri := fmt.Sprintf(pathPipeline, c.addr, repoID, pipeline)
|
||||
err := c.post(uri+"?"+val.Encode(), nil, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// Registry returns a registry by hostname.
|
||||
func (c *client) Registry(repoID int64, hostname string) (*Registry, error) {
|
||||
out := new(Registry)
|
||||
uri := fmt.Sprintf(pathRepoRegistry, c.addr, repoID, hostname)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// RegistryList returns a list of all repository registries.
|
||||
func (c *client) RegistryList(repoID int64) ([]*Registry, error) {
|
||||
var out []*Registry
|
||||
uri := fmt.Sprintf(pathRepoRegistries, c.addr, repoID)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// RegistryCreate creates a registry.
|
||||
func (c *client) RegistryCreate(repoID int64, in *Registry) (*Registry, error) {
|
||||
out := new(Registry)
|
||||
uri := fmt.Sprintf(pathRepoRegistries, c.addr, repoID)
|
||||
err := c.post(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// RegistryUpdate updates a registry.
|
||||
func (c *client) RegistryUpdate(repoID int64, in *Registry) (*Registry, error) {
|
||||
out := new(Registry)
|
||||
uri := fmt.Sprintf(pathRepoRegistry, c.addr, repoID, in.Address)
|
||||
err := c.patch(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// RegistryDelete deletes a registry.
|
||||
func (c *client) RegistryDelete(repoID int64, hostname string) error {
|
||||
uri := fmt.Sprintf(pathRepoRegistry, c.addr, repoID, hostname)
|
||||
return c.delete(uri)
|
||||
}
|
||||
|
||||
// Secret returns a secret by name.
|
||||
func (c *client) Secret(repoID int64, secret string) (*Secret, error) {
|
||||
out := new(Secret)
|
||||
uri := fmt.Sprintf(pathRepoSecret, c.addr, repoID, secret)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// SecretList returns a list of all repository secrets.
|
||||
func (c *client) SecretList(repoID int64) ([]*Secret, error) {
|
||||
var out []*Secret
|
||||
uri := fmt.Sprintf(pathRepoSecrets, c.addr, repoID)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// SecretCreate creates a secret.
|
||||
func (c *client) SecretCreate(repoID int64, in *Secret) (*Secret, error) {
|
||||
out := new(Secret)
|
||||
uri := fmt.Sprintf(pathRepoSecrets, c.addr, repoID)
|
||||
err := c.post(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// SecretUpdate updates a secret.
|
||||
func (c *client) SecretUpdate(repoID int64, in *Secret) (*Secret, error) {
|
||||
out := new(Secret)
|
||||
uri := fmt.Sprintf(pathRepoSecret, c.addr, repoID, in.Name)
|
||||
err := c.patch(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// SecretDelete deletes a secret.
|
||||
func (c *client) SecretDelete(repoID int64, secret string) error {
|
||||
uri := fmt.Sprintf(pathRepoSecret, c.addr, repoID, secret)
|
||||
return c.delete(uri)
|
||||
}
|
||||
|
||||
// Org returns an organization by id.
|
||||
func (c *client) Org(orgID int64) (*Org, error) {
|
||||
out := new(Org)
|
||||
uri := fmt.Sprintf(pathOrg, c.addr, orgID)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// OrgLookup returns a organization by its name.
|
||||
func (c *client) OrgLookup(name string) (*Org, error) {
|
||||
out := new(Org)
|
||||
uri := fmt.Sprintf(pathOrgLookup, c.addr, name)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// OrgSecret returns an organization secret by name.
|
||||
func (c *client) OrgSecret(orgID int64, secret string) (*Secret, error) {
|
||||
out := new(Secret)
|
||||
uri := fmt.Sprintf(pathOrgSecret, c.addr, orgID, secret)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// OrgSecretList returns a list of all organization secrets.
|
||||
func (c *client) OrgSecretList(orgID int64) ([]*Secret, error) {
|
||||
var out []*Secret
|
||||
uri := fmt.Sprintf(pathOrgSecrets, c.addr, orgID)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// OrgSecretCreate creates an organization secret.
|
||||
func (c *client) OrgSecretCreate(orgID int64, in *Secret) (*Secret, error) {
|
||||
out := new(Secret)
|
||||
uri := fmt.Sprintf(pathOrgSecrets, c.addr, orgID)
|
||||
err := c.post(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// OrgSecretUpdate updates an organization secret.
|
||||
func (c *client) OrgSecretUpdate(orgID int64, in *Secret) (*Secret, error) {
|
||||
out := new(Secret)
|
||||
uri := fmt.Sprintf(pathOrgSecret, c.addr, orgID, in.Name)
|
||||
err := c.patch(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// OrgSecretDelete deletes an organization secret.
|
||||
func (c *client) OrgSecretDelete(orgID int64, secret string) error {
|
||||
uri := fmt.Sprintf(pathOrgSecret, c.addr, orgID, secret)
|
||||
return c.delete(uri)
|
||||
}
|
||||
|
||||
// GlobalOrgSecret returns an global secret by name.
|
||||
func (c *client) GlobalSecret(secret string) (*Secret, error) {
|
||||
out := new(Secret)
|
||||
uri := fmt.Sprintf(pathGlobalSecret, c.addr, secret)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// GlobalSecretList returns a list of all global secrets.
|
||||
func (c *client) GlobalSecretList() ([]*Secret, error) {
|
||||
var out []*Secret
|
||||
uri := fmt.Sprintf(pathGlobalSecrets, c.addr)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// GlobalSecretCreate creates a global secret.
|
||||
func (c *client) GlobalSecretCreate(in *Secret) (*Secret, error) {
|
||||
out := new(Secret)
|
||||
uri := fmt.Sprintf(pathGlobalSecrets, c.addr)
|
||||
err := c.post(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// GlobalSecretUpdate updates a global secret.
|
||||
func (c *client) GlobalSecretUpdate(in *Secret) (*Secret, error) {
|
||||
out := new(Secret)
|
||||
uri := fmt.Sprintf(pathGlobalSecret, c.addr, in.Name)
|
||||
err := c.patch(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// GlobalSecretDelete deletes a global secret.
|
||||
func (c *client) GlobalSecretDelete(secret string) error {
|
||||
uri := fmt.Sprintf(pathGlobalSecret, c.addr, secret)
|
||||
return c.delete(uri)
|
||||
}
|
||||
|
||||
// QueueInfo returns queue info
|
||||
func (c *client) QueueInfo() (*Info, error) {
|
||||
out := new(Info)
|
||||
uri := fmt.Sprintf(pathQueue+"/info", c.addr)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// LogLevel returns the current logging level
|
||||
func (c *client) LogLevel() (*LogLevel, error) {
|
||||
out := new(LogLevel)
|
||||
|
@ -523,96 +74,31 @@ func (c *client) SetLogLevel(in *LogLevel) (*LogLevel, error) {
|
|||
return out, err
|
||||
}
|
||||
|
||||
func (c *client) CronList(repoID int64) ([]*Cron, error) {
|
||||
out := make([]*Cron, 0, 5)
|
||||
uri := fmt.Sprintf(pathRepoCrons, c.addr, repoID)
|
||||
return out, c.get(uri, &out)
|
||||
}
|
||||
|
||||
func (c *client) CronCreate(repoID int64, in *Cron) (*Cron, error) {
|
||||
out := new(Cron)
|
||||
uri := fmt.Sprintf(pathRepoCrons, c.addr, repoID)
|
||||
return out, c.post(uri, in, out)
|
||||
}
|
||||
|
||||
func (c *client) CronUpdate(repoID int64, in *Cron) (*Cron, error) {
|
||||
out := new(Cron)
|
||||
uri := fmt.Sprintf(pathRepoCron, c.addr, repoID, in.ID)
|
||||
err := c.patch(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *client) CronDelete(repoID, cronID int64) error {
|
||||
uri := fmt.Sprintf(pathRepoCron, c.addr, repoID, cronID)
|
||||
return c.delete(uri)
|
||||
}
|
||||
|
||||
func (c *client) CronGet(repoID, cronID int64) (*Cron, error) {
|
||||
out := new(Cron)
|
||||
uri := fmt.Sprintf(pathRepoCron, c.addr, repoID, cronID)
|
||||
return out, c.get(uri, out)
|
||||
}
|
||||
|
||||
func (c *client) AgentList() ([]*Agent, error) {
|
||||
out := make([]*Agent, 0, 5)
|
||||
uri := fmt.Sprintf(pathAgents, c.addr)
|
||||
return out, c.get(uri, &out)
|
||||
}
|
||||
|
||||
func (c *client) Agent(agentID int64) (*Agent, error) {
|
||||
out := new(Agent)
|
||||
uri := fmt.Sprintf(pathAgent, c.addr, agentID)
|
||||
return out, c.get(uri, out)
|
||||
}
|
||||
|
||||
func (c *client) AgentCreate(in *Agent) (*Agent, error) {
|
||||
out := new(Agent)
|
||||
uri := fmt.Sprintf(pathAgents, c.addr)
|
||||
return out, c.post(uri, in, out)
|
||||
}
|
||||
|
||||
func (c *client) AgentUpdate(in *Agent) (*Agent, error) {
|
||||
out := new(Agent)
|
||||
uri := fmt.Sprintf(pathAgent, c.addr, in.ID)
|
||||
return out, c.patch(uri, in, out)
|
||||
}
|
||||
|
||||
func (c *client) AgentDelete(agentID int64) error {
|
||||
uri := fmt.Sprintf(pathAgent, c.addr, agentID)
|
||||
return c.delete(uri)
|
||||
}
|
||||
|
||||
func (c *client) AgentTasksList(agentID int64) ([]*Task, error) {
|
||||
out := make([]*Task, 0, 5)
|
||||
uri := fmt.Sprintf(pathAgentTasks, c.addr, agentID)
|
||||
return out, c.get(uri, &out)
|
||||
}
|
||||
|
||||
//
|
||||
// http request helper functions
|
||||
//
|
||||
|
||||
// helper function for making an http GET request.
|
||||
// Helper function for making an http GET request.
|
||||
func (c *client) get(rawurl string, out any) error {
|
||||
return c.do(rawurl, http.MethodGet, nil, out)
|
||||
}
|
||||
|
||||
// helper function for making an http POST request.
|
||||
// Helper function for making an http POST request.
|
||||
func (c *client) post(rawurl string, in, out any) error {
|
||||
return c.do(rawurl, http.MethodPost, in, out)
|
||||
}
|
||||
|
||||
// helper function for making an http PATCH request.
|
||||
// Helper function for making an http PATCH request.
|
||||
func (c *client) patch(rawurl string, in, out any) error {
|
||||
return c.do(rawurl, http.MethodPatch, in, out)
|
||||
}
|
||||
|
||||
// helper function for making an http DELETE request.
|
||||
// Helper function for making an http DELETE request.
|
||||
func (c *client) delete(rawurl string) error {
|
||||
return c.do(rawurl, http.MethodDelete, nil, nil)
|
||||
}
|
||||
|
||||
// helper function to make an http request
|
||||
// Helper function to make an http request.
|
||||
func (c *client) do(rawurl, method string, in, out any) error {
|
||||
body, err := c.open(rawurl, method, in)
|
||||
if err != nil {
|
||||
|
@ -625,7 +111,7 @@ func (c *client) do(rawurl, method string, in, out any) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// helper function to open an http request
|
||||
// Helper function to open an http request.
|
||||
func (c *client) open(rawurl, method string, in any) (io.ReadCloser, error) {
|
||||
uri, err := url.Parse(rawurl)
|
||||
if err != nil {
|
||||
|
|
|
@ -25,44 +25,6 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_QueueInfo(t *testing.T) {
|
||||
fixtureHandler := func(w http.ResponseWriter, _ *http.Request) {
|
||||
fmt.Fprint(w, `{
|
||||
"pending": null,
|
||||
"running": [
|
||||
{
|
||||
"id": "4696",
|
||||
"data": "",
|
||||
"labels": {
|
||||
"platform": "linux/amd64",
|
||||
"repo": "woodpecker-ci/woodpecker"
|
||||
},
|
||||
"Dependencies": [],
|
||||
"DepStatus": {},
|
||||
"RunOn": null
|
||||
}
|
||||
],
|
||||
"stats": {
|
||||
"worker_count": 3,
|
||||
"pending_count": 0,
|
||||
"waiting_on_deps_count": 0,
|
||||
"running_count": 1,
|
||||
"completed_count": 0
|
||||
},
|
||||
"Paused": false
|
||||
}`)
|
||||
}
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(fixtureHandler))
|
||||
defer ts.Close()
|
||||
|
||||
client := NewClient(ts.URL, http.DefaultClient)
|
||||
|
||||
info, err := client.QueueInfo()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 3, info.Stats.Workers)
|
||||
}
|
||||
|
||||
func Test_LogLevel(t *testing.T) {
|
||||
logLevel := "warn"
|
||||
fixtureHandler := func(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
|
@ -49,7 +49,7 @@ const (
|
|||
LogEntryProgress
|
||||
)
|
||||
|
||||
// StepType identifies the type of step
|
||||
// StepType identifies the type of step.
|
||||
type StepType string
|
||||
|
||||
const (
|
||||
|
|
46
woodpecker-go/woodpecker/global_secret.go
Normal file
46
woodpecker-go/woodpecker/global_secret.go
Normal file
|
@ -0,0 +1,46 @@
|
|||
package woodpecker
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
pathGlobalSecrets = "%s/api/secrets"
|
||||
pathGlobalSecret = "%s/api/secrets/%s"
|
||||
)
|
||||
|
||||
// GlobalOrgSecret returns an global secret by name.
|
||||
func (c *client) GlobalSecret(secret string) (*Secret, error) {
|
||||
out := new(Secret)
|
||||
uri := fmt.Sprintf(pathGlobalSecret, c.addr, secret)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// GlobalSecretList returns a list of all global secrets.
|
||||
func (c *client) GlobalSecretList() ([]*Secret, error) {
|
||||
var out []*Secret
|
||||
uri := fmt.Sprintf(pathGlobalSecrets, c.addr)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// GlobalSecretCreate creates a global secret.
|
||||
func (c *client) GlobalSecretCreate(in *Secret) (*Secret, error) {
|
||||
out := new(Secret)
|
||||
uri := fmt.Sprintf(pathGlobalSecrets, c.addr)
|
||||
err := c.post(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// GlobalSecretUpdate updates a global secret.
|
||||
func (c *client) GlobalSecretUpdate(in *Secret) (*Secret, error) {
|
||||
out := new(Secret)
|
||||
uri := fmt.Sprintf(pathGlobalSecret, c.addr, in.Name)
|
||||
err := c.patch(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// GlobalSecretDelete deletes a global secret.
|
||||
func (c *client) GlobalSecretDelete(secret string) error {
|
||||
uri := fmt.Sprintf(pathGlobalSecret, c.addr, secret)
|
||||
return c.delete(uri)
|
||||
}
|
|
@ -190,42 +190,42 @@ type Client interface {
|
|||
// QueueInfo returns the queue state.
|
||||
QueueInfo() (*Info, error)
|
||||
|
||||
// LogLevel returns the current logging level
|
||||
// LogLevel returns the current logging level.
|
||||
LogLevel() (*LogLevel, error)
|
||||
|
||||
// SetLogLevel sets the server's logging level
|
||||
// SetLogLevel sets the server's logging level.
|
||||
SetLogLevel(logLevel *LogLevel) (*LogLevel, error)
|
||||
|
||||
// CronList list all cron jobs of a repo
|
||||
// CronList list all cron jobs of a repo.
|
||||
CronList(repoID int64) ([]*Cron, error)
|
||||
|
||||
// CronGet get a specific cron job of a repo by id
|
||||
// CronGet get a specific cron job of a repo by id.
|
||||
CronGet(repoID, cronID int64) (*Cron, error)
|
||||
|
||||
// CronDelete delete a specific cron job of a repo by id
|
||||
// CronDelete delete a specific cron job of a repo by id.
|
||||
CronDelete(repoID, cronID int64) error
|
||||
|
||||
// CronCreate create a new cron job in a repo
|
||||
// CronCreate create a new cron job in a repo.
|
||||
CronCreate(repoID int64, cron *Cron) (*Cron, error)
|
||||
|
||||
// CronUpdate update an existing cron job of a repo
|
||||
// CronUpdate update an existing cron job of a repo.
|
||||
CronUpdate(repoID int64, cron *Cron) (*Cron, error)
|
||||
|
||||
// AgentList returns a list of all registered agents
|
||||
// AgentList returns a list of all registered agents.
|
||||
AgentList() ([]*Agent, error)
|
||||
|
||||
// Agent returns an agent by id
|
||||
// Agent returns an agent by id.
|
||||
Agent(int64) (*Agent, error)
|
||||
|
||||
// AgentCreate creates a new agent
|
||||
// AgentCreate creates a new agent.
|
||||
AgentCreate(*Agent) (*Agent, error)
|
||||
|
||||
// AgentUpdate updates an existing agent
|
||||
// AgentUpdate updates an existing agent.
|
||||
AgentUpdate(*Agent) (*Agent, error)
|
||||
|
||||
// AgentDelete deletes an agent
|
||||
// AgentDelete deletes an agent.
|
||||
AgentDelete(int64) error
|
||||
|
||||
// AgentTasksList returns a list of all tasks executed by an agent
|
||||
// AgentTasksList returns a list of all tasks executed by an agent.
|
||||
AgentTasksList(int64) ([]*Task, error)
|
||||
}
|
||||
|
|
64
woodpecker-go/woodpecker/org.go
Normal file
64
woodpecker-go/woodpecker/org.go
Normal file
|
@ -0,0 +1,64 @@
|
|||
package woodpecker
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
pathOrg = "%s/api/orgs/%d"
|
||||
pathOrgLookup = "%s/api/orgs/lookup/%s"
|
||||
pathOrgSecrets = "%s/api/orgs/%d/secrets"
|
||||
pathOrgSecret = "%s/api/orgs/%d/secrets/%s"
|
||||
)
|
||||
|
||||
// Org returns an organization by id.
|
||||
func (c *client) Org(orgID int64) (*Org, error) {
|
||||
out := new(Org)
|
||||
uri := fmt.Sprintf(pathOrg, c.addr, orgID)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// OrgLookup returns a organization by its name.
|
||||
func (c *client) OrgLookup(name string) (*Org, error) {
|
||||
out := new(Org)
|
||||
uri := fmt.Sprintf(pathOrgLookup, c.addr, name)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// OrgSecret returns an organization secret by name.
|
||||
func (c *client) OrgSecret(orgID int64, secret string) (*Secret, error) {
|
||||
out := new(Secret)
|
||||
uri := fmt.Sprintf(pathOrgSecret, c.addr, orgID, secret)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// OrgSecretList returns a list of all organization secrets.
|
||||
func (c *client) OrgSecretList(orgID int64) ([]*Secret, error) {
|
||||
var out []*Secret
|
||||
uri := fmt.Sprintf(pathOrgSecrets, c.addr, orgID)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// OrgSecretCreate creates an organization secret.
|
||||
func (c *client) OrgSecretCreate(orgID int64, in *Secret) (*Secret, error) {
|
||||
out := new(Secret)
|
||||
uri := fmt.Sprintf(pathOrgSecrets, c.addr, orgID)
|
||||
err := c.post(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// OrgSecretUpdate updates an organization secret.
|
||||
func (c *client) OrgSecretUpdate(orgID int64, in *Secret) (*Secret, error) {
|
||||
out := new(Secret)
|
||||
uri := fmt.Sprintf(pathOrgSecret, c.addr, orgID, in.Name)
|
||||
err := c.patch(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// OrgSecretDelete deletes an organization secret.
|
||||
func (c *client) OrgSecretDelete(orgID int64, secret string) error {
|
||||
uri := fmt.Sprintf(pathOrgSecret, c.addr, orgID, secret)
|
||||
return c.delete(uri)
|
||||
}
|
13
woodpecker-go/woodpecker/pipeline.go
Normal file
13
woodpecker-go/woodpecker/pipeline.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
package woodpecker
|
||||
|
||||
import "fmt"
|
||||
|
||||
const pathPipelineQueue = "%s/api/pipelines"
|
||||
|
||||
// PipelineQueue returns a list of enqueued pipelines.
|
||||
func (c *client) PipelineQueue() ([]*Feed, error) {
|
||||
var out []*Feed
|
||||
uri := fmt.Sprintf(pathPipelineQueue, c.addr)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
13
woodpecker-go/woodpecker/queue.go
Normal file
13
woodpecker-go/woodpecker/queue.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
package woodpecker
|
||||
|
||||
import "fmt"
|
||||
|
||||
const pathQueue = "%s/api/queue"
|
||||
|
||||
// QueueInfo returns queue info.
|
||||
func (c *client) QueueInfo() (*Info, error) {
|
||||
out := new(Info)
|
||||
uri := fmt.Sprintf(pathQueue+"/info", c.addr)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
116
woodpecker-go/woodpecker/queue_test.go
Normal file
116
woodpecker-go/woodpecker/queue_test.go
Normal file
|
@ -0,0 +1,116 @@
|
|||
package woodpecker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestClient_QueueInfo(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
handler http.HandlerFunc
|
||||
expected *Info
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
handler: func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err := fmt.Fprint(w, `{
|
||||
"pending": null,
|
||||
"running": [
|
||||
{
|
||||
"id": "4696",
|
||||
"data": "",
|
||||
"labels": {
|
||||
"platform": "linux/amd64",
|
||||
"repo": "woodpecker-ci/woodpecker"
|
||||
},
|
||||
"Dependencies": [],
|
||||
"DepStatus": {},
|
||||
"RunOn": null
|
||||
}
|
||||
],
|
||||
"stats": {
|
||||
"worker_count": 2,
|
||||
"pending_count": 0,
|
||||
"waiting_on_deps_count": 0,
|
||||
"running_count": 0,
|
||||
"completed_count": 0
|
||||
},
|
||||
"Paused": false
|
||||
}`)
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
expected: &Info{
|
||||
Running: []Task{
|
||||
{
|
||||
ID: "4696",
|
||||
Data: []byte{},
|
||||
Labels: map[string]string{
|
||||
"platform": "linux/amd64",
|
||||
"repo": "woodpecker-ci/woodpecker",
|
||||
},
|
||||
Dependencies: []string{},
|
||||
DepStatus: nil,
|
||||
RunOn: nil,
|
||||
},
|
||||
},
|
||||
Stats: struct {
|
||||
Workers int `json:"worker_count"`
|
||||
Pending int `json:"pending_count"`
|
||||
WaitingOnDeps int `json:"waiting_on_deps_count"`
|
||||
Running int `json:"running_count"`
|
||||
Complete int `json:"completed_count"`
|
||||
}{
|
||||
Workers: 2,
|
||||
Pending: 0,
|
||||
WaitingOnDeps: 0,
|
||||
Running: 0,
|
||||
Complete: 0,
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "server error",
|
||||
handler: func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
},
|
||||
expected: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid response",
|
||||
handler: func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err := fmt.Fprint(w, `invalid json`)
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
expected: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ts := httptest.NewServer(tt.handler)
|
||||
defer ts.Close()
|
||||
|
||||
client := NewClient(ts.URL, http.DefaultClient)
|
||||
info, err := client.QueueInfo()
|
||||
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.expected, info)
|
||||
})
|
||||
}
|
||||
}
|
304
woodpecker-go/woodpecker/repo.go
Normal file
304
woodpecker-go/woodpecker/repo.go
Normal file
|
@ -0,0 +1,304 @@
|
|||
package woodpecker
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
pathRepoPost = "%s/api/repos?forge_remote_id=%d"
|
||||
pathRepo = "%s/api/repos/%d"
|
||||
pathRepoLookup = "%s/api/repos/lookup/%s"
|
||||
pathRepoMove = "%s/api/repos/%d/move?to=%s"
|
||||
pathChown = "%s/api/repos/%d/chown"
|
||||
pathRepair = "%s/api/repos/%d/repair"
|
||||
pathPipelines = "%s/api/repos/%d/pipelines"
|
||||
pathPipeline = "%s/api/repos/%d/pipelines/%v"
|
||||
pathPipelineLogs = "%s/api/repos/%d/logs/%d"
|
||||
pathStepLogs = "%s/api/repos/%d/logs/%d/%d"
|
||||
pathApprove = "%s/api/repos/%d/pipelines/%d/approve"
|
||||
pathDecline = "%s/api/repos/%d/pipelines/%d/decline"
|
||||
pathStop = "%s/api/repos/%d/pipelines/%d/cancel"
|
||||
pathRepoSecrets = "%s/api/repos/%d/secrets"
|
||||
pathRepoSecret = "%s/api/repos/%d/secrets/%s"
|
||||
pathRepoRegistries = "%s/api/repos/%d/registry"
|
||||
pathRepoRegistry = "%s/api/repos/%d/registry/%s"
|
||||
pathRepoCrons = "%s/api/repos/%d/cron"
|
||||
pathRepoCron = "%s/api/repos/%d/cron/%d"
|
||||
)
|
||||
|
||||
// Repo returns a repository by id.
|
||||
func (c *client) Repo(repoID int64) (*Repo, error) {
|
||||
out := new(Repo)
|
||||
uri := fmt.Sprintf(pathRepo, c.addr, repoID)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// RepoLookup returns a repository by name.
|
||||
func (c *client) RepoLookup(fullName string) (*Repo, error) {
|
||||
out := new(Repo)
|
||||
uri := fmt.Sprintf(pathRepoLookup, c.addr, fullName)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// RepoPost activates a repository.
|
||||
func (c *client) RepoPost(forgeRemoteID int64) (*Repo, error) {
|
||||
out := new(Repo)
|
||||
uri := fmt.Sprintf(pathRepoPost, c.addr, forgeRemoteID)
|
||||
err := c.post(uri, nil, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// RepoChown updates a repository owner.
|
||||
func (c *client) RepoChown(repoID int64) (*Repo, error) {
|
||||
out := new(Repo)
|
||||
uri := fmt.Sprintf(pathChown, c.addr, repoID)
|
||||
err := c.post(uri, nil, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// RepoRepair repairs the repository hooks.
|
||||
func (c *client) RepoRepair(repoID int64) error {
|
||||
uri := fmt.Sprintf(pathRepair, c.addr, repoID)
|
||||
return c.post(uri, nil, nil)
|
||||
}
|
||||
|
||||
// RepoPatch updates a repository.
|
||||
func (c *client) RepoPatch(repoID int64, in *RepoPatch) (*Repo, error) {
|
||||
out := new(Repo)
|
||||
uri := fmt.Sprintf(pathRepo, c.addr, repoID)
|
||||
err := c.patch(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// RepoDel deletes a repository.
|
||||
func (c *client) RepoDel(repoID int64) error {
|
||||
uri := fmt.Sprintf(pathRepo, c.addr, repoID)
|
||||
err := c.delete(uri)
|
||||
return err
|
||||
}
|
||||
|
||||
// RepoMove moves a repository.
|
||||
func (c *client) RepoMove(repoID int64, newFullName string) error {
|
||||
uri := fmt.Sprintf(pathRepoMove, c.addr, repoID, newFullName)
|
||||
return c.post(uri, nil, nil)
|
||||
}
|
||||
|
||||
// Registry returns a registry by hostname.
|
||||
func (c *client) Registry(repoID int64, hostname string) (*Registry, error) {
|
||||
out := new(Registry)
|
||||
uri := fmt.Sprintf(pathRepoRegistry, c.addr, repoID, hostname)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// RegistryList returns a list of all repository registries.
|
||||
func (c *client) RegistryList(repoID int64) ([]*Registry, error) {
|
||||
var out []*Registry
|
||||
uri := fmt.Sprintf(pathRepoRegistries, c.addr, repoID)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// RegistryCreate creates a registry.
|
||||
func (c *client) RegistryCreate(repoID int64, in *Registry) (*Registry, error) {
|
||||
out := new(Registry)
|
||||
uri := fmt.Sprintf(pathRepoRegistries, c.addr, repoID)
|
||||
err := c.post(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// RegistryUpdate updates a registry.
|
||||
func (c *client) RegistryUpdate(repoID int64, in *Registry) (*Registry, error) {
|
||||
out := new(Registry)
|
||||
uri := fmt.Sprintf(pathRepoRegistry, c.addr, repoID, in.Address)
|
||||
err := c.patch(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// RegistryDelete deletes a registry.
|
||||
func (c *client) RegistryDelete(repoID int64, hostname string) error {
|
||||
uri := fmt.Sprintf(pathRepoRegistry, c.addr, repoID, hostname)
|
||||
return c.delete(uri)
|
||||
}
|
||||
|
||||
// Secret returns a secret by name.
|
||||
func (c *client) Secret(repoID int64, secret string) (*Secret, error) {
|
||||
out := new(Secret)
|
||||
uri := fmt.Sprintf(pathRepoSecret, c.addr, repoID, secret)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// SecretList returns a list of all repository secrets.
|
||||
func (c *client) SecretList(repoID int64) ([]*Secret, error) {
|
||||
var out []*Secret
|
||||
uri := fmt.Sprintf(pathRepoSecrets, c.addr, repoID)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// SecretCreate creates a secret.
|
||||
func (c *client) SecretCreate(repoID int64, in *Secret) (*Secret, error) {
|
||||
out := new(Secret)
|
||||
uri := fmt.Sprintf(pathRepoSecrets, c.addr, repoID)
|
||||
err := c.post(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// SecretUpdate updates a secret.
|
||||
func (c *client) SecretUpdate(repoID int64, in *Secret) (*Secret, error) {
|
||||
out := new(Secret)
|
||||
uri := fmt.Sprintf(pathRepoSecret, c.addr, repoID, in.Name)
|
||||
err := c.patch(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// SecretDelete deletes a secret.
|
||||
func (c *client) SecretDelete(repoID int64, secret string) error {
|
||||
uri := fmt.Sprintf(pathRepoSecret, c.addr, repoID, secret)
|
||||
return c.delete(uri)
|
||||
}
|
||||
|
||||
// CronList returns a list of cronjobs for the specified repository.
|
||||
func (c *client) CronList(repoID int64) ([]*Cron, error) {
|
||||
out := make([]*Cron, 0, 5)
|
||||
uri := fmt.Sprintf(pathRepoCrons, c.addr, repoID)
|
||||
return out, c.get(uri, &out)
|
||||
}
|
||||
|
||||
// CronCreate creates a new cron job for the specified repository.
|
||||
func (c *client) CronCreate(repoID int64, in *Cron) (*Cron, error) {
|
||||
out := new(Cron)
|
||||
uri := fmt.Sprintf(pathRepoCrons, c.addr, repoID)
|
||||
return out, c.post(uri, in, out)
|
||||
}
|
||||
|
||||
// CronUpdate updates an existing cron job for the specified repository.
|
||||
func (c *client) CronUpdate(repoID int64, in *Cron) (*Cron, error) {
|
||||
out := new(Cron)
|
||||
uri := fmt.Sprintf(pathRepoCron, c.addr, repoID, in.ID)
|
||||
err := c.patch(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// CronDelete deletes a cron job by cron-id for the specified repository.
|
||||
func (c *client) CronDelete(repoID, cronID int64) error {
|
||||
uri := fmt.Sprintf(pathRepoCron, c.addr, repoID, cronID)
|
||||
return c.delete(uri)
|
||||
}
|
||||
|
||||
// CronGet returns a cron job by cron-id for the specified repository.
|
||||
func (c *client) CronGet(repoID, cronID int64) (*Cron, error) {
|
||||
out := new(Cron)
|
||||
uri := fmt.Sprintf(pathRepoCron, c.addr, repoID, cronID)
|
||||
return out, c.get(uri, out)
|
||||
}
|
||||
|
||||
// Pipeline returns a repository pipeline by pipeline-id.
|
||||
func (c *client) Pipeline(repoID, pipeline int64) (*Pipeline, error) {
|
||||
out := new(Pipeline)
|
||||
uri := fmt.Sprintf(pathPipeline, c.addr, repoID, pipeline)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// Pipeline returns the latest repository pipeline by branch.
|
||||
func (c *client) PipelineLast(repoID int64, branch string) (*Pipeline, error) {
|
||||
out := new(Pipeline)
|
||||
uri := fmt.Sprintf(pathPipeline, c.addr, repoID, "latest")
|
||||
if len(branch) != 0 {
|
||||
uri += "?branch=" + branch
|
||||
}
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// PipelineList returns a list of recent pipelines for the
|
||||
// the specified repository.
|
||||
func (c *client) PipelineList(repoID int64) ([]*Pipeline, error) {
|
||||
var out []*Pipeline
|
||||
uri := fmt.Sprintf(pathPipelines, c.addr, repoID)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// PipelineCreate creates a new pipeline for the specified repository.
|
||||
func (c *client) PipelineCreate(repoID int64, options *PipelineOptions) (*Pipeline, error) {
|
||||
var out *Pipeline
|
||||
uri := fmt.Sprintf(pathPipelines, c.addr, repoID)
|
||||
err := c.post(uri, options, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// PipelineStart re-starts a stopped pipeline.
|
||||
func (c *client) PipelineStart(repoID, pipeline int64, params map[string]string) (*Pipeline, error) {
|
||||
out := new(Pipeline)
|
||||
val := mapValues(params)
|
||||
uri := fmt.Sprintf(pathPipeline, c.addr, repoID, pipeline)
|
||||
err := c.post(uri+"?"+val.Encode(), nil, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// PipelineStop cancels the running step.
|
||||
func (c *client) PipelineStop(repoID, pipeline int64) error {
|
||||
uri := fmt.Sprintf(pathStop, c.addr, repoID, pipeline)
|
||||
err := c.post(uri, nil, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// PipelineApprove approves a blocked pipeline.
|
||||
func (c *client) PipelineApprove(repoID, pipeline int64) (*Pipeline, error) {
|
||||
out := new(Pipeline)
|
||||
uri := fmt.Sprintf(pathApprove, c.addr, repoID, pipeline)
|
||||
err := c.post(uri, nil, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// PipelineDecline declines a blocked pipeline.
|
||||
func (c *client) PipelineDecline(repoID, pipeline int64) (*Pipeline, error) {
|
||||
out := new(Pipeline)
|
||||
uri := fmt.Sprintf(pathDecline, c.addr, repoID, pipeline)
|
||||
err := c.post(uri, nil, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// PipelineKill force kills the running pipeline.
|
||||
func (c *client) PipelineKill(repoID, pipeline int64) error {
|
||||
uri := fmt.Sprintf(pathPipeline, c.addr, repoID, pipeline)
|
||||
err := c.delete(uri)
|
||||
return err
|
||||
}
|
||||
|
||||
// LogsPurge purges the pipeline all steps logs for the specified pipeline.
|
||||
func (c *client) LogsPurge(repoID, pipeline int64) error {
|
||||
uri := fmt.Sprintf(pathPipelineLogs, c.addr, repoID, pipeline)
|
||||
err := c.delete(uri)
|
||||
return err
|
||||
}
|
||||
|
||||
// Deploy triggers a deployment for an existing pipeline using the
|
||||
// specified target environment.
|
||||
func (c *client) Deploy(repoID, pipeline int64, env string, params map[string]string) (*Pipeline, error) {
|
||||
out := new(Pipeline)
|
||||
val := mapValues(params)
|
||||
val.Set("event", EventDeploy)
|
||||
val.Set("deploy_to", env)
|
||||
uri := fmt.Sprintf(pathPipeline, c.addr, repoID, pipeline)
|
||||
err := c.post(uri+"?"+val.Encode(), nil, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// StepLogEntries returns the pipeline logs for the specified step.
|
||||
func (c *client) StepLogEntries(repoID, num, step int64) ([]*LogEntry, error) {
|
||||
uri := fmt.Sprintf(pathStepLogs, c.addr, repoID, num, step)
|
||||
var out []*LogEntry
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// StepLogsPurge purges the pipeline logs for the specified step.
|
||||
func (c *client) StepLogsPurge(repoID, pipelineNumber, stepID int64) error {
|
||||
uri := fmt.Sprintf(pathStepLogs, c.addr, repoID, pipelineNumber, stepID)
|
||||
err := c.delete(uri)
|
||||
return err
|
||||
}
|
|
@ -181,12 +181,22 @@ type (
|
|||
Commit string `json:"commit,omitempty"`
|
||||
}
|
||||
|
||||
// QueueStats struct {
|
||||
// Workers int `json:"worker_count"`
|
||||
// Pending int `json:"pending_count"`
|
||||
// WaitingOnDeps int `json:"waiting_on_deps_count"`
|
||||
// Running int `json:"running_count"`
|
||||
// Complete int `json:"completed_count"`
|
||||
// }
|
||||
|
||||
// Info provides queue stats.
|
||||
Info struct {
|
||||
Pending []Task `json:"pending"`
|
||||
WaitingOnDeps []Task `json:"waiting_on_deps"`
|
||||
Running []Task `json:"running"`
|
||||
Stats struct {
|
||||
// TODO use dedicated struct in 3.x
|
||||
// Stats QueueStats `json:"stats"`
|
||||
Stats struct {
|
||||
Workers int `json:"worker_count"`
|
||||
Pending int `json:"pending_count"`
|
||||
WaitingOnDeps int `json:"waiting_on_deps_count"`
|
||||
|
@ -196,7 +206,7 @@ type (
|
|||
Paused bool `json:"paused,omitempty"`
|
||||
}
|
||||
|
||||
// LogLevel is for checking/setting logging level
|
||||
// LogLevel is for checking/setting logging level.
|
||||
LogLevel struct {
|
||||
Level string `json:"log-level"`
|
||||
}
|
||||
|
@ -211,7 +221,7 @@ type (
|
|||
Type LogEntryType `json:"type"`
|
||||
}
|
||||
|
||||
// Cron is the JSON data of a cron job
|
||||
// Cron is the JSON data of a cron job.
|
||||
Cron struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
|
@ -223,13 +233,13 @@ type (
|
|||
Branch string `json:"branch"`
|
||||
}
|
||||
|
||||
// PipelineOptions is the JSON data for creating a new pipeline
|
||||
// PipelineOptions is the JSON data for creating a new pipeline.
|
||||
PipelineOptions struct {
|
||||
Branch string `json:"branch"`
|
||||
Variables map[string]string `json:"variables"`
|
||||
}
|
||||
|
||||
// Agent is the JSON data for an agent
|
||||
// Agent is the JSON data for an agent.
|
||||
Agent struct {
|
||||
ID int64 `json:"id"`
|
||||
Created int64 `json:"created"`
|
||||
|
@ -245,7 +255,7 @@ type (
|
|||
NoSchedule bool `json:"no_schedule"`
|
||||
}
|
||||
|
||||
// Task is the JSON data for a task
|
||||
// Task is the JSON data for a task.
|
||||
Task struct {
|
||||
ID string `json:"id"`
|
||||
Data []byte `json:"data"`
|
||||
|
@ -256,7 +266,7 @@ type (
|
|||
AgentID int64 `json:"agent_id"`
|
||||
}
|
||||
|
||||
// Org is the JSON data for an organization
|
||||
// Org is the JSON data for an organization.
|
||||
Org struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
|
|
75
woodpecker-go/woodpecker/user.go
Normal file
75
woodpecker-go/woodpecker/user.go
Normal file
|
@ -0,0 +1,75 @@
|
|||
package woodpecker
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
pathSelf = "%s/api/user"
|
||||
pathRepos = "%s/api/user/repos"
|
||||
pathUsers = "%s/api/users"
|
||||
pathUser = "%s/api/users/%s"
|
||||
)
|
||||
|
||||
// Self returns the currently authenticated user.
|
||||
func (c *client) Self() (*User, error) {
|
||||
out := new(User)
|
||||
uri := fmt.Sprintf(pathSelf, c.addr)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// User returns a user by login.
|
||||
func (c *client) User(login string) (*User, error) {
|
||||
out := new(User)
|
||||
uri := fmt.Sprintf(pathUser, c.addr, login)
|
||||
err := c.get(uri, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// UserList returns a list of all registered users.
|
||||
func (c *client) UserList() ([]*User, error) {
|
||||
var out []*User
|
||||
uri := fmt.Sprintf(pathUsers, c.addr)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// UserPost creates a new user account.
|
||||
func (c *client) UserPost(in *User) (*User, error) {
|
||||
out := new(User)
|
||||
uri := fmt.Sprintf(pathUsers, c.addr)
|
||||
err := c.post(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// UserPatch updates a user account.
|
||||
func (c *client) UserPatch(in *User) (*User, error) {
|
||||
out := new(User)
|
||||
uri := fmt.Sprintf(pathUser, c.addr, in.Login)
|
||||
err := c.patch(uri, in, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// UserDel deletes a user account.
|
||||
func (c *client) UserDel(login string) error {
|
||||
uri := fmt.Sprintf(pathUser, c.addr, login)
|
||||
err := c.delete(uri)
|
||||
return err
|
||||
}
|
||||
|
||||
// RepoList returns a list of all repositories to which
|
||||
// the user has explicit access in the host system.
|
||||
func (c *client) RepoList() ([]*Repo, error) {
|
||||
var out []*Repo
|
||||
uri := fmt.Sprintf(pathRepos, c.addr)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// RepoListOpts returns a list of all repositories to which
|
||||
// the user has explicit access in the host system.
|
||||
func (c *client) RepoListOpts(all bool) ([]*Repo, error) {
|
||||
var out []*Repo
|
||||
uri := fmt.Sprintf(pathRepos+"?all=%v", c.addr, all)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
267
woodpecker-go/woodpecker/user_test.go
Normal file
267
woodpecker-go/woodpecker/user_test.go
Normal file
|
@ -0,0 +1,267 @@
|
|||
package woodpecker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestClient_UserList(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
handler http.HandlerFunc
|
||||
expected []*User
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
handler: func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err := fmt.Fprint(w, `[{"id":1,"login":"user1"},{"id":2,"login":"user2"}]`)
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
expected: []*User{{ID: 1, Login: "user1"}, {ID: 2, Login: "user2"}},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "empty response",
|
||||
handler: func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err := fmt.Fprint(w, `[]`)
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
expected: []*User{},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "server error",
|
||||
handler: func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
},
|
||||
expected: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ts := httptest.NewServer(tt.handler)
|
||||
defer ts.Close()
|
||||
|
||||
client := NewClient(ts.URL, http.DefaultClient)
|
||||
users, err := client.UserList()
|
||||
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, users, tt.expected)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_UserPost(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
handler http.HandlerFunc
|
||||
input *User
|
||||
expected *User
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
handler: func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
_, err := fmt.Fprint(w, `{"id":1,"login":"new_user"}`)
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
input: &User{Login: "new_user"},
|
||||
expected: &User{ID: 1, Login: "new_user"},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "invalid input",
|
||||
handler: func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
},
|
||||
input: &User{},
|
||||
expected: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "server error",
|
||||
handler: func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
},
|
||||
input: &User{Login: "new_user"},
|
||||
expected: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ts := httptest.NewServer(tt.handler)
|
||||
defer ts.Close()
|
||||
|
||||
client := NewClient(ts.URL, http.DefaultClient)
|
||||
user, err := client.UserPost(tt.input)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, user, tt.expected)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_UserPatch(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
handler http.HandlerFunc
|
||||
input *User
|
||||
expected *User
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPatch {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err := fmt.Fprint(w, `{"id":1,"login":"updated_user"}`)
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
input: &User{ID: 1, Login: "existing_user"},
|
||||
expected: &User{ID: 1, Login: "updated_user"},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "not found",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPatch {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
},
|
||||
input: &User{ID: 999, Login: "nonexistent_user"},
|
||||
expected: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid input",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPatch {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
},
|
||||
input: &User{},
|
||||
expected: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "server error",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPatch {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
},
|
||||
input: &User{ID: 1, Login: "existing_user"},
|
||||
expected: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ts := httptest.NewServer(tt.handler)
|
||||
defer ts.Close()
|
||||
|
||||
client := NewClient(ts.URL, http.DefaultClient)
|
||||
user, err := client.UserPatch(tt.input)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, user, tt.expected)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_UserDel(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
handler http.HandlerFunc
|
||||
login string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodDelete {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
},
|
||||
login: "existing_user",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "not found",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodDelete {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
},
|
||||
login: "nonexistent_user",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "server error",
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodDelete {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
},
|
||||
login: "existing_user",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ts := httptest.NewServer(tt.handler)
|
||||
defer ts.Close()
|
||||
|
||||
client := NewClient(ts.URL, http.DefaultClient)
|
||||
err := client.UserDel(tt.login)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue