Update swagger API specification (#1782)

# Summary

This PR drops the outdated former swagger.yaml/json and introduced
automatic API document generation from Go code.
The generated code is also used to generate documentation/markdown for
the community page,
as well as enable the Woodpecker server to serve a Swagger Web UI for
manual tinkering.

I did opt-in for gin-swagger, a middleware for the Gin framework, to
ease implementation and have a sophisticated output.
This middleware only produces Swagger v2 specs. AFAIK the newer OpenApi
3x tooling is not yet that mature,
so I guess that's fine for now.

## Implemenation notes

- former swagger.json files removed
- former // swagger godocs removed
- introduced new dependency gin-swagger, which uses godoc annotations on
top of Gin Handler functions.
- reworked Makefile to automatically generate Go code for the server
- introduce new dependency go-swagger, to generate Markdown for
documentation purposes
- add a Swagger Web UI, incl. capabilities for manual API exploration
- consider relative root paths in the implementation
- write documentation for all exposed API endpoints
- incl. API docs in the community website (auto-generated)
- provide developer documentation, for the Woodpecker authors
- no other existing logic/code was intentionally changed

---------

close #292

---------

Co-authored-by: qwerty287 <80460567+qwerty287@users.noreply.github.com>
Co-authored-by: 6543 <6543@obermui.de>
This commit is contained in:
Martin W. Kirst 2023-06-03 21:38:36 +02:00 committed by GitHub
parent b9731d8da9
commit 14177635b6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
49 changed files with 6047 additions and 1153 deletions

1
.ecrc
View file

@ -8,6 +8,7 @@
"node_modules", "node_modules",
"server/store/datastore/migration/testfiles/sqlite.db", "server/store/datastore/migration/testfiles/sqlite.db",
"server/store/datastore/feed.go", "server/store/datastore/feed.go",
"cmd/server/docs/docs.go",
"_test.go", "_test.go",
"Makefile" "Makefile"
] ]

4
.gitignore vendored
View file

@ -40,9 +40,6 @@ extras/
/build/ /build/
/dist/ /dist/
server/swagger/files/*.json
server/swagger/swagger_gen.go
docs/venv docs/venv
# helm charts # helm charts
@ -51,3 +48,4 @@ docs/venv
### Generated by CI ### ### Generated by CI ###
docs/docs/40-cli.md docs/docs/40-cli.md
docs/docs/20-usage/90-rest-api.md

View file

@ -40,10 +40,6 @@ run:
issues: issues:
exclude-rules: exclude-rules:
- path: woodpecker-go/woodpecker/client.go|server/swagger/swagger.go
linters:
- deadcode
- unused
# gin force us to use string as context key # gin force us to use string as context key
- path: server/store/context.go - path: server/store/context.go
linters: linters:

View file

@ -45,6 +45,16 @@ pipeline:
when: when:
path: *when_path path: *when_path
check_swagger:
image: *golang_image
group: test
commands:
- "make generate-swagger"
- "DIFF=$(git diff | head)"
- "[ -n \"$DIFF\" ] && { echo \"swagger not up to date, exec 'make generate-swagger' and commit\"; exit 1; } || true"
when:
path: *when_path
lint-editorconfig: lint-editorconfig:
image: mstruebing/editorconfig-checker image: mstruebing/editorconfig-checker
group: test group: test

View file

@ -91,9 +91,12 @@ clean: ## Clean build artifacts
@[ "1" != "$(shell docker image ls woodpecker/make:local -a | wc -l)" ] && docker image rm woodpecker/make:local || echo no docker image to clean @[ "1" != "$(shell docker image ls woodpecker/make:local -a | wc -l)" ] && docker image rm woodpecker/make:local || echo no docker image to clean
.PHONY: generate .PHONY: generate
generate: ## Run all code generations generate: generate-swagger ## Run all code generations
go generate ./... go generate ./...
generate-swagger: install-tools ## Run swagger code generation
swag init -g server/api/ -g cmd/server/swagger.go --outputTypes go -output cmd/server/docs
check-xgo: ## Check if xgo is installed check-xgo: ## Check if xgo is installed
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ @hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install src.techknowlogick.com/xgo@latest; \ $(GO) install src.techknowlogick.com/xgo@latest; \
@ -108,6 +111,9 @@ install-tools: ## Install development tools
fi ; \ fi ; \
hash gofumpt > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ hash gofumpt > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go install mvdan.cc/gofumpt@latest; \ go install mvdan.cc/gofumpt@latest; \
fi ; \
hash swag > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go install github.com/swaggo/swag/cmd/swag@latest; \
fi fi
ui-dependencies: ## Install UI dependencies ui-dependencies: ## Install UI dependencies
@ -161,7 +167,7 @@ test: test-agent test-server test-server-datastore test-cli test-lib test-ui ##
build-ui: ## Build UI build-ui: ## Build UI
(cd web/; pnpm install --frozen-lockfile; pnpm build) (cd web/; pnpm install --frozen-lockfile; pnpm build)
build-server: build-ui ## Build server build-server: build-ui generate-swagger ## Build server
CGO_ENABLED=${CGO_ENABLED} GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -ldflags '${LDFLAGS}' -o dist/woodpecker-server github.com/woodpecker-ci/woodpecker/cmd/server CGO_ENABLED=${CGO_ENABLED} GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -ldflags '${LDFLAGS}' -o dist/woodpecker-server github.com/woodpecker-ci/woodpecker/cmd/server
build-agent: ## Build agent build-agent: ## Build agent
@ -284,5 +290,6 @@ bundle: bundle-agent bundle-server bundle-cli ## Create all bundles
.PHONY: docs .PHONY: docs
docs: ## Generate docs (currently only for the cli) docs: ## Generate docs (currently only for the cli)
go generate cmd/cli/app.go go generate cmd/cli/app.go
go generate cmd/server/swagger.go
endif endif

4343
cmd/server/docs/docs.go Normal file

File diff suppressed because it is too large Load diff

View file

@ -20,6 +20,7 @@ import (
_ "github.com/joho/godotenv/autoload" _ "github.com/joho/godotenv/autoload"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
_ "github.com/woodpecker-ci/woodpecker/cmd/server/docs"
"github.com/woodpecker-ci/woodpecker/version" "github.com/woodpecker-ci/woodpecker/version"
) )
@ -32,6 +33,8 @@ func main() {
app.Action = run app.Action = run
app.Flags = flags app.Flags = flags
setupSwaggerStaticConfig()
if err := app.Run(os.Args); err != nil { if err := app.Run(os.Args); err != nil {
_, _ = fmt.Fprintln(os.Stderr, err) _, _ = fmt.Fprintln(os.Stderr, err)
os.Exit(1) os.Exit(1)

38
cmd/server/swagger.go Normal file
View file

@ -0,0 +1,38 @@
// 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 main
import (
"github.com/woodpecker-ci/woodpecker/cmd/server/docs"
"github.com/woodpecker-ci/woodpecker/version"
)
// generate docs/docs/20-usage/90-rest-api.md via:
//go:generate go run woodpecker_docs_gen.go swagger.go
// setupSwaggerStaticConfig initializes static content only (contacts, title and description)
// for dynamic configuration of e.g. hostname, etc. see router.setupSwaggerConfigAndRoutes
//
// @contact.name Woodpecker CI Community
// @contact.url https://woodpecker-ci.org/
func setupSwaggerStaticConfig() {
docs.SwaggerInfo.BasePath = "/api"
docs.SwaggerInfo.InfoInstanceName = "api"
docs.SwaggerInfo.Title = "Woodpecker CI API"
docs.SwaggerInfo.Version = version.String()
docs.SwaggerInfo.Description = "Woodpecker is a simple CI engine with great extensibility.\n" +
"To get a personal access token (PAT) for authentication, please log in your Woodpecker server,\n" +
"and go to you personal profile page, by clicking the user icon at the top right."
}

View file

@ -0,0 +1,134 @@
// 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.
// ************************************************************************************************
// This is a generator tool, to update the Markdown documentation for the woodpecker-ci.org website
// ************************************************************************************************
//go:build generate
// +build generate
package main
import (
"bufio"
"fmt"
"os"
"path"
"strings"
"time"
"github.com/go-swagger/go-swagger/generator"
"github.com/woodpecker-ci/woodpecker/cmd/server/docs"
)
const restApiMarkdownInto = `
# REST API
Woodpecker offers a comprehensive REST API, so you can integrate easily with from and with other tools.
## API specification
Starting with Woodpecker v1.0.0 a Swagger v2 API specification is served by the Woodpecker Server.
The typical URL looks like "http://woodpecker-host/swagger/doc.json", where you can fetch the API specification.
## Swagger API UI
Starting with Woodpecker v1.0.0 a Swagger web user interface (UI) is served by the Woodpecker Server.
Typically, you can open "http://woodpecker-host/swagger/index.html" in your browser, to explore the API documentation.
# API endpoint summary
This is a summary of available API endpoints.
Please, keep in mind this documentation reflects latest development changes
and might differ from your used server version.
Its recommended to consult the Swagger API UI of your Woodpecker server,
where you also have the chance to do manual exploration and live testing.
`
func main() {
setupSwaggerStaticConfig()
specFile := createTempFileWithSwaggerSpec()
defer os.Remove(specFile)
markdown := generateTempMarkdown(specFile)
f, err := os.Create(path.Join("..", "..", "docs", "docs", "20-usage", "90-rest-api.md"))
if err != nil {
panic(err)
}
defer f.Close()
_, err = f.WriteString(restApiMarkdownInto)
if err != nil {
panic(err)
}
_, err = f.WriteString(readGeneratedMarkdownAndSkipIntro(markdown))
if err != nil {
panic(err)
}
}
func createTempFileWithSwaggerSpec() string {
f, err := os.CreateTemp(os.TempDir(), "swagger.json")
if err != nil {
panic(err)
}
defer f.Close()
_, err = f.WriteString(docs.SwaggerInfo.ReadDoc())
if err != nil {
panic(err)
}
return f.Name()
}
func generateTempMarkdown(specFile string) string {
// HINT: we MUST use underscores, since the library tends to rename things
tempFile := fmt.Sprintf("woodpecker_api_%d.md", time.Now().UnixMilli())
markdownFile := path.Join(os.TempDir(), tempFile)
opts := generator.GenOpts{
GenOptsCommon: generator.GenOptsCommon{
Spec: specFile,
},
}
// TODO: contrib upstream a GenerateMarkdown that use io.Reader and io.Writer
err := generator.GenerateMarkdown(markdownFile, []string{}, []string{}, &opts)
if err != nil {
panic(err)
}
data, err := os.ReadFile(markdownFile)
if err != nil {
panic(err)
}
defer os.Remove(markdownFile)
return string(data)
}
func readGeneratedMarkdownAndSkipIntro(markdown string) string {
scanner := bufio.NewScanner(strings.NewReader(markdown))
sb := strings.Builder{}
foundActualContentStart := false
for scanner.Scan() {
text := scanner.Text()
foundActualContentStart = foundActualContentStart || (strings.HasPrefix(text, "##") && strings.Contains(strings.ToLower(text), "all endpoints"))
if foundActualContentStart {
sb.WriteString(text + "\n")
}
}
return sb.String()
}

View file

@ -0,0 +1,76 @@
# Swagger, API Spec and Code Generation
Woodpecker uses [gin-swagger](https://github.com/swaggo/gin-swagger) middleware to automatically
generate Swagger v2 API specifications and a nice looking Web UI from the source code.
Also, the generated spec will be transformed into Markdown, using [go-swagger](https://github.com/go-swagger/go-swagger)
and then being using on the community's website documentation.
It's paramount important to keep the gin handler function's godoc documentation up-to-date,
to always have accurate API documentation.
Whenever you change, add or enhance an API endpoint, please update the godocs.
You don't require any extra tools on your machine, all Swagger tooling is automatically fetched by standard Go tools.
### Gin-Handler API documentation guideline
Here's a typical example of how annotations for Swagger documentation look like...
```text
--- server/api/user.go ---
// @Summary Get a user
// @Description Returns a user with the specified login name. Requires admin rights.
// @Router /users/{login} [get]
// @Produce json
// @Success 200 {object} User
// @Tags Users
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param login path string true "the user's login name"
// @Param foobar query string false "optional foobar parameter"
// @Param page query int false "for response pagination, page offset number" default(1)
// @Param perPage query int false "for response pagination, max items per page" default(50)
```
```text
--- server/model/user.go ---
type User struct {
ID int64 `json:"id" xorm:"pk autoincr 'user_id'"`
// ...
} // @name User
```
These guidelines aim to have consistent wording in the swagger doc:
* first word after `@Summary` and `@Summary` are always uppercase
* `@Summary` has no . (dot) at the end of the line
* model structs shall use custom short names, to ease life for API consumers, using `@name`
* `@Success` object or array declarations shall be short, this means the actual `model.User` struct must have a `@name` annotation, so that the model can be renderend in Swagger
* when pagination is used, `@Parame page` and `@Parame perPage` must be added manually
* `@Param Authorization` is almost always present, there are just a few un-protected endpoints
There are many examples in the server/api package, which you can use a blueprint.
More enhanced information you can find here https://github.com/swaggo/swag/blob/master/README.md#declarative-comments-format
### Manual code generation
##### generate the server's Go code containing the Swagger
```shell
make generate-swagger
```
##### update the Markdown in the ./docs folder
```shell
make docs
```
##### auto-format swagger related godoc
```shell
go run github.com/swaggo/swag/cmd/swag@latest fmt -g server/api/z.go
```
**WARNING, known issue**: using swag v1.18.12 , there's a bug when running the `fmt` command,
which makes the swagger generator failing, because it can't find the models/structs/types anymore.
To fix it, please replace `// @name\tModelName` with `// @name ModelName`,
which means, replace the tab (`\t`) with a space (` `).
See https://github.com/swaggo/swag/pull/1594 == once this is merged and released, the mentioned issue is obsolete.

40
go.mod
View file

@ -20,6 +20,7 @@ require (
github.com/gin-gonic/gin v1.9.1 github.com/gin-gonic/gin v1.9.1
github.com/go-ap/httpsig v0.0.0-20221203064646-3647b4d88fdf github.com/go-ap/httpsig v0.0.0-20221203064646-3647b4d88fdf
github.com/go-sql-driver/mysql v1.7.1 github.com/go-sql-driver/mysql v1.7.1
github.com/go-swagger/go-swagger v0.30.4
github.com/golang-jwt/jwt/v4 v4.5.0 github.com/golang-jwt/jwt/v4 v4.5.0
github.com/google/go-github/v39 v39.2.0 github.com/google/go-github/v39 v39.2.0
github.com/google/tink/go v1.7.0 github.com/google/tink/go v1.7.0
@ -38,6 +39,9 @@ require (
github.com/robfig/cron v1.2.0 github.com/robfig/cron v1.2.0
github.com/rs/zerolog v1.29.1 github.com/rs/zerolog v1.29.1
github.com/stretchr/testify v1.8.3 github.com/stretchr/testify v1.8.3
github.com/swaggo/files v1.0.1
github.com/swaggo/gin-swagger v1.6.0
github.com/swaggo/swag v1.16.1
github.com/tevino/abool v1.2.0 github.com/tevino/abool v1.2.0
github.com/urfave/cli/v2 v2.25.3 github.com/urfave/cli/v2 v2.25.3
github.com/xanzy/go-gitlab v0.83.0 github.com/xanzy/go-gitlab v0.83.0
@ -59,7 +63,12 @@ require (
require ( require (
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.0 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/bytedance/sonic v1.9.1 // indirect github.com/bytedance/sonic v1.9.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect
@ -74,9 +83,17 @@ require (
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-fed/httpsig v1.1.0 // indirect github.com/go-fed/httpsig v1.1.0 // indirect
github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/logr v1.2.3 // indirect
github.com/go-openapi/analysis v0.21.4 // indirect
github.com/go-openapi/errors v0.20.3 // indirect
github.com/go-openapi/inflect v0.19.0 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.1 // indirect github.com/go-openapi/jsonreference v0.20.1 // indirect
github.com/go-openapi/loads v0.21.2 // indirect
github.com/go-openapi/runtime v0.25.0 // indirect
github.com/go-openapi/spec v0.20.8 // indirect
github.com/go-openapi/strfmt v0.21.3 // indirect
github.com/go-openapi/swag v0.22.3 // indirect github.com/go-openapi/swag v0.22.3 // indirect
github.com/go-openapi/validate v0.22.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect
@ -92,43 +109,61 @@ require (
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.2 // indirect
github.com/hashicorp/go-version v1.5.0 // indirect github.com/hashicorp/go-version v1.5.0 // indirect
github.com/imdario/mergo v0.3.6 // indirect github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huandu/xstrings v1.3.3 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/kr/fs v0.1.0 // indirect github.com/kr/fs v0.1.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/leodido/go-urn v1.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect
github.com/libdns/libdns v0.2.1 // indirect github.com/libdns/libdns v0.2.1 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mailru/easyjson v0.7.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-isatty v0.0.19 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mholt/acmez v1.0.4 // indirect github.com/mholt/acmez v1.0.4 // indirect
github.com/miekg/dns v1.1.50 // indirect github.com/miekg/dns v1.1.50 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect github.com/morikuni/aec v1.0.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.2 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/pkg/sftp v1.13.5 // indirect github.com/pkg/sftp v1.13.5 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.9.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect
github.com/rogpeppe/go-internal v1.10.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect github.com/sirupsen/logrus v1.9.0 // indirect
github.com/spf13/afero v1.9.2 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.14.0 // indirect
github.com/stretchr/objx v0.5.0 // indirect github.com/stretchr/objx v0.5.0 // indirect
github.com/subosito/gotenv v1.4.1 // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect github.com/ugorji/go/codec v1.2.11 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
go.mongodb.org/mongo-driver v1.11.1 // indirect
go.uber.org/atomic v1.9.0 // indirect go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.6.0 // indirect go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.23.0 // indirect go.uber.org/zap v1.23.0 // indirect
golang.org/x/arch v0.3.0 // indirect golang.org/x/arch v0.3.0 // indirect
golang.org/x/mod v0.9.0 // indirect golang.org/x/mod v0.9.0 // indirect
@ -140,6 +175,7 @@ require (
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gotest.tools/v3 v3.4.0 // indirect gotest.tools/v3 v3.4.0 // indirect
k8s.io/klog/v2 v2.90.1 // indirect k8s.io/klog/v2 v2.90.1 // indirect

494
go.sum

File diff suppressed because it is too large Load diff

View file

@ -28,6 +28,16 @@ import (
"github.com/woodpecker-ci/woodpecker/server/store" "github.com/woodpecker-ci/woodpecker/server/store"
) )
// GetAgents
//
// @Summary Get agent list
// @Router /agents [get]
// @Produce json
// @Success 200 {array} Agent
// @Tags Agents
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param page query int false "for response pagination, page offset number" default(1)
// @Param perPage query int false "for response pagination, max items per page" default(50)
func GetAgents(c *gin.Context) { func GetAgents(c *gin.Context) {
agents, err := store.FromContext(c).AgentList(session.Pagination(c)) agents, err := store.FromContext(c).AgentList(session.Pagination(c))
if err != nil { if err != nil {
@ -37,6 +47,15 @@ func GetAgents(c *gin.Context) {
c.JSON(http.StatusOK, agents) c.JSON(http.StatusOK, agents)
} }
// GetAgent
//
// @Summary Get agent information
// @Router /agents/{agent} [get]
// @Produce json
// @Success 200 {object} Agent
// @Tags Agents
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param agent path int true "the agent's id"
func GetAgent(c *gin.Context) { func GetAgent(c *gin.Context) {
agentID, err := strconv.ParseInt(c.Param("agent"), 10, 64) agentID, err := strconv.ParseInt(c.Param("agent"), 10, 64)
if err != nil { if err != nil {
@ -52,6 +71,15 @@ func GetAgent(c *gin.Context) {
c.JSON(http.StatusOK, agent) c.JSON(http.StatusOK, agent)
} }
// GetAgentTasks
//
// @Summary Get agent tasks
// @Router /agents/{agent}/tasks [get]
// @Produce json
// @Success 200 {array} Task
// @Tags Agents
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param agent path int true "the agent's id"
func GetAgentTasks(c *gin.Context) { func GetAgentTasks(c *gin.Context) {
agentID, err := strconv.ParseInt(c.Param("agent"), 10, 64) agentID, err := strconv.ParseInt(c.Param("agent"), 10, 64)
if err != nil { if err != nil {
@ -76,6 +104,16 @@ func GetAgentTasks(c *gin.Context) {
c.JSON(http.StatusOK, tasks) c.JSON(http.StatusOK, tasks)
} }
// PatchAgent
//
// @Summary Update agent information
// @Router /agents/{agent} [patch]
// @Produce json
// @Success 200 {object} Agent
// @Tags Agents
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param agent path int true "the agent's id"
// @Param agentData body Agent true "the agent's data"
func PatchAgent(c *gin.Context) { func PatchAgent(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
@ -109,7 +147,15 @@ func PatchAgent(c *gin.Context) {
c.JSON(http.StatusOK, agent) c.JSON(http.StatusOK, agent)
} }
// PostAgent create a new agent with a random token so a new agent can connect to the server // PostAgent
//
// @Summary Create a new agent with a random token so a new agent can connect to the server
// @Router /agents [post]
// @Produce json
// @Success 200 {object} Agent
// @Tags Agents
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param agent body Agent true "the agent's data (only 'name' and 'no_schedule' are read)"
func PostAgent(c *gin.Context) { func PostAgent(c *gin.Context) {
in := &model.Agent{} in := &model.Agent{}
err := c.Bind(in) err := c.Bind(in)
@ -135,6 +181,15 @@ func PostAgent(c *gin.Context) {
c.JSON(http.StatusOK, agent) c.JSON(http.StatusOK, agent)
} }
// DeleteAgent
//
// @Summary Delete an agent
// @Router /agents/{agent} [delete]
// @Produce plain
// @Success 200
// @Tags Agents
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param agent path int true "the agent's id"
func DeleteAgent(c *gin.Context) { func DeleteAgent(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)

View file

@ -34,6 +34,15 @@ import (
"github.com/woodpecker-ci/woodpecker/server/store/types" "github.com/woodpecker-ci/woodpecker/server/store/types"
) )
// GetBadge
//
// @Summary Get status badge, SVG format
// @Router /badges/{owner}/{name}/status.svg [get]
// @Produce image/svg+xml
// @Success 200
// @Tags Badges
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
func GetBadge(c *gin.Context) { func GetBadge(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
repo, err := _store.GetRepoName(c.Param("owner") + "/" + c.Param("name")) repo, err := _store.GetRepoName(c.Param("owner") + "/" + c.Param("name"))
@ -65,6 +74,18 @@ func GetBadge(c *gin.Context) {
c.String(http.StatusOK, badges.Generate(pipeline)) c.String(http.StatusOK, badges.Generate(pipeline))
} }
// GetCC
//
// @Summary Provide pipeline status information to the CCMenu tool
// @Description CCMenu displays the pipeline status of projects on a CI server as an item in the Mac's menu bar.
// @Description More details on how to install, you can find at http://ccmenu.org/
// @Description The response format adheres to CCTray v1 Specification, https://cctray.org/v1/
// @Router /badges/{owner}/{name}/cc.xml [get]
// @Produce xml
// @Success 200
// @Tags Badges
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
func GetCC(c *gin.Context) { func GetCC(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
repo, err := _store.GetRepoName(c.Param("owner") + "/" + c.Param("name")) repo, err := _store.GetRepoName(c.Param("owner") + "/" + c.Param("name"))

View file

@ -28,8 +28,17 @@ import (
"github.com/woodpecker-ci/woodpecker/server/store" "github.com/woodpecker-ci/woodpecker/server/store"
) )
// GetCron gets a cron job by id from the database and writes // GetCron
// to the response in json format. //
// @Summary Get a cron job by id
// @Router /repos/{owner}/{name}/cron/{cron} [get]
// @Produce json
// @Success 200 {object} Cron
// @Tags Repository cron jobs
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param cron path string true "the cron job id"
func GetCron(c *gin.Context) { func GetCron(c *gin.Context) {
repo := session.Repo(c) repo := session.Repo(c)
id, err := strconv.ParseInt(c.Param("cron"), 10, 64) id, err := strconv.ParseInt(c.Param("cron"), 10, 64)
@ -46,7 +55,17 @@ func GetCron(c *gin.Context) {
c.JSON(http.StatusOK, cron) c.JSON(http.StatusOK, cron)
} }
// RunCron starts a cron job now. // RunCron
//
// @Summary Start a cron job now
// @Router /repos/{owner}/{name}/cron/{cron} [post]
// @Produce json
// @Success 200 {object} Pipeline
// @Tags Repository cron jobs
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param cron path string true "the cron job id"
func RunCron(c *gin.Context) { func RunCron(c *gin.Context) {
repo := session.Repo(c) repo := session.Repo(c)
_store := store.FromContext(c) _store := store.FromContext(c)
@ -77,7 +96,17 @@ func RunCron(c *gin.Context) {
c.JSON(http.StatusOK, pl) c.JSON(http.StatusOK, pl)
} }
// PostCron persists the cron job to the database. // PostCron
//
// @Summary Persist/creat a cron job
// @Router /repos/{owner}/{name}/cron [post]
// @Produce json
// @Success 200 {object} Cron
// @Tags Repository cron jobs
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param cronJob body Cron true "the new cron job"
func PostCron(c *gin.Context) { func PostCron(c *gin.Context) {
repo := session.Repo(c) repo := session.Repo(c)
user := session.User(c) user := session.User(c)
@ -124,7 +153,18 @@ func PostCron(c *gin.Context) {
c.JSON(http.StatusOK, cron) c.JSON(http.StatusOK, cron)
} }
// PatchCron updates the cron job in the database. // PatchCron
//
// @Summary Update a cron job
// @Router /repos/{owner}/{name}/cron/{cron} [patch]
// @Produce json
// @Success 200 {object} Cron
// @Tags Repository cron jobs
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param cron path string true "the cron job id"
// @Param cronJob body Cron true "the cron job data"
func PatchCron(c *gin.Context) { func PatchCron(c *gin.Context) {
repo := session.Repo(c) repo := session.Repo(c)
user := session.User(c) user := session.User(c)
@ -183,8 +223,18 @@ func PatchCron(c *gin.Context) {
c.JSON(http.StatusOK, cron) c.JSON(http.StatusOK, cron)
} }
// GetCronList gets the cron job list from the database and writes // GetCronList
// to the response in json format. //
// @Summary Get the cron job list
// @Router /repos/{owner}/{name}/cron [get]
// @Produce json
// @Success 200 {array} Cron
// @Tags Repository cron jobs
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param page query int false "for response pagination, page offset number" default(1)
// @Param perPage query int false "for response pagination, max items per page" default(50)
func GetCronList(c *gin.Context) { func GetCronList(c *gin.Context) {
repo := session.Repo(c) repo := session.Repo(c)
list, err := store.FromContext(c).CronList(repo, session.Pagination(c)) list, err := store.FromContext(c).CronList(repo, session.Pagination(c))
@ -195,7 +245,17 @@ func GetCronList(c *gin.Context) {
c.JSON(http.StatusOK, list) c.JSON(http.StatusOK, list)
} }
// DeleteCron deletes the named cron job from the database. // DeleteCron
//
// @Summary Delete a cron job by id
// @Router /repos/{owner}/{name}/cron/{cron} [delete]
// @Produce plain
// @Success 200
// @Tags Repository cron jobs
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param cron path string true "the cron job id"
func DeleteCron(c *gin.Context) { func DeleteCron(c *gin.Context) {
repo := session.Repo(c) repo := session.Repo(c)
id, err := strconv.ParseInt(c.Param("cron"), 10, 64) id, err := strconv.ParseInt(c.Param("cron"), 10, 64)

View file

@ -20,63 +20,146 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
// IndexHandler will pass the call from /debug/pprof to pprof // IndexHandler
//
// @Summary List available pprof profiles (HTML)
// @Description Only available, when server was started with WOODPECKER_LOG_LEVEL=debug
// @Router /debug/pprof [get]
// @Produce html
// @Success 200
// @Tags Process profiling and debugging
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
func IndexHandler() gin.HandlerFunc { func IndexHandler() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
pprof.Index(c.Writer, c.Request) pprof.Index(c.Writer, c.Request)
} }
} }
// HeapHandler will pass the call from /debug/pprof/heap to pprof // HeapHandler
//
// @Summary Get pprof heap dump, a sampling of memory allocations of live objects
// @Description Only available, when server was started with WOODPECKER_LOG_LEVEL=debug
// @Router /debug/pprof/heap [get]
// @Produce plain
// @Success 200
// @Tags Process profiling and debugging
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param gc query string false "You can specify gc=heap to run GC before taking the heap sample" default()
func HeapHandler() gin.HandlerFunc { func HeapHandler() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
pprof.Handler("heap").ServeHTTP(c.Writer, c.Request) pprof.Handler("heap").ServeHTTP(c.Writer, c.Request)
} }
} }
// GoroutineHandler will pass the call from /debug/pprof/goroutine to pprof // GoroutineHandler
//
// @Summary Get pprof stack traces of all current goroutines
// @Description Only available, when server was started with WOODPECKER_LOG_LEVEL=debug
// @Router /debug/pprof/goroutine [get]
// @Produce plain
// @Success 200
// @Tags Process profiling and debugging
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param debug query int false "Use debug=2 as a query parameter to export in the same format as an un-recovered panic" default(1)
func GoroutineHandler() gin.HandlerFunc { func GoroutineHandler() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
pprof.Handler("goroutine").ServeHTTP(c.Writer, c.Request) pprof.Handler("goroutine").ServeHTTP(c.Writer, c.Request)
} }
} }
// BlockHandler will pass the call from /debug/pprof/block to pprof // BlockHandler
//
// @Summary Get pprof stack traces that led to blocking on synchronization primitives
// @Description Only available, when server was started with WOODPECKER_LOG_LEVEL=debug
// @Router /debug/pprof/block [get]
// @Produce plain
// @Success 200
// @Tags Process profiling and debugging
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
func BlockHandler() gin.HandlerFunc { func BlockHandler() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
pprof.Handler("block").ServeHTTP(c.Writer, c.Request) pprof.Handler("block").ServeHTTP(c.Writer, c.Request)
} }
} }
// ThreadCreateHandler will pass the call from /debug/pprof/threadcreate to pprof // ThreadCreateHandler
//
// @Summary Get pprof stack traces that led to the creation of new OS threads
// @Description Only available, when server was started with WOODPECKER_LOG_LEVEL=debug
// @Router /debug/pprof/threadcreate [get]
// @Produce plain
// @Success 200
// @Tags Process profiling and debugging
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
func ThreadCreateHandler() gin.HandlerFunc { func ThreadCreateHandler() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
pprof.Handler("threadcreate").ServeHTTP(c.Writer, c.Request) pprof.Handler("threadcreate").ServeHTTP(c.Writer, c.Request)
} }
} }
// CmdlineHandler will pass the call from /debug/pprof/cmdline to pprof // CmdlineHandler
//
// @Summary Get the command line invocation of the current program
// @Description Only available, when server was started with WOODPECKER_LOG_LEVEL=debug
// @Router /debug/pprof/cmdline [get]
// @Produce plain
// @Success 200
// @Tags Process profiling and debugging
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
func CmdlineHandler() gin.HandlerFunc { func CmdlineHandler() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
pprof.Cmdline(c.Writer, c.Request) pprof.Cmdline(c.Writer, c.Request)
} }
} }
// ProfileHandler will pass the call from /debug/pprof/profile to pprof // ProfileHandler
//
// @Summary Get pprof CPU profile
// @Description Only available, when server was started with WOODPECKER_LOG_LEVEL=debug
// @Description After you get the profile file, use the go tool pprof command to investigate the profile.
// @Router /debug/pprof/profile [get]
// @Produce plain
// @Success 200
// @Tags Process profiling and debugging
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param seconds query int true "You can specify the duration in the seconds GET parameter." default (30)
func ProfileHandler() gin.HandlerFunc { func ProfileHandler() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
pprof.Profile(c.Writer, c.Request) pprof.Profile(c.Writer, c.Request)
} }
} }
// SymbolHandler will pass the call from /debug/pprof/symbol to pprof // SymbolHandler
//
// @Summary Get pprof program counters mapping to function names
// @Description Only available, when server was started with WOODPECKER_LOG_LEVEL=debug
// @Description Looks up the program counters listed in the request,
// @Description responding with a table mapping program counters to function names.
// @Description The requested program counters can be provided via GET + query parameters,
// @Description or POST + body parameters. Program counters shall be space delimited.
// @Router /debug/pprof/symbol [get]
// @Router /debug/pprof/symbol [post]
// @Produce plain
// @Success 200
// @Tags Process profiling and debugging
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
func SymbolHandler() gin.HandlerFunc { func SymbolHandler() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
pprof.Symbol(c.Writer, c.Request) pprof.Symbol(c.Writer, c.Request)
} }
} }
// TraceHandler will pass the call from /debug/pprof/trace to pprof // TraceHandler
//
// @Summary Get a trace of execution of the current program
// @Description Only available, when server was started with WOODPECKER_LOG_LEVEL=debug
// @Description After you get the profile file, use the go tool pprof command to investigate the profile.
// @Router /debug/pprof/trace [get]
// @Produce plain
// @Success 200
// @Tags Process profiling and debugging
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param seconds query int true "You can specify the duration in the seconds GET parameter." default (30)
func TraceHandler() gin.HandlerFunc { func TraceHandler() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
pprof.Trace(c.Writer, c.Request) pprof.Trace(c.Writer, c.Request)

View file

@ -24,8 +24,16 @@ import (
"github.com/woodpecker-ci/woodpecker/server/model" "github.com/woodpecker-ci/woodpecker/server/model"
) )
// GetGlobalSecretList gets the global secret list from // GetGlobalSecretList
// the database and writes to the response in json format. //
// @Summary Get the global secret list
// @Router /secrets [get]
// @Produce json
// @Success 200 {array} Secret
// @Tags Secrets
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param page query int false "for response pagination, page offset number" default(1)
// @Param perPage query int false "for response pagination, max items per page" default(50)
func GetGlobalSecretList(c *gin.Context) { func GetGlobalSecretList(c *gin.Context) {
list, err := server.Config.Services.Secrets.GlobalSecretList(session.Pagination(c)) list, err := server.Config.Services.Secrets.GlobalSecretList(session.Pagination(c))
if err != nil { if err != nil {
@ -40,8 +48,15 @@ func GetGlobalSecretList(c *gin.Context) {
c.JSON(http.StatusOK, list) c.JSON(http.StatusOK, list)
} }
// GetGlobalSecret gets the named global secret from the database // GetGlobalSecret
// and writes to the response in json format. //
// @Summary Get a global secret by name
// @Router /secrets/{secret} [get]
// @Produce json
// @Success 200 {object} Secret
// @Tags Secrets
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param secret path string true "the secret's name"
func GetGlobalSecret(c *gin.Context) { func GetGlobalSecret(c *gin.Context) {
name := c.Param("secret") name := c.Param("secret")
secret, err := server.Config.Services.Secrets.GlobalSecretFind(name) secret, err := server.Config.Services.Secrets.GlobalSecretFind(name)
@ -52,7 +67,15 @@ func GetGlobalSecret(c *gin.Context) {
c.JSON(http.StatusOK, secret.Copy()) c.JSON(http.StatusOK, secret.Copy())
} }
// PostGlobalSecret persists a global secret to the database. // PostGlobalSecret
//
// @Summary Persist/create a global secret
// @Router /secrets [post]
// @Produce json
// @Success 200 {object} Secret
// @Tags Secrets
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param secret body Secret true "the secret object data"
func PostGlobalSecret(c *gin.Context) { func PostGlobalSecret(c *gin.Context) {
in := new(model.Secret) in := new(model.Secret)
if err := c.Bind(in); err != nil { if err := c.Bind(in); err != nil {
@ -77,7 +100,16 @@ func PostGlobalSecret(c *gin.Context) {
c.JSON(http.StatusOK, secret.Copy()) c.JSON(http.StatusOK, secret.Copy())
} }
// PatchGlobalSecret updates a global secret in the database. // PatchGlobalSecret
//
// @Summary Update a global secret by name
// @Router /secrets/{secret} [patch]
// @Produce json
// @Success 200 {object} Secret
// @Tags Secrets
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param secret path string true "the secret's name"
// @Param secretData body Secret true "the secret's data"
func PatchGlobalSecret(c *gin.Context) { func PatchGlobalSecret(c *gin.Context) {
name := c.Param("secret") name := c.Param("secret")
@ -115,7 +147,15 @@ func PatchGlobalSecret(c *gin.Context) {
c.JSON(http.StatusOK, secret.Copy()) c.JSON(http.StatusOK, secret.Copy())
} }
// DeleteGlobalSecret deletes the named global secret from the database. // DeleteGlobalSecret
//
// @Summary Delete a global secret by name
// @Router /secrets/{secret} [delete]
// @Produce plain
// @Success 200
// @Tags Secrets
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param secret path string true "the secret's name"
func DeleteGlobalSecret(c *gin.Context) { func DeleteGlobalSecret(c *gin.Context) {
name := c.Param("secret") name := c.Param("secret")
if err := server.Config.Services.Secrets.GlobalSecretDelete(name); err != nil { if err := server.Config.Services.Secrets.GlobalSecretDelete(name); err != nil {

View file

@ -35,22 +35,55 @@ import (
var skipRe = regexp.MustCompile(`\[(?i:ci *skip|skip *ci)\]`) var skipRe = regexp.MustCompile(`\[(?i:ci *skip|skip *ci)\]`)
// GetQueueInfo
//
// @Summary Get pipeline queue information
// @Description TODO: link the InfoT response object - this is blocked, until the `swaggo/swag` tool dependency is v1.18.12 or newer
// @Router /queue/info [get]
// @Produce json
// @Success 200 {object} map[string]string
// @Tags Pipeline queues
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
func GetQueueInfo(c *gin.Context) { func GetQueueInfo(c *gin.Context) {
c.IndentedJSON(http.StatusOK, c.IndentedJSON(http.StatusOK,
server.Config.Services.Queue.Info(c), server.Config.Services.Queue.Info(c),
) )
} }
// PauseQueue
//
// @Summary Pause a pipeline queue
// @Router /queue/pause [post]
// @Produce plain
// @Success 200
// @Tags Pipeline queues
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
func PauseQueue(c *gin.Context) { func PauseQueue(c *gin.Context) {
server.Config.Services.Queue.Pause() server.Config.Services.Queue.Pause()
c.Status(http.StatusOK) c.Status(http.StatusOK)
} }
// ResumeQueue
//
// @Summary Resume a pipeline queue
// @Router /queue/resume [post]
// @Produce plain
// @Success 200
// @Tags Pipeline queues
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
func ResumeQueue(c *gin.Context) { func ResumeQueue(c *gin.Context) {
server.Config.Services.Queue.Resume() server.Config.Services.Queue.Resume()
c.Status(http.StatusOK) c.Status(http.StatusOK)
} }
// BlockTilQueueHasRunningItem
//
// @Summary Block til pipeline queue has a running item
// @Router /queue/norunningpipelines [get]
// @Produce plain
// @Success 200
// @Tags Pipeline queues
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
func BlockTilQueueHasRunningItem(c *gin.Context) { func BlockTilQueueHasRunningItem(c *gin.Context) {
for { for {
info := server.Config.Services.Queue.Info(c) info := server.Config.Services.Queue.Info(c)
@ -61,7 +94,14 @@ func BlockTilQueueHasRunningItem(c *gin.Context) {
c.Status(http.StatusOK) c.Status(http.StatusOK)
} }
// PostHook start a pipeline triggered by a forges post webhook // PostHook
//
// @Summary Incoming webhook from forge
// @Router /hook [post]
// @Produce plain
// @Success 200
// @Tags System
// @Param hook body object true "the webhook payload; forge is automatically detected"
func PostHook(c *gin.Context) { func PostHook(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
forge := server.Config.Services.Forge forge := server.Config.Services.Forge

View file

@ -24,7 +24,15 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
// GetOrgPermissions returns the permissions of the current user in the given organization. // GetOrgPermissions
//
// @Summary Get the permissions of the current user in the given organization
// @Router /orgs/{owner}/permissions [get]
// @Produce json
// @Success 200 {array} OrgPerm
// @Tags Organization permissions
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the owner's name"
func GetOrgPermissions(c *gin.Context) { func GetOrgPermissions(c *gin.Context) {
var ( var (
err error err error

View file

@ -24,8 +24,16 @@ import (
"github.com/woodpecker-ci/woodpecker/server/model" "github.com/woodpecker-ci/woodpecker/server/model"
) )
// GetOrgSecret gets the named organization secret from the database // GetOrgSecret
// and writes to the response in json format. //
// @Summary Get the named organization secret
// @Router /orgs/{owner}/secrets/{secret} [get]
// @Produce json
// @Success 200 {object} Secret
// @Tags Organization secrets
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the owner's name"
// @Param secret path string true "the secret's name"
func GetOrgSecret(c *gin.Context) { func GetOrgSecret(c *gin.Context) {
var ( var (
owner = c.Param("owner") owner = c.Param("owner")
@ -39,8 +47,17 @@ func GetOrgSecret(c *gin.Context) {
c.JSON(http.StatusOK, secret.Copy()) c.JSON(http.StatusOK, secret.Copy())
} }
// GetOrgSecretList gets the organization secret list from // GetOrgSecretList
// the database and writes to the response in json format. //
// @Summary Get the organization secret list
// @Router /orgs/{owner}/secrets [get]
// @Produce json
// @Success 200 {array} Secret
// @Tags Organization secrets
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the owner's name"
// @Param page query int false "for response pagination, page offset number" default(1)
// @Param perPage query int false "for response pagination, max items per page" default(50)
func GetOrgSecretList(c *gin.Context) { func GetOrgSecretList(c *gin.Context) {
owner := c.Param("owner") owner := c.Param("owner")
list, err := server.Config.Services.Secrets.OrgSecretList(owner, session.Pagination(c)) list, err := server.Config.Services.Secrets.OrgSecretList(owner, session.Pagination(c))
@ -56,7 +73,16 @@ func GetOrgSecretList(c *gin.Context) {
c.JSON(http.StatusOK, list) c.JSON(http.StatusOK, list)
} }
// PostOrgSecret persists an organization secret to the database. // PostOrgSecret
//
// @Summary Persist/create an organization secret
// @Router /orgs/{owner}/secrets [post]
// @Produce json
// @Success 200 {object} Secret
// @Tags Organization secrets
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the owner's name"
// @Param secretData body Secret true "the new secret"
func PostOrgSecret(c *gin.Context) { func PostOrgSecret(c *gin.Context) {
owner := c.Param("owner") owner := c.Param("owner")
@ -84,7 +110,17 @@ func PostOrgSecret(c *gin.Context) {
c.JSON(http.StatusOK, secret.Copy()) c.JSON(http.StatusOK, secret.Copy())
} }
// PatchOrgSecret updates an organization secret in the database. // PatchOrgSecret
//
// @Summary Update an organization secret
// @Router /orgs/{owner}/secrets/{secret} [patch]
// @Produce json
// @Success 200 {object} Secret
// @Tags Organization secrets
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the owner's name"
// @Param secret path string true "the secret's name"
// @Param secretData body Secret true "the update secret data"
func PatchOrgSecret(c *gin.Context) { func PatchOrgSecret(c *gin.Context) {
var ( var (
owner = c.Param("owner") owner = c.Param("owner")
@ -125,7 +161,16 @@ func PatchOrgSecret(c *gin.Context) {
c.JSON(http.StatusOK, secret.Copy()) c.JSON(http.StatusOK, secret.Copy())
} }
// DeleteOrgSecret deletes the named organization secret from the database. // DeleteOrgSecret
//
// @Summary Delete the named secret from an organization
// @Router /orgs/{owner}/secrets/{secret} [delete]
// @Produce plain
// @Success 200
// @Tags Organization secrets
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the owner's name"
// @Param secret path string true "the secret's name"
func DeleteOrgSecret(c *gin.Context) { func DeleteOrgSecret(c *gin.Context) {
var ( var (
owner = c.Param("owner") owner = c.Param("owner")

View file

@ -39,6 +39,17 @@ import (
"github.com/woodpecker-ci/woodpecker/server/store/types" "github.com/woodpecker-ci/woodpecker/server/store/types"
) )
// CreatePipeline
//
// @Summary Run/trigger a pipelines
// @Router /repos/{owner}/{name}/pipelines [post]
// @Produce json
// @Success 200 {object} Pipeline
// @Tags Pipelines
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param options body PipelineOptions true "the options for the pipeline to run"
func CreatePipeline(c *gin.Context) { func CreatePipeline(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
repo := session.Repo(c) repo := session.Repo(c)
@ -86,6 +97,18 @@ func createTmpPipeline(event model.WebhookEvent, commitSHA string, repo *model.R
} }
} }
// GetPipelines
//
// @Summary Get pipelines, current running and past ones
// @Router /repos/{owner}/{name}/pipelines [get]
// @Produce json
// @Success 200 {array} Pipeline
// @Tags Pipelines
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param page query int false "for response pagination, page offset number" default(1)
// @Param perPage query int false "for response pagination, max items per page" default(50)
func GetPipelines(c *gin.Context) { func GetPipelines(c *gin.Context) {
repo := session.Repo(c) repo := session.Repo(c)
@ -101,6 +124,17 @@ func GetPipelines(c *gin.Context) {
c.JSON(http.StatusOK, pipelines) c.JSON(http.StatusOK, pipelines)
} }
// GetPipeline
//
// @Summary Pipeline information by number
// @Router /repos/{owner}/{name}/pipelines/{number} [get]
// @Produce json
// @Success 200 {object} Pipeline
// @Tags Pipelines
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param number path int true "the number of the pipeline, OR 'latest'"
func GetPipeline(c *gin.Context) { func GetPipeline(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
if c.Param("number") == "latest" { if c.Param("number") == "latest" {
@ -156,6 +190,19 @@ func GetPipelineLast(c *gin.Context) {
c.JSON(http.StatusOK, pl) c.JSON(http.StatusOK, pl)
} }
// GetPipelineLogs
//
// @Summary Log information per step
// @Router /repos/{owner}/{name}/logs/{number}/{pid}/{step} [get]
// @Produce plain
// @Success 200
// @Tags Pipeline logs
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param number path int true "the number of the pipeline"
// @Param pid path int true "the pipeline id"
// @Param step path int true "the step name"
func GetPipelineLogs(c *gin.Context) { func GetPipelineLogs(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
repo := session.Repo(c) repo := session.Repo(c)
@ -192,6 +239,18 @@ func GetPipelineLogs(c *gin.Context) {
} }
} }
// GetStepLogs
//
// @Summary Log information
// @Router /repos/{owner}/{name}/logs/{number}/{pid} [get]
// @Produce plain
// @Success 200
// @Tags Pipeline logs
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param number path int true "the number of the pipeline"
// @Param pid path int true "the pipeline id"
func GetStepLogs(c *gin.Context) { func GetStepLogs(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
repo := session.Repo(c) repo := session.Repo(c)
@ -227,6 +286,17 @@ func GetStepLogs(c *gin.Context) {
} }
} }
// GetPipelineConfig
//
// @Summary Pipeline configuration
// @Router /repos/{owner}/{name}/pipelines/{number}/config [get]
// @Produce json
// @Success 200 {array} Config
// @Tags Pipelines
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param number path int true "the number of the pipeline"
func GetPipelineConfig(c *gin.Context) { func GetPipelineConfig(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
repo := session.Repo(c) repo := session.Repo(c)
@ -251,7 +321,17 @@ func GetPipelineConfig(c *gin.Context) {
c.JSON(http.StatusOK, configs) c.JSON(http.StatusOK, configs)
} }
// CancelPipeline cancels a pipeline // CancelPipeline
//
// @Summary Cancels a pipeline
// @Router /repos/{owner}/{name}/pipelines/{number}/cancel [post]
// @Produce plain
// @Success 200
// @Tags Pipelines
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param number path int true "the number of the pipeline"
func CancelPipeline(c *gin.Context) { func CancelPipeline(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
repo := session.Repo(c) repo := session.Repo(c)
@ -271,7 +351,17 @@ func CancelPipeline(c *gin.Context) {
} }
} }
// PostApproval start pipelines in gated repos // PostApproval
//
// @Summary Start pipelines in gated repos
// @Router /repos/{owner}/{name}/pipelines/{number}/approve [post]
// @Produce json
// @Success 200 {object} Pipeline
// @Tags Pipelines
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param number path int true "the number of the pipeline"
func PostApproval(c *gin.Context) { func PostApproval(c *gin.Context) {
var ( var (
_store = store.FromContext(c) _store = store.FromContext(c)
@ -294,7 +384,17 @@ func PostApproval(c *gin.Context) {
} }
} }
// PostDecline decline pipelines in gated repos // PostDecline
//
// @Summary Decline pipelines in gated repos
// @Router /repos/{owner}/{name}/pipelines/{number}/decline [post]
// @Produce json
// @Success 200 {object} Pipeline
// @Tags Pipelines
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param number path int true "the number of the pipeline"
func PostDecline(c *gin.Context) { func PostDecline(c *gin.Context) {
var ( var (
_store = store.FromContext(c) _store = store.FromContext(c)
@ -317,6 +417,14 @@ func PostDecline(c *gin.Context) {
} }
} }
// GetPipelineQueue
//
// @Summary List pipeline queues
// @Router /pipelines [get]
// @Produce json
// @Success 200 {array} Feed
// @Tags Pipeline queues
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
func GetPipelineQueue(c *gin.Context) { func GetPipelineQueue(c *gin.Context) {
out, err := store.FromContext(c).GetPipelineQueue() out, err := store.FromContext(c).GetPipelineQueue()
if err != nil { if err != nil {
@ -326,7 +434,20 @@ func GetPipelineQueue(c *gin.Context) {
c.JSON(http.StatusOK, out) c.JSON(http.StatusOK, out)
} }
// PostPipeline restarts a pipeline optional with altered event, deploy or environment // PostPipeline
//
// @Summary Restart a pipeline
// @Description Restarts a pipeline optional with altered event, deploy or environment
// @Router /repos/{owner}/{name}/pipelines/{number} [post]
// @Produce json
// @Success 200 {object} Pipeline
// @Tags Pipelines
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param number path int true "the number of the pipeline"
// @Param event query string false "override the event type"
// @Param deploy_to query string false "override the target deploy value"
func PostPipeline(c *gin.Context) { func PostPipeline(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
repo := session.Repo(c) repo := session.Repo(c)
@ -396,6 +517,17 @@ func PostPipeline(c *gin.Context) {
} }
} }
// DeletePipelineLogs
//
// @Summary Deletes log
// @Router /repos/{owner}/{name}/logs/{number} [post]
// @Produce plain
// @Success 200
// @Tags Pipeline logs
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param number path int true "the number of the pipeline"
func DeletePipelineLogs(c *gin.Context) { func DeletePipelineLogs(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)

View file

@ -24,8 +24,17 @@ import (
"github.com/woodpecker-ci/woodpecker/server/router/middleware/session" "github.com/woodpecker-ci/woodpecker/server/router/middleware/session"
) )
// GetRegistry gets the name registry from the database and writes // GetRegistry
// to the response in json format. //
// @Summary Get a named registry
// @Router /repos/{owner}/{name}/registry/{registry} [get]
// @Produce json
// @Success 200 {object} Registry
// @Tags Repository registries
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param registry path string true "the registry name"
func GetRegistry(c *gin.Context) { func GetRegistry(c *gin.Context) {
var ( var (
repo = session.Repo(c) repo = session.Repo(c)
@ -39,7 +48,17 @@ func GetRegistry(c *gin.Context) {
c.JSON(200, registry.Copy()) c.JSON(200, registry.Copy())
} }
// PostRegistry persists the registry to the database. // PostRegistry
//
// @Summary Persist/create a registry
// @Router /repos/{owner}/{name}/registry [post]
// @Produce json
// @Success 200 {object} Registry
// @Tags Repository registries
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param registry body Registry true "the new registry data"
func PostRegistry(c *gin.Context) { func PostRegistry(c *gin.Context) {
repo := session.Repo(c) repo := session.Repo(c)
@ -67,7 +86,18 @@ func PostRegistry(c *gin.Context) {
c.JSON(http.StatusOK, in.Copy()) c.JSON(http.StatusOK, in.Copy())
} }
// PatchRegistry updates the registry in the database. // PatchRegistry
//
// @Summary Update a named registry
// @Router /repos/{owner}/{name}/registry/{registry} [patch]
// @Produce json
// @Success 200 {object} Registry
// @Tags Repository registries
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param registry path string true "the registry name"
// @Param registryData body Registry true "the attributes for the registry"
func PatchRegistry(c *gin.Context) { func PatchRegistry(c *gin.Context) {
var ( var (
repo = session.Repo(c) repo = session.Repo(c)
@ -110,8 +140,18 @@ func PatchRegistry(c *gin.Context) {
c.JSON(http.StatusOK, in.Copy()) c.JSON(http.StatusOK, in.Copy())
} }
// GetRegistryList gets the registry list from the database and writes // GetRegistryList
// to the response in json format. //
// @Summary Get the registry list
// @Router /repos/{owner}/{name}/registry [get]
// @Produce json
// @Success 200 {array} Registry
// @Tags Repository registries
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param page query int false "for response pagination, page offset number" default(1)
// @Param perPage query int false "for response pagination, max items per page" default(50)
func GetRegistryList(c *gin.Context) { func GetRegistryList(c *gin.Context) {
repo := session.Repo(c) repo := session.Repo(c)
list, err := server.Config.Services.Registries.RegistryList(repo, session.Pagination(c)) list, err := server.Config.Services.Registries.RegistryList(repo, session.Pagination(c))
@ -127,7 +167,17 @@ func GetRegistryList(c *gin.Context) {
c.JSON(http.StatusOK, list) c.JSON(http.StatusOK, list)
} }
// DeleteRegistry deletes the named registry from the database. // DeleteRegistry
//
// @Summary Delete a named registry
// @Router /repos/{owner}/{name}/registry/{registry} [delete]
// @Produce plain
// @Success 200
// @Tags Repository registries
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param registry path string true "the registry name"
func DeleteRegistry(c *gin.Context) { func DeleteRegistry(c *gin.Context) {
var ( var (
repo = session.Repo(c) repo = session.Repo(c)

View file

@ -35,6 +35,16 @@ import (
"github.com/woodpecker-ci/woodpecker/shared/token" "github.com/woodpecker-ci/woodpecker/shared/token"
) )
// PostRepo
//
// @Summary Activate a repository
// @Router /repos/{owner}/{name} [post]
// @Produce json
// @Success 200 {object} Repo
// @Tags Repositories
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
func PostRepo(c *gin.Context) { func PostRepo(c *gin.Context) {
forge := server.Config.Services.Forge forge := server.Config.Services.Forge
_store := store.FromContext(c) _store := store.FromContext(c)
@ -134,6 +144,17 @@ func PostRepo(c *gin.Context) {
c.JSON(http.StatusOK, repo) c.JSON(http.StatusOK, repo)
} }
// PatchRepo
//
// @Summary Change a repository
// @Router /repos/{owner}/{name} [patch]
// @Produce json
// @Success 200 {object} Repo
// @Tags Repositories
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param repo body RepoPatch true "the repository's information"
func PatchRepo(c *gin.Context) { func PatchRepo(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
repo := session.Repo(c) repo := session.Repo(c)
@ -194,6 +215,16 @@ func PatchRepo(c *gin.Context) {
c.JSON(http.StatusOK, repo) c.JSON(http.StatusOK, repo)
} }
// ChownRepo
//
// @Summary Change a repository's owner, to the one holding the access token
// @Router /repos/{owner}/{name}/chown [post]
// @Produce json
// @Success 200 {object} Repo
// @Tags Repositories
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
func ChownRepo(c *gin.Context) { func ChownRepo(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
repo := session.Repo(c) repo := session.Repo(c)
@ -208,15 +239,48 @@ func ChownRepo(c *gin.Context) {
c.JSON(http.StatusOK, repo) c.JSON(http.StatusOK, repo)
} }
// GetRepo
//
// @Summary Get repository information
// @Router /repos/{owner}/{name} [get]
// @Produce json
// @Success 200 {object} Repo
// @Tags Repositories
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
func GetRepo(c *gin.Context) { func GetRepo(c *gin.Context) {
c.JSON(http.StatusOK, session.Repo(c)) c.JSON(http.StatusOK, session.Repo(c))
} }
// GetRepoPermissions
//
// @Summary Repository permission information
// @Description The repository permission, according to the used access token.
// @Router /repos/{owner}/{name}/permissions [get]
// @Produce json
// @Success 200 {object} Perm
// @Tags Repositories
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
func GetRepoPermissions(c *gin.Context) { func GetRepoPermissions(c *gin.Context) {
perm := session.Perm(c) perm := session.Perm(c)
c.JSON(http.StatusOK, perm) c.JSON(http.StatusOK, perm)
} }
// GetRepoBranches
//
// @Summary Get repository branches
// @Router /repos/{owner}/{name}/branches [get]
// @Produce json
// @Success 200 {array} string
// @Tags Repositories
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param page query int false "for response pagination, page offset number" default(1)
// @Param perPage query int false "for response pagination, max items per page" default(50)
func GetRepoBranches(c *gin.Context) { func GetRepoBranches(c *gin.Context) {
repo := session.Repo(c) repo := session.Repo(c)
user := session.User(c) user := session.User(c)
@ -231,6 +295,18 @@ func GetRepoBranches(c *gin.Context) {
c.JSON(http.StatusOK, branches) c.JSON(http.StatusOK, branches)
} }
// GetRepoPullRequests
//
// @Summary List active pull requests
// @Router /repos/{owner}/{name}/pull_requests [get]
// @Produce json
// @Success 200 {array} PullRequest
// @Tags Repositories
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param page query int false "for response pagination, page offset number" default(1)
// @Param perPage query int false "for response pagination, max items per page" default(50)
func GetRepoPullRequests(c *gin.Context) { func GetRepoPullRequests(c *gin.Context) {
repo := session.Repo(c) repo := session.Repo(c)
user := session.User(c) user := session.User(c)
@ -245,6 +321,16 @@ func GetRepoPullRequests(c *gin.Context) {
c.JSON(http.StatusOK, prs) c.JSON(http.StatusOK, prs)
} }
// DeleteRepo
//
// @Summary Delete a repository
// @Router /repos/{owner}/{name} [delete]
// @Produce json
// @Success 200 {object} Repo
// @Tags Repositories
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
func DeleteRepo(c *gin.Context) { func DeleteRepo(c *gin.Context) {
remove, _ := strconv.ParseBool(c.Query("remove")) remove, _ := strconv.ParseBool(c.Query("remove"))
_store := store.FromContext(c) _store := store.FromContext(c)
@ -274,6 +360,16 @@ func DeleteRepo(c *gin.Context) {
c.JSON(http.StatusOK, repo) c.JSON(http.StatusOK, repo)
} }
// RepairRepo
//
// @Summary Repair a repository
// @Router /repos/{owner}/{name}/repair [post]
// @Produce plain
// @Success 200
// @Tags Repositories
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
func RepairRepo(c *gin.Context) { func RepairRepo(c *gin.Context) {
forge := server.Config.Services.Forge forge := server.Config.Services.Forge
_store := store.FromContext(c) _store := store.FromContext(c)
@ -336,6 +432,17 @@ func RepairRepo(c *gin.Context) {
c.Writer.WriteHeader(http.StatusOK) c.Writer.WriteHeader(http.StatusOK)
} }
// MoveRepo
//
// @Summary Move a repository to a new owner
// @Router /repos/{owner}/{name}/move [post]
// @Produce plain
// @Success 200
// @Tags Repositories
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param to query string true "the username to move the repository to"
func MoveRepo(c *gin.Context) { func MoveRepo(c *gin.Context) {
forge := server.Config.Services.Forge forge := server.Config.Services.Forge
_store := store.FromContext(c) _store := store.FromContext(c)

View file

@ -25,8 +25,17 @@ import (
"github.com/woodpecker-ci/woodpecker/server/router/middleware/session" "github.com/woodpecker-ci/woodpecker/server/router/middleware/session"
) )
// GetSecret gets the named secret from the database and writes // GetSecret
// to the response in json format. //
// @Summary Get a named secret
// @Router /repos/{owner}/{name}/secrets/{secretName} [get]
// @Produce json
// @Success 200 {object} Secret
// @Tags Repository secrets
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param secretName path string true "the secret name"
func GetSecret(c *gin.Context) { func GetSecret(c *gin.Context) {
var ( var (
repo = session.Repo(c) repo = session.Repo(c)
@ -40,7 +49,17 @@ func GetSecret(c *gin.Context) {
c.JSON(http.StatusOK, secret.Copy()) c.JSON(http.StatusOK, secret.Copy())
} }
// PostSecret persists the secret to the database. // PostSecret
//
// @Summary Persist/create a secret
// @Router /repos/{owner}/{name}/secrets [post]
// @Produce json
// @Success 200 {object} Secret
// @Tags Repository secrets
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param secret body Secret true "the new secret"
func PostSecret(c *gin.Context) { func PostSecret(c *gin.Context) {
repo := session.Repo(c) repo := session.Repo(c)
@ -68,7 +87,18 @@ func PostSecret(c *gin.Context) {
c.JSON(http.StatusOK, secret.Copy()) c.JSON(http.StatusOK, secret.Copy())
} }
// PatchSecret updates the secret in the database. // PatchSecret
//
// @Summary Update a named secret
// @Router /repos/{owner}/{name}/secrets/{secretName} [patch]
// @Produce json
// @Success 200 {object} Secret
// @Tags Repository secrets
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param secretName path string true "the secret name"
// @Param secret body Secret true "the secret itself"
func PatchSecret(c *gin.Context) { func PatchSecret(c *gin.Context) {
var ( var (
repo = session.Repo(c) repo = session.Repo(c)
@ -109,8 +139,18 @@ func PatchSecret(c *gin.Context) {
c.JSON(http.StatusOK, secret.Copy()) c.JSON(http.StatusOK, secret.Copy())
} }
// GetSecretList gets the secret list from the database and writes // GetSecretList
// to the response in json format. //
// @Summary Get the secret list
// @Router /repos/{owner}/{name}/secrets [get]
// @Produce json
// @Success 200 {array} Secret
// @Tags Repository secrets
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param page query int false "for response pagination, page offset number" default(1)
// @Param perPage query int false "for response pagination, max items per page" default(50)
func GetSecretList(c *gin.Context) { func GetSecretList(c *gin.Context) {
repo := session.Repo(c) repo := session.Repo(c)
list, err := server.Config.Services.Secrets.SecretList(repo, session.Pagination(c)) list, err := server.Config.Services.Secrets.SecretList(repo, session.Pagination(c))
@ -126,7 +166,17 @@ func GetSecretList(c *gin.Context) {
c.JSON(http.StatusOK, list) c.JSON(http.StatusOK, list)
} }
// DeleteSecret deletes the named secret from the database. // DeleteSecret
//
// @Summary Delete a named secret
// @Router /repos/{owner}/{name}/secrets/{secretName} [delete]
// @Produce plain
// @Success 200
// @Tags Repository secrets
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param owner path string true "the repository owner's name"
// @Param name path string true "the repository name"
// @Param secretName path string true "the secret name"
func DeleteSecret(c *gin.Context) { func DeleteSecret(c *gin.Context) {
var ( var (
repo = session.Repo(c) repo = session.Repo(c)

View file

@ -24,6 +24,14 @@ import (
"github.com/woodpecker-ci/woodpecker/server" "github.com/woodpecker-ci/woodpecker/server"
) )
// GetSignaturePublicKey
//
// @Summary Get server's signature public key
// @Router /signature/public-key [get]
// @Produce plain
// @Success 200
// @Tags System
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
func GetSignaturePublicKey(c *gin.Context) { func GetSignaturePublicKey(c *gin.Context) {
b, err := x509.MarshalPKIXPublicKey(server.Config.Services.SignaturePublicKey) b, err := x509.MarshalPKIXPublicKey(server.Config.Services.SignaturePublicKey)
if err != nil { if err != nil {

View file

@ -28,10 +28,27 @@ import (
"github.com/woodpecker-ci/woodpecker/shared/token" "github.com/woodpecker-ci/woodpecker/shared/token"
) )
// GetSelf
//
// @Summary Returns the currently authenticated user.
// @Router /user [get]
// @Produce json
// @Success 200 {object} User
// @Tags User
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
func GetSelf(c *gin.Context) { func GetSelf(c *gin.Context) {
c.JSON(http.StatusOK, session.User(c)) c.JSON(http.StatusOK, session.User(c))
} }
// GetFeed
//
// @Summary A feed entry for a build.
// @Description Feed entries can be used to display information on the latest builds.
// @Router /user/feed [get]
// @Produce json
// @Success 200 {object} Feed
// @Tags User
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
func GetFeed(c *gin.Context) { func GetFeed(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
@ -56,6 +73,15 @@ func GetFeed(c *gin.Context) {
c.JSON(http.StatusOK, feed) c.JSON(http.StatusOK, feed)
} }
// GetRepos
//
// @Summary Get user's repos
// @Description Retrieve the currently authenticated User's Repository list
// @Router /user/repos [get]
// @Produce json
// @Success 200 {array} Repo
// @Tags User
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
func GetRepos(c *gin.Context) { func GetRepos(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
_forge := server.Config.Services.Forge _forge := server.Config.Services.Forge
@ -97,6 +123,14 @@ func GetRepos(c *gin.Context) {
c.JSON(http.StatusOK, activeRepos) c.JSON(http.StatusOK, activeRepos)
} }
// PostToken
//
// @Summary Return the token of the current user as stringª
// @Router /user/token [post]
// @Produce plain
// @Success 200
// @Tags User
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
func PostToken(c *gin.Context) { func PostToken(c *gin.Context) {
user := session.User(c) user := session.User(c)
tokenString, err := token.New(token.UserToken, user.Login).Sign(user.Hash) tokenString, err := token.New(token.UserToken, user.Login).Sign(user.Hash)
@ -107,6 +141,15 @@ func PostToken(c *gin.Context) {
c.String(http.StatusOK, tokenString) c.String(http.StatusOK, tokenString)
} }
// DeleteToken
//
// @Summary Reset a token
// @Description Reset's the current personal access token of the user and returns a new one.
// @Router /user/token [delete]
// @Produce plain
// @Success 200
// @Tags User
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
func DeleteToken(c *gin.Context) { func DeleteToken(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)

View file

@ -26,6 +26,17 @@ import (
"github.com/woodpecker-ci/woodpecker/server/store" "github.com/woodpecker-ci/woodpecker/server/store"
) )
// GetUsers
//
// @Summary Get all users
// @Description Returns all registered, active users in the system. Requires admin rights.
// @Router /users [get]
// @Produce json
// @Success 200 {array} User
// @Tags Users
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param page query int false "for response pagination, page offset number" default(1)
// @Param perPage query int false "for response pagination, max items per page" default(50)
func GetUsers(c *gin.Context) { func GetUsers(c *gin.Context) {
users, err := store.FromContext(c).GetUserList(session.Pagination(c)) users, err := store.FromContext(c).GetUserList(session.Pagination(c))
if err != nil { if err != nil {
@ -35,6 +46,16 @@ func GetUsers(c *gin.Context) {
c.JSON(200, users) c.JSON(200, users)
} }
// GetUser
//
// @Summary Get a user
// @Description Returns a user with the specified login name. Requires admin rights.
// @Router /users/{login} [get]
// @Produce json
// @Success 200 {object} User
// @Tags Users
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param login path string true "the user's login name"
func GetUser(c *gin.Context) { func GetUser(c *gin.Context) {
user, err := store.FromContext(c).GetUserLogin(c.Param("login")) user, err := store.FromContext(c).GetUserLogin(c.Param("login"))
if err != nil { if err != nil {
@ -44,6 +65,18 @@ func GetUser(c *gin.Context) {
c.JSON(200, user) c.JSON(200, user)
} }
// PatchUser
//
// @Summary Change a user
// @Description Changes the data of an existing user. Requires admin rights.
// @Router /users/{login} [patch]
// @Produce json
// @Accept json
// @Success 200 {object} User
// @Tags Users
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param login path string true "the user's login name"
// @Param user body User true "the user's data"
func PatchUser(c *gin.Context) { func PatchUser(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
@ -75,6 +108,16 @@ func PatchUser(c *gin.Context) {
c.JSON(http.StatusOK, user) c.JSON(http.StatusOK, user)
} }
// PostUser
//
// @Summary Create a user
// @Description Creates a new user account with the specified external login. Requires admin rights.
// @Router /users [post]
// @Produce json
// @Success 200 {object} User
// @Tags Users
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param user body User true "the user's data"
func PostUser(c *gin.Context) { func PostUser(c *gin.Context) {
in := &model.User{} in := &model.User{}
err := c.Bind(in) err := c.Bind(in)
@ -101,6 +144,16 @@ func PostUser(c *gin.Context) {
c.JSON(http.StatusOK, user) c.JSON(http.StatusOK, user)
} }
// DeleteUser
//
// @Summary Delete a user
// @Description Deletes the given user. Requires admin rights.
// @Router /users/{login} [delete]
// @Produce json
// @Success 200 {object} User
// @Tags Users
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param login path string true "the user's login name"
func DeleteUser(c *gin.Context) { func DeleteUser(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)

View file

@ -25,7 +25,15 @@ import (
"github.com/woodpecker-ci/woodpecker/version" "github.com/woodpecker-ci/woodpecker/version"
) )
// Health endpoint returns a 500 if the server state is unhealthy. // Health
//
// @Summary Health information
// @Description If everything is fine, just a 200 will be returned, a 500 signals server state is unhealthy.
// @Router /healthz [get]
// @Produce plain
// @Success 200
// @Failure 500
// @Tags System
func Health(c *gin.Context) { func Health(c *gin.Context) {
if err := store.FromContext(c).Ping(); err != nil { if err := store.FromContext(c).Ping(); err != nil {
c.String(http.StatusInternalServerError, err.Error()) c.String(http.StatusInternalServerError, err.Error())
@ -34,7 +42,14 @@ func Health(c *gin.Context) {
c.String(http.StatusOK, "") c.String(http.StatusOK, "")
} }
// Version endpoint returns the server version and build information. // Version
//
// @Summary Get version
// @Description Endpoint returns the server version and build information.
// @Router /version [get]
// @Produce json
// @Success 200 {object} string{source=string,version=string}
// @Tags System
func Version(c *gin.Context) { func Version(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"source": "https://github.com/woodpecker-ci/woodpecker", "source": "https://github.com/woodpecker-ci/woodpecker",
@ -42,14 +57,30 @@ func Version(c *gin.Context) {
}) })
} }
// LogLevel endpoint returns the current logging level // LogLevel
//
// @Summary Current log level
// @Description Endpoint returns the current logging level. Requires admin rights.
// @Router /log-level [get]
// @Produce json
// @Success 200 {object} string{log-level=string}
// @Tags System
func LogLevel(c *gin.Context) { func LogLevel(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"log-level": zerolog.GlobalLevel().String(), "log-level": zerolog.GlobalLevel().String(),
}) })
} }
// SetLogLevel endpoint allows setting the logging level via API // SetLogLevel
//
// @Summary Set log level
// @Description Endpoint sets the current logging level. Requires admin rights.
// @Router /log-level [post]
// @Produce json
// @Success 200 {object} string{log-level=string}
// @Tags System
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param log-level body string{log-level=string} true "the new log level, one of <debug,trace,info,warn,error,fatal,panic,disabled>"
func SetLogLevel(c *gin.Context) { func SetLogLevel(c *gin.Context) {
logLevel := struct { logLevel := struct {
LogLevel string `json:"log-level"` LogLevel string `json:"log-level"`

View file

@ -27,7 +27,7 @@ type Agent struct {
Capacity int32 `json:"capacity"` Capacity int32 `json:"capacity"`
Version string `json:"version"` Version string `json:"version"`
NoSchedule bool `json:"no_schedule"` NoSchedule bool `json:"no_schedule"`
} } // @name Agent
// TableName return database table name for xorm // TableName return database table name for xorm
func (Agent) TableName() string { func (Agent) TableName() string {

View file

@ -31,7 +31,7 @@ type Config struct {
Hash string `json:"hash" xorm:"UNIQUE(s) 'config_hash'"` Hash string `json:"hash" xorm:"UNIQUE(s) 'config_hash'"`
Name string `json:"name" xorm:"config_name"` Name string `json:"name" xorm:"config_name"`
Data []byte `json:"data" xorm:"config_data"` Data []byte `json:"data" xorm:"config_data"`
} } // @name Config
// PipelineConfig is the n:n relation between Pipeline and Config // PipelineConfig is the n:n relation between Pipeline and Config
type PipelineConfig struct { type PipelineConfig struct {

View file

@ -20,7 +20,7 @@ import (
"fmt" "fmt"
) )
type WebhookEvent string type WebhookEvent string // @name WebhookEvent
const ( const (
EventPush WebhookEvent = "push" EventPush WebhookEvent = "push"
@ -49,7 +49,7 @@ func ValidateWebhookEvent(s WebhookEvent) error {
} }
// StatusValue represent pipeline states woodpecker know // StatusValue represent pipeline states woodpecker know
type StatusValue string type StatusValue string // @name StatusValue
const ( const (
StatusSkipped StatusValue = "skipped" StatusSkipped StatusValue = "skipped"
@ -64,7 +64,7 @@ const (
) )
// SCMKind represent different version control systems // SCMKind represent different version control systems
type SCMKind string type SCMKind string // @name SCMKind
const ( const (
RepoGit SCMKind = "git" RepoGit SCMKind = "git"
@ -74,7 +74,7 @@ const (
) )
// RepoVisibility represent to wat state a repo in woodpecker is visible to others // RepoVisibility represent to wat state a repo in woodpecker is visible to others
type RepoVisibility string type RepoVisibility string // @name RepoVisibility
const ( const (
VisibilityPublic RepoVisibility = "public" VisibilityPublic RepoVisibility = "public"

View file

@ -20,17 +20,16 @@ import (
"github.com/robfig/cron" "github.com/robfig/cron"
) )
// swagger:model cron
type Cron struct { type Cron struct {
ID int64 `json:"id" xorm:"pk autoincr"` ID int64 `json:"id" xorm:"pk autoincr"`
Name string `json:"name" xorm:"UNIQUE(s) INDEX"` Name string `json:"name" xorm:"UNIQUE(s) INDEX"`
RepoID int64 `json:"repo_id" xorm:"repo_id UNIQUE(s) INDEX"` RepoID int64 `json:"repo_id" xorm:"repo_id UNIQUE(s) INDEX"`
CreatorID int64 `json:"creator_id" xorm:"creator_id INDEX"` CreatorID int64 `json:"creator_id" xorm:"creator_id INDEX"`
NextExec int64 `json:"next_exec"` NextExec int64 `json:"next_exec"`
Schedule string `json:"schedule" xorm:"NOT NULL"` // @weekly, 3min, ... Schedule string `json:"schedule" xorm:"NOT NULL"` // @weekly, 3min, ...
Created int64 `json:"created_at" xorm:"created NOT NULL DEFAULT 0"` Created int64 `json:"created_at" xorm:"created NOT NULL DEFAULT 0"`
Branch string `json:"branch"` Branch string `json:"branch"`
} } // @name Cron
// TableName returns the database table name for xorm // TableName returns the database table name for xorm
func (Cron) TableName() string { func (Cron) TableName() string {

View file

@ -35,7 +35,6 @@ type EnvironStore interface {
} }
// Environ represents an environment variable. // Environ represents an environment variable.
// swagger:model environ
type Environ struct { type Environ struct {
ID int64 `json:"id"` ID int64 `json:"id"`
Name string `json:"name"` Name string `json:"name"`

View file

@ -16,8 +16,6 @@
package model package model
// Feed represents an item in the user's feed or timeline. // Feed represents an item in the user's feed or timeline.
//
// swagger:model feed
type Feed struct { type Feed struct {
Owner string `json:"owner" xorm:"feed_repo_owner"` Owner string `json:"owner" xorm:"feed_repo_owner"`
Name string `json:"name" xorm:"feed_repo_name"` Name string `json:"name" xorm:"feed_repo_name"`
@ -40,4 +38,4 @@ type Feed struct {
Author string `json:"author,omitempty" xorm:"feed_pipeline_author"` Author string `json:"author,omitempty" xorm:"feed_pipeline_author"`
Avatar string `json:"author_avatar,omitempty" xorm:"feed_pipeline_avatar"` Avatar string `json:"author_avatar,omitempty" xorm:"feed_pipeline_avatar"`
Email string `json:"author_email,omitempty" xorm:"feed_pipeline_email"` Email string `json:"author_email,omitempty" xorm:"feed_pipeline_email"`
} } // @name Feed

View file

@ -34,15 +34,15 @@ type Perm struct {
Synced int64 `json:"synced" xorm:"perm_synced"` Synced int64 `json:"synced" xorm:"perm_synced"`
Created int64 `json:"created" xorm:"created"` Created int64 `json:"created" xorm:"created"`
Updated int64 `json:"updated" xorm:"updated"` Updated int64 `json:"updated" xorm:"updated"`
} } // @name Perm
// TableName return database table name for xorm // TableName return database table name for xorm
func (Perm) TableName() string { func (Perm) TableName() string {
return "perms" return "perms"
} }
// OrgPerm defines a organization permission for an individual user. // OrgPerm defines an organization permission for an individual user.
type OrgPerm struct { type OrgPerm struct {
Member bool `json:"member"` Member bool `json:"member"`
Admin bool `json:"admin"` Admin bool `json:"admin"`
} } // @name OrgPerm

View file

@ -15,7 +15,6 @@
package model package model
// swagger:model pipeline
type Pipeline struct { type Pipeline struct {
ID int64 `json:"id" xorm:"pk autoincr 'pipeline_id'"` ID int64 `json:"id" xorm:"pk autoincr 'pipeline_id'"`
RepoID int64 `json:"-" xorm:"UNIQUE(s) INDEX 'pipeline_repo_id'"` RepoID int64 `json:"-" xorm:"UNIQUE(s) INDEX 'pipeline_repo_id'"`
@ -52,7 +51,7 @@ type Pipeline struct {
ChangedFiles []string `json:"changed_files,omitempty" xorm:"json 'changed_files'"` ChangedFiles []string `json:"changed_files,omitempty" xorm:"json 'changed_files'"`
AdditionalVariables map[string]string `json:"variables,omitempty" xorm:"json 'additional_variables'"` AdditionalVariables map[string]string `json:"variables,omitempty" xorm:"json 'additional_variables'"`
PullRequestLabels []string `json:"pr_labels,omitempty" xorm:"json 'pr_labels'"` PullRequestLabels []string `json:"pr_labels,omitempty" xorm:"json 'pr_labels'"`
} } // @name Pipeline
// TableName return database table name for xorm // TableName return database table name for xorm
func (Pipeline) TableName() string { func (Pipeline) TableName() string {
@ -66,4 +65,4 @@ type UpdatePipelineStore interface {
type PipelineOptions struct { type PipelineOptions struct {
Branch string `json:"branch"` Branch string `json:"branch"`
Variables map[string]string `json:"variables"` Variables map[string]string `json:"variables"`
} } // @name PipelineOptions

View file

@ -3,4 +3,4 @@ package model
type PullRequest struct { type PullRequest struct {
Index int64 `json:"index"` Index int64 `json:"index"`
Title string `json:"title"` Title string `json:"title"`
} } // @name PullRequest

View file

@ -51,7 +51,6 @@ type RegistryStore interface {
} }
// Registry represents a docker registry with credentials. // Registry represents a docker registry with credentials.
// swagger:model registry
type Registry struct { type Registry struct {
ID int64 `json:"id" xorm:"pk autoincr 'registry_id'"` ID int64 `json:"id" xorm:"pk autoincr 'registry_id'"`
RepoID int64 `json:"-" xorm:"UNIQUE(s) INDEX 'registry_repo_id'"` RepoID int64 `json:"-" xorm:"UNIQUE(s) INDEX 'registry_repo_id'"`
@ -60,7 +59,7 @@ type Registry struct {
Password string `json:"password" xorm:"TEXT 'registry_password'"` Password string `json:"password" xorm:"TEXT 'registry_password'"`
Token string `json:"token" xorm:"TEXT 'registry_token'"` Token string `json:"token" xorm:"TEXT 'registry_token'"`
Email string `json:"email" xorm:"varchar(500) 'registry_email'"` Email string `json:"email" xorm:"varchar(500) 'registry_email'"`
} } // @name Registry
// Validate validates the registry information. // Validate validates the registry information.
func (r *Registry) Validate() error { func (r *Registry) Validate() error {

View file

@ -21,8 +21,6 @@ import (
) )
// Repo represents a repository. // Repo represents a repository.
//
// swagger:model repo
type Repo struct { type Repo struct {
ID int64 `json:"id,omitempty" xorm:"pk autoincr 'repo_id'"` ID int64 `json:"id,omitempty" xorm:"pk autoincr 'repo_id'"`
UserID int64 `json:"-" xorm:"repo_user_id"` UserID int64 `json:"-" xorm:"repo_user_id"`
@ -48,7 +46,7 @@ type Repo struct {
Perm *Perm `json:"-" xorm:"-"` Perm *Perm `json:"-" xorm:"-"`
CancelPreviousPipelineEvents []WebhookEvent `json:"cancel_previous_pipeline_events" xorm:"json 'cancel_previous_pipeline_events'"` CancelPreviousPipelineEvents []WebhookEvent `json:"cancel_previous_pipeline_events" xorm:"json 'cancel_previous_pipeline_events'"`
NetrcOnlyTrusted bool `json:"netrc_only_trusted" xorm:"NOT NULL DEFAULT true 'netrc_only_trusted'"` NetrcOnlyTrusted bool `json:"netrc_only_trusted" xorm:"NOT NULL DEFAULT true 'netrc_only_trusted'"`
} } // @name Repo
// TableName return database table name for xorm // TableName return database table name for xorm
func (Repo) TableName() string { func (Repo) TableName() string {
@ -109,7 +107,7 @@ type RepoPatch struct {
AllowPull *bool `json:"allow_pr,omitempty"` AllowPull *bool `json:"allow_pr,omitempty"`
CancelPreviousPipelineEvents *[]WebhookEvent `json:"cancel_previous_pipeline_events"` CancelPreviousPipelineEvents *[]WebhookEvent `json:"cancel_previous_pipeline_events"`
NetrcOnlyTrusted *bool `json:"netrc_only_trusted"` NetrcOnlyTrusted *bool `json:"netrc_only_trusted"`
} } // @name RepoPatch
type ForgeRemoteID string type ForgeRemoteID string

View file

@ -68,7 +68,6 @@ type SecretStore interface {
} }
// Secret represents a secret variable, such as a password or token. // Secret represents a secret variable, such as a password or token.
// swagger:model registry
type Secret struct { type Secret struct {
ID int64 `json:"id" xorm:"pk autoincr 'secret_id'"` ID int64 `json:"id" xorm:"pk autoincr 'secret_id'"`
Owner string `json:"-" xorm:"NOT NULL DEFAULT '' UNIQUE(s) INDEX 'secret_owner'"` Owner string `json:"-" xorm:"NOT NULL DEFAULT '' UNIQUE(s) INDEX 'secret_owner'"`
@ -80,7 +79,7 @@ type Secret struct {
Events []WebhookEvent `json:"event" xorm:"json 'secret_events'"` Events []WebhookEvent `json:"event" xorm:"json 'secret_events'"`
SkipVerify bool `json:"-" xorm:"secret_skip_verify"` SkipVerify bool `json:"-" xorm:"secret_skip_verify"`
Conceal bool `json:"-" xorm:"secret_conceal"` Conceal bool `json:"-" xorm:"secret_conceal"`
} } // @name Secret
// TableName return database table name for xorm // TableName return database table name for xorm
func (Secret) TableName() string { func (Secret) TableName() string {

View file

@ -29,7 +29,6 @@ type StepStore interface {
} }
// Step represents a process in the pipeline. // Step represents a process in the pipeline.
// swagger:model step
type Step struct { type Step struct {
ID int64 `json:"id" xorm:"pk autoincr 'step_id'"` ID int64 `json:"id" xorm:"pk autoincr 'step_id'"`
PipelineID int64 `json:"pipeline_id" xorm:"UNIQUE(s) INDEX 'step_pipeline_id'"` PipelineID int64 `json:"pipeline_id" xorm:"UNIQUE(s) INDEX 'step_pipeline_id'"`
@ -46,7 +45,7 @@ type Step struct {
Platform string `json:"platform,omitempty" xorm:"step_platform"` Platform string `json:"platform,omitempty" xorm:"step_platform"`
Environ map[string]string `json:"environ,omitempty" xorm:"json 'step_environ'"` Environ map[string]string `json:"environ,omitempty" xorm:"json 'step_environ'"`
Children []*Step `json:"children,omitempty" xorm:"-"` Children []*Step `json:"children,omitempty" xorm:"-"`
} } // @name Step
type UpdateStepStore interface { type UpdateStepStore interface {
StepUpdate(*Step) error StepUpdate(*Step) error

View file

@ -35,7 +35,7 @@ type Task struct {
RunOn []string `json:"run_on" xorm:"json 'task_run_on'"` RunOn []string `json:"run_on" xorm:"json 'task_run_on'"`
DepStatus map[string]StatusValue `json:"dep_status" xorm:"json 'task_dep_status'"` DepStatus map[string]StatusValue `json:"dep_status" xorm:"json 'task_dep_status'"`
AgentID int64 `json:"agent_id" xorm:"'agent_id'"` AgentID int64 `json:"agent_id" xorm:"'agent_id'"`
} } // @name Task
// TableName return database table name for xorm // TableName return database table name for xorm
func (Task) TableName() string { func (Task) TableName() string {

View file

@ -15,8 +15,6 @@
package model package model
// Team represents a team or organization in the forge. // Team represents a team or organization in the forge.
//
// swagger:model user
type Team struct { type Team struct {
// Login is the username for this team. // Login is the username for this team.
Login string `json:"login"` Login string `json:"login"`

View file

@ -26,8 +26,6 @@ var reUsername = regexp.MustCompile("^[a-zA-Z0-9-_.]+$")
var errUserLoginInvalid = errors.New("Invalid User Login") var errUserLoginInvalid = errors.New("Invalid User Login")
// User represents a registered user. // User represents a registered user.
//
// swagger:model user
type User struct { type User struct {
// the id for this user. // the id for this user.
// //
@ -66,7 +64,7 @@ type User struct {
// Hash is a unique token used to sign tokens. // Hash is a unique token used to sign tokens.
Hash string `json:"-" xorm:"UNIQUE varchar(500) 'user_hash'"` Hash string `json:"-" xorm:"UNIQUE varchar(500) 'user_hash'"`
} } // @name User
// TableName return database table name for xorm // TableName return database table name for xorm
func (User) TableName() string { func (User) TableName() string {

View file

@ -29,7 +29,7 @@ type InfoT struct {
Complete int `json:"completed_count"` Complete int `json:"completed_count"`
} `json:"stats"` } `json:"stats"`
Paused bool `json:"paused"` Paused bool `json:"paused"`
} } // @name InfoT
func (t *InfoT) String() string { func (t *InfoT) String() string {
var sb strings.Builder var sb strings.Builder

View file

@ -16,9 +16,14 @@ package router
import ( import (
"net/http" "net/http"
"net/url"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
swaggerfiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
"github.com/woodpecker-ci/woodpecker/cmd/server/docs"
"github.com/woodpecker-ci/woodpecker/server"
"github.com/woodpecker-ci/woodpecker/server/api" "github.com/woodpecker-ci/woodpecker/server/api"
"github.com/woodpecker-ci/woodpecker/server/api/metrics" "github.com/woodpecker-ci/woodpecker/server/api/metrics"
@ -64,6 +69,18 @@ func Load(noRouteHandler http.HandlerFunc, middleware ...gin.HandlerFunc) http.H
e.GET("/healthz", api.Health) e.GET("/healthz", api.Health)
apiRoutes(e) apiRoutes(e)
setupSwaggerConfigAndRoutes(e)
return e return e
} }
func setupSwaggerConfigAndRoutes(e *gin.Engine) {
docs.SwaggerInfo.Host = getHost(server.Config.Server.Host)
docs.SwaggerInfo.BasePath = server.Config.Server.RootURL + "/api"
e.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler))
}
func getHost(s string) string {
parse, _ := url.Parse(s)
return parse.Host
}

View file

@ -1,31 +0,0 @@
// Copyright 2018 Drone.IO Inc.
//
// 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 classification Drone API.
//
// Schemes: http, https
// BasePath: /api
// Version: 1.0.0
//
// Consumes:
// - application/json
//
// Produces:
// - application/json
//
// swagger:meta
package swagger
//go:generate swagger generate spec -o files/swagger.json
//go:generate go-bindata -pkg swagger -o swagger_gen.go files/

View file

@ -1,991 +0,0 @@
swagger: "2.0"
info:
version: 1.0.0
title: Woodpecker API
license:
name: Creative Commons 4.0 International
url: "http://creativecommons.org/licenses/by/4.0/"
host: "localhost:8080"
basePath: /api
schemes:
- http
- https
consumes:
- application/json
produces:
- application/json
#
# Operation tags
#
tags:
- name: Repos
- name: Builds
- name: User
- name: Users
#
# Security Definitions
#
security:
- accessToken: []
securityDefinitions:
accessToken:
type: apiKey
in: query
name: access_token
#
# Endpoint Definitions
#
paths:
#
# Repos Endpoint
#
/repos/{owner}/{name}:
get:
parameters:
- name: owner
in: path
type: string
description: owner of the repository
- name: name
in: path
type: string
description: name of the repository
tags:
- Repos
summary: Get a repo
description: Retrieves the details of a repository.
security:
- accessToken: []
responses:
200:
schema:
$ref: "#/definitions/Repo"
404:
description: |
Unable to find the repository.
patch:
parameters:
- name: owner
in: path
type: string
description: owner of the repository
- name: name
in: path
type: string
description: name of the repository
- name: repo
in: body
description: The updated repository JSON
schema:
$ref: '#/definitions/Repo'
example: |
{
"timeout": 60,
"private": false,
"trusted": false,
"allow_pr": true
}
required: true
tags:
- Repos
summary: Updates a repo
description: Updates the specified repository.
security:
- accessToken: []
responses:
200:
schema:
$ref: "#/definitions/Repo"
400:
description: |
Unable to update the repository in the database.
404:
description: |
Unable to find the repository.
post:
parameters:
- name: owner
in: path
type: string
description: owner of the repository
- name: name
in: path
type: string
description: name of the repository
tags:
- Repos
summary: Activates a repo
description: Activates a repository.
security:
- accessToken: []
responses:
200:
schema:
$ref: "#/definitions/Repo"
400:
description: |
Unable to update the Repository record in the database
403:
description: |
Unable to activate the Repository due to insufficient privileges
404:
description: |
Unable to retrieve the Repository from the remote system (ie GitHub)
409:
description: |
Unable to activate the Repository because it is already activate
500:
description: |
Unable to activate the Repository due to an internal server error. This may indicate a problem adding hooks to the remote system (ie GitHub), generating SSH deployment keys, or persisting to the database.
delete:
parameters:
- name: owner
in: path
type: string
description: owner of the repository
- name: name
in: path
type: string
description: name of the repository
tags:
- Repos
summary: Delete a repo
description: Permanently deletes a repository. It cannot be undone.
security:
- accessToken: []
responses:
200:
description: |
Successfully deleted the Repository
400:
description: |
Unable to remove post-commit hooks from the remote system (ie GitHub)
404:
description: |
Unable to find the Repository in the database
500:
description: |
Unable to update the Repository record in the database
#
# Repos Param Encryption Endpoint
# TODO: properly add the input output schema
/repos/{owner}/{name}/encrypt:
post:
parameters:
- name: owner
in: path
type: string
description: owner of the repository
- name: name
in: path
type: string
description: name of the repository
tags:
- Repos
summary: Encrypt repo secrets
description: Encrypts a Yaml file with secret environment variables for secure public storage.
security:
- accessToken: []
responses:
200:
description: The encrypted parameters.
400:
description: |
Unable to encrypt the parameters.
404:
description: |
Unable to find the repository.
#
# Builds Endpoint
#
/repos/{owner}/{name}/builds:
get:
parameters:
- name: owner
in: path
type: string
description: owner of the repository
- name: name
in: path
type: string
description: name of the repository
tags:
- Builds
summary: Get recent builds
description: Returns recent builds for the repository based on name.
security:
- accessToken: []
responses:
200:
description: The recent builds.
schema:
type: array
items:
$ref: "#/definitions/Build"
404:
description: |
Unable to find the Repository in the database
/repos/{owner}/{name}/builds/{number}:
get:
parameters:
- name: owner
in: path
type: string
description: owner of the repository
- name: name
in: path
type: string
description: name of the repository
- name: branch
in: query
type: string
description: name of the branch
required: false
- name: number
in: path
type: integer
description: sequential build number
tags:
- Builds
summary: Get the latest build
description: Returns the latest repository build.
security:
- accessToken: []
responses:
200:
description: The build.
schema:
$ref: "#/definitions/Build"
404:
description: |
Unable to find the Repository or Build
post:
parameters:
- name: owner
in: path
type: string
description: owner of the repository
- name: name
in: path
type: string
description: name of the repository
- name: number
in: path
type: integer
description: sequential build number
tags:
- Builds
summary: Restart a build
description: Restart the a build by number.
security:
- accessToken: []
responses:
200:
description: Successfully restarted the Pipeline.
schema:
$ref: "#/definitions/Build"
404:
description: |
Unable to find the Repository or Build.
409:
description: |
Cannot re-start a Build that is running.
#
# Jobs Endpoint
#
/repos/{owner}/{name}/logs/{number}/{job}:
get:
parameters:
- name: owner
in: path
type: string
description: owner of the repository
- name: name
in: path
type: string
description: name of the repository
- name: number
in: path
type: integer
description: sequential build number
- name: job
in: path
type: integer
description: sequential job number
tags:
- Builds
summary: Get build logs
description: Returns the build logs for a specific job (build step).
produces:
- text/plain
security:
- accessToken: []
responses:
200:
description: The logs for the requested job.
404:
description: |
Unable to find the repository, build or job.
delete:
parameters:
- name: owner
in: path
type: string
description: owner of the repository
- name: name
in: path
type: string
description: name of the repository
- name: number
in: path
type: integer
description: sequential build number
- name: job
in: path
type: integer
description: sequential job number
tags:
- Builds
summary: Cancel a Job
description: Cancel the a build job by number.
security:
- accessToken: []
responses:
200:
description: Successfully canceled the Job
404:
description: |
Unable to find the Repository or Job
409:
description: |
Cannot cancel a Job that is already stopped
#
# User Endpoint
#
/user:
get:
summary: Gets a user
description: Returns the currently authenticated user.
security:
- accessToken: []
tags:
- User
responses:
200:
description: The currently authenticated user.
schema:
$ref: "#/definitions/User"
patch:
summary: Updates a user
description: Updates the currently authenticated user.
tags:
- User
parameters:
- name: user
in: body
description: Updates to the user.
required: true
schema:
$ref: "#/definitions/User"
responses:
200:
description: The updated user.
schema:
$ref: "#/definitions/User"
400:
description: |
Unable to update the user in the database
#
# User Repos
#
/user/repos:
get:
summary: Get user repos
description: |
Retrieve the currently authenticated User's Repository list
tags:
- User
responses:
200:
schema:
type: array
items:
$ref: "#/definitions/Repo"
400:
description: |
Unable to retrieve Repository list
#
# Users Endpoint
#
/users:
get:
tags:
- Users
summary: Get all users
description: Returns all registered, active users in the system.
security:
- accessToken: []
responses:
200:
description: All registered users.
schema:
type: array
items:
$ref: "#/definitions/User"
/users/{login}:
get:
parameters:
- name: login
in: path
type: string
description: user login
tags:
- Users
summary: Get a user
description: Returns a user with the specified login name.
security:
- accessToken: []
responses:
200:
description: Returns the user.
schema:
$ref: "#/definitions/User"
404:
description: Cannot find user with matching login.
post:
parameters:
- name: login
in: path
type: string
description: user login to activate
tags:
- Users
summary: Create a user
description: Creates a new user account with the specified external login.
security:
- accessToken: []
responses:
201:
description: Returns the created user.
schema:
$ref: "#/definitions/User"
400:
description: |
Error inserting User into the database
patch:
parameters:
- name: login
in: path
type: string
description: user login
- name: user
in: body
description: changes to the user
schema:
$ref: '#/definitions/User'
example: |
{
"email": "octocat@github.com",
"admin": false,
"active": true
}
required: true
tags:
- Users
summary: Update a user
description: Updates an existing user account.
security:
- accessToken: []
responses:
200:
description: Returns the updated user.
schema:
$ref: "#/definitions/User"
400:
description: |
Error updating the User in the database
delete:
parameters:
- name: login
in: path
type: string
description: user login
tags:
- Users
summary: Delete a user
description: Deletes the user with the specified login name.
security:
- accessToken: []
responses:
204:
description: |
Successfully deleted the User
400:
description: |
Error deleting the User from the database
403:
description: |
Cannot delete your own User account
404:
description: |
Cannot find the User
#
# Schema Definitions
#
definitions:
User:
description: The user account.
example: |
{
"id": 1,
"login": "octocat",
"email": "octocat@github.com",
"avatar_url": "http://www.gravatar.com/avatar/7194e8d48fa1d2b689f99443b767316c",
"admin": false,
"active": true
}
properties:
id:
description: The unique identifier for the account.
type: integer
format: int64
login:
description: The login name for the account.
type: string
email:
description: The email address for the account.
type: string
avatar_url:
description: The url for the avatar image.
type: string
admin:
description: Whether the account has administrative privileges.
type: boolean
active:
description: Whether the account is currently active.
type: boolean
Repo:
description: A version control repository.
example: |
{
"id": 1,
"scm": "git",
"owner": "octocat",
"name": "hello-world",
"full_name": "octocat/hello-world",
"avatar_url": "https://avatars.githubusercontent.com/u/2181346?v=3",
"link_url": "https://github.com/octocat/hello-world",
"clone_url": "https://github.com/octocat/hello-world.git",
"default_branch": "master",
"timeout": 60,
"private": false,
"trusted": false,
"allow_pr": true
}
properties:
id:
description: The unique identifier for the repository.
type: integer
format: int64
scm:
description: |
The source control management being used.
Currently this is either 'git' or 'hg' (Mercurial).
type: string
owner:
description: The owner of the repository.
type: string
name:
description: The name of the repository.
type: string
full_name:
description: |
The full name of the repository.
This is created from the owner and name of the repository.
type: string
avatar_url:
description: The url for the avatar image.
type: string
link_url:
description: The link to view the repository.
type: string
clone_url:
description: The url used to clone the repository.
type: string
default_branch:
description: The default branch of the repository.
type: string
private:
description: Whether the repository is publicly visible.
type: boolean
trusted:
description: |
Whether the repository has trusted access for builds.
If the repository is trusted then the host network can be used and
volumes can be created.
type: boolean
timeout:
description: The amount of time in minutes before the build is killed.
type: integer
x-dart-type: Duration
allow_pr:
description: Whether pull requests should trigger a build.
type: boolean
Build:
description: A build for a repository.
example: |
{
"id": 1,
"number": 1,
"event": "push",
"status": "success",
"created_at": 1443677151,
"enqueued_at": 1443677151,
"started_at": 1443677151,
"finished_at": 1443677255,
"commit": "2deb7e0d0cbac357eeb110c8a2f2f32ce037e0d5",
"branch": "master",
"ref": "refs/heads/master",
"remote": "https://github.com/octocat/hello-world.git",
"message": "New line at end of file. --Signed off by Spaceghost",
"timestamp": 1443677255,
"author": "Spaceghost",
"author_avatar": "https://avatars0.githubusercontent.com/u/251370?v=3",
"author_email": "octocat@github.com",
"link_url": "https://github.com/octocat/hello-world/commit/762941318ee16e59dabbacb1b4049eec22f0d303",
"jobs": [
{
"id": 1,
"number": 1,
"status": "success",
"enqueued_at": 1443677151,
"started_at": 1443677151,
"finished_at": 1443677255,
"exit_code": 0,
"environment": { "GO_VERSION": "1.4" }
},
{
"id": 2,
"number": 2,
"status": "success",
"enqueued_at": 1443677151,
"started_at": 1443677151,
"finished_at": 1443677255,
"exit_code": 0,
"environment": { "GO_VERSION": "1.5" }
}
]
}
properties:
id:
type: integer
format: int64
number:
description: |
The build number.
This number is specified within the context of the repository the build
belongs to and is unique within that.
type: integer
status:
description: The current status of the build.
$ref: '#definitions/BuildStatus'
created_at:
description: When the build request was received.
type: integer
format: int64
x-dart-type: DateTime
enqueued_at:
description: When the build was enqueued.
type: integer
format: int64
x-dart-type: DateTime
started_at:
description: When the build began execution.
type: integer
format: int64
x-dart-type: DateTime
finished_at:
description: When the build was finished.
type: integer
format: int64
x-dart-type: DateTime
deploy_to:
description: Where the deployment should go.
type: string
commit:
description: The commit for the build.
type: string
branch:
description: The branch the commit was pushed to.
type: string
message:
description: The commit message.
type: string
timestamp:
description: When the commit was created.
type: integer
format: int64
x-dart-format: DateTime
ref:
description: The alias for the commit.
type: string
refspec:
description: The mapping from the local repository to a branch in the remote.
type: string
remote:
description: The remote repository.
type: string
author:
description: The login for the author of the commit.
type: string
author_avatar:
description: The avatar for the author of the commit.
type: string
author_email:
description: The email for the author of the commit.
type: string
link_url:
description: |
The link to view the repository.
This link will point to the repository state associated with the
build's commit.
type: string
jobs:
description: |
The jobs associated with this build.
A build will have multiple jobs if a matrix build was used or if a
rebuild was requested.
type: array
items:
$ref: "#/definitions/Job"
BuildStatus:
description: The status of a build.
type: string
enum:
- success
- failure
- pending
- started
- error
- killed
x-enum-descriptions:
- The build was successful.
- The build failed.
- The build is pending execution.
- The build was started.
- There was an error running the build.
- The build was killed either manually or through a timeout.
Job:
description: A single job being executed as part of a build.
example: |
{
"id": 1,
"number": 1,
"status": "success",
"enqueued_at": 1443677151,
"started_at": 1443677151,
"finished_at": 1443677255,
"exit_code": 0,
"environment": { "GO_VERSION": "1.4" }
}
properties:
id:
description: The unique identifier for the build.
type: integer
format: int64
number:
description: |
The job number.
This number is specified within the context of the build the job
belongs to and is unique within that.
type: integer
status:
description: The current status of the job.
$ref: '#definitions/BuildStatus'
exit_code:
description: The exit code for the build.
type: integer
enqueued_at:
description: When the job was enqueued.
type: integer
format: int64
x-dart-type: DateTime
started_at:
description: When the job began execution.
type: integer
format: int64
x-dart-type: DateTime
finished_at:
description: When the job finished execution.
type: integer
format: int64
x-dart-type: DateTime
environment:
description: |
The environment that the job was run with.
This is a map containing any values for matrix builds.
type: object
Feed:
description: |
A feed entry for a build.
Feed entries can be used to display information on the latest builds.
example: |
{
"owner": "octocat",
"name": "hello-world",
"full_name": "octocat/hello-world",
"number": 1,
"event": "push",
"status": "success",
"created_at": 1443677151,
"enqueued_at": 1443677151,
"started_at": 1443677151,
"finished_at": 1443677255,
"commit": "2deb7e0d0cbac357eeb110c8a2f2f32ce037e0d5",
"branch": "master",
"ref": "refs/heads/master",
"remote": "https://github.com/octocat/hello-world.git",
"message": "New line at end of file. --Signed off by Spaceghost",
"timestamp": 1443677255,
"author": "Spaceghost",
"author_avatar": "https://avatars0.githubusercontent.com/u/251370?v=3",
"author_email": "octocat@github.com",
"link_url": "https://github.com/octocat/hello-world/commit/762941318ee16e59dabbacb1b4049eec22f0d303",
}
properties:
owner:
description: The owner of the repository.
type: string
name:
description: The name of the repository.
type: string
full_name:
description: |
The full name of the repository.
This is created from the owner and name of the repository.
type: string
number:
description: |
The build number.
This number is specified within the context of the repository the build
belongs to and is unique within that.
type: integer
status:
description: The current status of the build.
$ref: '#definitions/BuildStatus'
created_at:
description: When the build request was received.
type: integer
format: int64
x-dart-type: DateTime
enqueued_at:
description: When the build was enqueued.
type: integer
format: int64
x-dart-type: DateTime
started_at:
description: When the build began execution.
type: integer
format: int64
x-dart-type: DateTime
finished_at:
description: When the build was finished.
type: integer
format: int64
x-dart-type: DateTime
commit:
description: The commit for the build.
type: string
branch:
description: The branch the commit was pushed to.
type: string
message:
description: The commit message.
type: string
timestamp:
description: When the commit was created.
type: integer
format: int64
x-dart-format: DateTime
ref:
description: The alias for the commit.
type: string
refspec:
description: The mapping from the local repository to a branch in the remote.
type: string
remote:
description: The remote repository.
type: string
author:
description: The login for the author of the commit.
type: string
author_avatar:
description: The avatar for the author of the commit.
type: string
author_email:
description: The email for the author of the commit.
type: string
link_url:
description: |
The link to view the repository.
This link will point to the repository state associated with the
build's commit.
type: string

View file

@ -19,7 +19,10 @@
</div> </div>
<div> <div>
<h2 class="text-lg text-color">{{ $t('user.api_usage') }}</h2> <div class="flex items-center">
<h2 class="text-lg text-color">{{ $t('user.api_usage') }}</h2>
<a :href="`${address}/swagger/index.html`" target="_blank" class="ml-4 text-link">Swagger UI</a>
</div>
<pre class="cli-box">{{ usageWithCurl }}</pre> <pre class="cli-box">{{ usageWithCurl }}</pre>
</div> </div>