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",
"server/store/datastore/migration/testfiles/sqlite.db",
"server/store/datastore/feed.go",
"cmd/server/docs/docs.go",
"_test.go",
"Makefile"
]

4
.gitignore vendored
View file

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

View file

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

View file

@ -45,6 +45,16 @@ pipeline:
when:
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:
image: mstruebing/editorconfig-checker
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
.PHONY: generate
generate: ## Run all code generations
generate: generate-swagger ## Run all code generations
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
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install src.techknowlogick.com/xgo@latest; \
@ -108,6 +111,9 @@ install-tools: ## Install development tools
fi ; \
hash gofumpt > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
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
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
(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
build-agent: ## Build agent
@ -284,5 +290,6 @@ bundle: bundle-agent bundle-server bundle-cli ## Create all bundles
.PHONY: docs
docs: ## Generate docs (currently only for the cli)
go generate cmd/cli/app.go
go generate cmd/server/swagger.go
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/urfave/cli/v2"
_ "github.com/woodpecker-ci/woodpecker/cmd/server/docs"
"github.com/woodpecker-ci/woodpecker/version"
)
@ -32,6 +33,8 @@ func main() {
app.Action = run
app.Flags = flags
setupSwaggerStaticConfig()
if err := app.Run(os.Args); err != nil {
_, _ = fmt.Fprintln(os.Stderr, err)
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/go-ap/httpsig v0.0.0-20221203064646-3647b4d88fdf
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/google/go-github/v39 v39.2.0
github.com/google/tink/go v1.7.0
@ -38,6 +39,9 @@ require (
github.com/robfig/cron v1.2.0
github.com/rs/zerolog v1.29.1
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/urfave/cli/v2 v2.25.3
github.com/xanzy/go-gitlab v0.83.0
@ -59,7 +63,12 @@ require (
require (
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/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bytedance/sonic v1.9.1 // 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/go-fed/httpsig v1.1.0 // 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/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/validate v0.22.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // 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-retryablehttp v0.7.2 // 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/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // 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/libdns/libdns v0.2.1 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mholt/acmez v1.0.4 // 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/reflect2 v1.0.2 // indirect
github.com/morikuni/aec v1.0.0 // 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/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/pkg/sftp v1.13.5 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.42.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/shopspring/decimal v1.2.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/viper v1.14.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/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // 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/multierr v1.6.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.23.0 // indirect
golang.org/x/arch v0.3.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/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // 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
gotest.tools/v3 v3.4.0 // 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"
)
// 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) {
agents, err := store.FromContext(c).AgentList(session.Pagination(c))
if err != nil {
@ -37,6 +47,15 @@ func GetAgents(c *gin.Context) {
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) {
agentID, err := strconv.ParseInt(c.Param("agent"), 10, 64)
if err != nil {
@ -52,6 +71,15 @@ func GetAgent(c *gin.Context) {
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) {
agentID, err := strconv.ParseInt(c.Param("agent"), 10, 64)
if err != nil {
@ -76,6 +104,16 @@ func GetAgentTasks(c *gin.Context) {
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) {
_store := store.FromContext(c)
@ -109,7 +147,15 @@ func PatchAgent(c *gin.Context) {
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) {
in := &model.Agent{}
err := c.Bind(in)
@ -135,6 +181,15 @@ func PostAgent(c *gin.Context) {
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) {
_store := store.FromContext(c)

View file

@ -34,6 +34,15 @@ import (
"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) {
_store := store.FromContext(c)
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))
}
// 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) {
_store := store.FromContext(c)
repo, err := _store.GetRepoName(c.Param("owner") + "/" + c.Param("name"))

View file

@ -28,8 +28,17 @@ import (
"github.com/woodpecker-ci/woodpecker/server/store"
)
// GetCron gets a cron job by id from the database and writes
// to the response in json format.
// GetCron
//
// @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) {
repo := session.Repo(c)
id, err := strconv.ParseInt(c.Param("cron"), 10, 64)
@ -46,7 +55,17 @@ func GetCron(c *gin.Context) {
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) {
repo := session.Repo(c)
_store := store.FromContext(c)
@ -77,7 +96,17 @@ func RunCron(c *gin.Context) {
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) {
repo := session.Repo(c)
user := session.User(c)
@ -124,7 +153,18 @@ func PostCron(c *gin.Context) {
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) {
repo := session.Repo(c)
user := session.User(c)
@ -183,8 +223,18 @@ func PatchCron(c *gin.Context) {
c.JSON(http.StatusOK, cron)
}
// GetCronList gets the cron job list from the database and writes
// to the response in json format.
// GetCronList
//
// @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) {
repo := session.Repo(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)
}
// 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) {
repo := session.Repo(c)
id, err := strconv.ParseInt(c.Param("cron"), 10, 64)

View file

@ -20,63 +20,146 @@ import (
"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 {
return func(c *gin.Context) {
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 {
return func(c *gin.Context) {
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 {
return func(c *gin.Context) {
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 {
return func(c *gin.Context) {
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 {
return func(c *gin.Context) {
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 {
return func(c *gin.Context) {
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 {
return func(c *gin.Context) {
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 {
return func(c *gin.Context) {
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 {
return func(c *gin.Context) {
pprof.Trace(c.Writer, c.Request)

View file

@ -24,8 +24,16 @@ import (
"github.com/woodpecker-ci/woodpecker/server/model"
)
// GetGlobalSecretList gets the global secret list from
// the database and writes to the response in json format.
// GetGlobalSecretList
//
// @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) {
list, err := server.Config.Services.Secrets.GlobalSecretList(session.Pagination(c))
if err != nil {
@ -40,8 +48,15 @@ func GetGlobalSecretList(c *gin.Context) {
c.JSON(http.StatusOK, list)
}
// GetGlobalSecret gets the named global secret from the database
// and writes to the response in json format.
// GetGlobalSecret
//
// @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) {
name := c.Param("secret")
secret, err := server.Config.Services.Secrets.GlobalSecretFind(name)
@ -52,7 +67,15 @@ func GetGlobalSecret(c *gin.Context) {
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) {
in := new(model.Secret)
if err := c.Bind(in); err != nil {
@ -77,7 +100,16 @@ func PostGlobalSecret(c *gin.Context) {
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) {
name := c.Param("secret")
@ -115,7 +147,15 @@ func PatchGlobalSecret(c *gin.Context) {
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) {
name := c.Param("secret")
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)\]`)
// 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) {
c.IndentedJSON(http.StatusOK,
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) {
server.Config.Services.Queue.Pause()
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) {
server.Config.Services.Queue.Resume()
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) {
for {
info := server.Config.Services.Queue.Info(c)
@ -61,7 +94,14 @@ func BlockTilQueueHasRunningItem(c *gin.Context) {
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) {
_store := store.FromContext(c)
forge := server.Config.Services.Forge

View file

@ -24,7 +24,15 @@ import (
"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) {
var (
err error

View file

@ -24,8 +24,16 @@ import (
"github.com/woodpecker-ci/woodpecker/server/model"
)
// GetOrgSecret gets the named organization secret from the database
// and writes to the response in json format.
// GetOrgSecret
//
// @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) {
var (
owner = c.Param("owner")
@ -39,8 +47,17 @@ func GetOrgSecret(c *gin.Context) {
c.JSON(http.StatusOK, secret.Copy())
}
// GetOrgSecretList gets the organization secret list from
// the database and writes to the response in json format.
// GetOrgSecretList
//
// @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) {
owner := c.Param("owner")
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)
}
// 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) {
owner := c.Param("owner")
@ -84,7 +110,17 @@ func PostOrgSecret(c *gin.Context) {
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) {
var (
owner = c.Param("owner")
@ -125,7 +161,16 @@ func PatchOrgSecret(c *gin.Context) {
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) {
var (
owner = c.Param("owner")

View file

@ -39,6 +39,17 @@ import (
"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) {
_store := store.FromContext(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) {
repo := session.Repo(c)
@ -101,6 +124,17 @@ func GetPipelines(c *gin.Context) {
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) {
_store := store.FromContext(c)
if c.Param("number") == "latest" {
@ -156,6 +190,19 @@ func GetPipelineLast(c *gin.Context) {
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) {
_store := store.FromContext(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) {
_store := store.FromContext(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) {
_store := store.FromContext(c)
repo := session.Repo(c)
@ -251,7 +321,17 @@ func GetPipelineConfig(c *gin.Context) {
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) {
_store := store.FromContext(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) {
var (
_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) {
var (
_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) {
out, err := store.FromContext(c).GetPipelineQueue()
if err != nil {
@ -326,7 +434,20 @@ func GetPipelineQueue(c *gin.Context) {
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) {
_store := store.FromContext(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) {
_store := store.FromContext(c)

View file

@ -24,8 +24,17 @@ import (
"github.com/woodpecker-ci/woodpecker/server/router/middleware/session"
)
// GetRegistry gets the name registry from the database and writes
// to the response in json format.
// GetRegistry
//
// @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) {
var (
repo = session.Repo(c)
@ -39,7 +48,17 @@ func GetRegistry(c *gin.Context) {
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) {
repo := session.Repo(c)
@ -67,7 +86,18 @@ func PostRegistry(c *gin.Context) {
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) {
var (
repo = session.Repo(c)
@ -110,8 +140,18 @@ func PatchRegistry(c *gin.Context) {
c.JSON(http.StatusOK, in.Copy())
}
// GetRegistryList gets the registry list from the database and writes
// to the response in json format.
// GetRegistryList
//
// @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) {
repo := session.Repo(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)
}
// 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) {
var (
repo = session.Repo(c)

View file

@ -35,6 +35,16 @@ import (
"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) {
forge := server.Config.Services.Forge
_store := store.FromContext(c)
@ -134,6 +144,17 @@ func PostRepo(c *gin.Context) {
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) {
_store := store.FromContext(c)
repo := session.Repo(c)
@ -194,6 +215,16 @@ func PatchRepo(c *gin.Context) {
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) {
_store := store.FromContext(c)
repo := session.Repo(c)
@ -208,15 +239,48 @@ func ChownRepo(c *gin.Context) {
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) {
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) {
perm := session.Perm(c)
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) {
repo := session.Repo(c)
user := session.User(c)
@ -231,6 +295,18 @@ func GetRepoBranches(c *gin.Context) {
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) {
repo := session.Repo(c)
user := session.User(c)
@ -245,6 +321,16 @@ func GetRepoPullRequests(c *gin.Context) {
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) {
remove, _ := strconv.ParseBool(c.Query("remove"))
_store := store.FromContext(c)
@ -274,6 +360,16 @@ func DeleteRepo(c *gin.Context) {
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) {
forge := server.Config.Services.Forge
_store := store.FromContext(c)
@ -336,6 +432,17 @@ func RepairRepo(c *gin.Context) {
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) {
forge := server.Config.Services.Forge
_store := store.FromContext(c)

View file

@ -25,8 +25,17 @@ import (
"github.com/woodpecker-ci/woodpecker/server/router/middleware/session"
)
// GetSecret gets the named secret from the database and writes
// to the response in json format.
// GetSecret
//
// @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) {
var (
repo = session.Repo(c)
@ -40,7 +49,17 @@ func GetSecret(c *gin.Context) {
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) {
repo := session.Repo(c)
@ -68,7 +87,18 @@ func PostSecret(c *gin.Context) {
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) {
var (
repo = session.Repo(c)
@ -109,8 +139,18 @@ func PatchSecret(c *gin.Context) {
c.JSON(http.StatusOK, secret.Copy())
}
// GetSecretList gets the secret list from the database and writes
// to the response in json format.
// GetSecretList
//
// @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) {
repo := session.Repo(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)
}
// 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) {
var (
repo = session.Repo(c)

View file

@ -24,6 +24,14 @@ import (
"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) {
b, err := x509.MarshalPKIXPublicKey(server.Config.Services.SignaturePublicKey)
if err != nil {

View file

@ -28,10 +28,27 @@ import (
"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) {
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) {
_store := store.FromContext(c)
@ -56,6 +73,15 @@ func GetFeed(c *gin.Context) {
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) {
_store := store.FromContext(c)
_forge := server.Config.Services.Forge
@ -97,6 +123,14 @@ func GetRepos(c *gin.Context) {
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) {
user := session.User(c)
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)
}
// 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) {
_store := store.FromContext(c)

View file

@ -26,6 +26,17 @@ import (
"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) {
users, err := store.FromContext(c).GetUserList(session.Pagination(c))
if err != nil {
@ -35,6 +46,16 @@ func GetUsers(c *gin.Context) {
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) {
user, err := store.FromContext(c).GetUserLogin(c.Param("login"))
if err != nil {
@ -44,6 +65,18 @@ func GetUser(c *gin.Context) {
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) {
_store := store.FromContext(c)
@ -75,6 +108,16 @@ func PatchUser(c *gin.Context) {
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) {
in := &model.User{}
err := c.Bind(in)
@ -101,6 +144,16 @@ func PostUser(c *gin.Context) {
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) {
_store := store.FromContext(c)

View file

@ -25,7 +25,15 @@ import (
"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) {
if err := store.FromContext(c).Ping(); err != nil {
c.String(http.StatusInternalServerError, err.Error())
@ -34,7 +42,14 @@ func Health(c *gin.Context) {
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) {
c.JSON(http.StatusOK, gin.H{
"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) {
c.JSON(http.StatusOK, gin.H{
"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) {
logLevel := struct {
LogLevel string `json:"log-level"`

View file

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

View file

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

View file

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

View file

@ -20,17 +20,16 @@ import (
"github.com/robfig/cron"
)
// swagger:model cron
type Cron struct {
ID int64 `json:"id" xorm:"pk autoincr"`
Name string `json:"name" xorm:"UNIQUE(s) INDEX"`
RepoID int64 `json:"repo_id" xorm:"repo_id UNIQUE(s) INDEX"`
CreatorID int64 `json:"creator_id" xorm:"creator_id INDEX"`
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"`
Branch string `json:"branch"`
}
} // @name Cron
// TableName returns the database table name for xorm
func (Cron) TableName() string {

View file

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

View file

@ -16,8 +16,6 @@
package model
// Feed represents an item in the user's feed or timeline.
//
// swagger:model feed
type Feed struct {
Owner string `json:"owner" xorm:"feed_repo_owner"`
Name string `json:"name" xorm:"feed_repo_name"`
@ -40,4 +38,4 @@ type Feed struct {
Author string `json:"author,omitempty" xorm:"feed_pipeline_author"`
Avatar string `json:"author_avatar,omitempty" xorm:"feed_pipeline_avatar"`
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"`
Created int64 `json:"created" xorm:"created"`
Updated int64 `json:"updated" xorm:"updated"`
}
} // @name Perm
// TableName return database table name for xorm
func (Perm) TableName() string {
return "perms"
}
// OrgPerm defines a organization permission for an individual user.
// OrgPerm defines an organization permission for an individual user.
type OrgPerm struct {
Member bool `json:"member"`
Admin bool `json:"admin"`
}
} // @name OrgPerm

View file

@ -15,7 +15,6 @@
package model
// swagger:model pipeline
type Pipeline struct {
ID int64 `json:"id" xorm:"pk autoincr 'pipeline_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'"`
AdditionalVariables map[string]string `json:"variables,omitempty" xorm:"json 'additional_variables'"`
PullRequestLabels []string `json:"pr_labels,omitempty" xorm:"json 'pr_labels'"`
}
} // @name Pipeline
// TableName return database table name for xorm
func (Pipeline) TableName() string {
@ -66,4 +65,4 @@ type UpdatePipelineStore interface {
type PipelineOptions struct {
Branch string `json:"branch"`
Variables map[string]string `json:"variables"`
}
} // @name PipelineOptions

View file

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

View file

@ -51,7 +51,6 @@ type RegistryStore interface {
}
// Registry represents a docker registry with credentials.
// swagger:model registry
type Registry struct {
ID int64 `json:"id" xorm:"pk autoincr 'registry_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'"`
Token string `json:"token" xorm:"TEXT 'registry_token'"`
Email string `json:"email" xorm:"varchar(500) 'registry_email'"`
}
} // @name Registry
// Validate validates the registry information.
func (r *Registry) Validate() error {

View file

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

View file

@ -68,7 +68,6 @@ type SecretStore interface {
}
// Secret represents a secret variable, such as a password or token.
// swagger:model registry
type Secret struct {
ID int64 `json:"id" xorm:"pk autoincr 'secret_id'"`
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'"`
SkipVerify bool `json:"-" xorm:"secret_skip_verify"`
Conceal bool `json:"-" xorm:"secret_conceal"`
}
} // @name Secret
// TableName return database table name for xorm
func (Secret) TableName() string {

View file

@ -29,7 +29,6 @@ type StepStore interface {
}
// Step represents a process in the pipeline.
// swagger:model step
type Step struct {
ID int64 `json:"id" xorm:"pk autoincr 'step_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"`
Environ map[string]string `json:"environ,omitempty" xorm:"json 'step_environ'"`
Children []*Step `json:"children,omitempty" xorm:"-"`
}
} // @name Step
type UpdateStepStore interface {
StepUpdate(*Step) error

View file

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

View file

@ -15,8 +15,6 @@
package model
// Team represents a team or organization in the forge.
//
// swagger:model user
type Team struct {
// Login is the username for this team.
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")
// User represents a registered user.
//
// swagger:model user
type User struct {
// the id for this user.
//
@ -66,7 +64,7 @@ type User struct {
// Hash is a unique token used to sign tokens.
Hash string `json:"-" xorm:"UNIQUE varchar(500) 'user_hash'"`
}
} // @name User
// TableName return database table name for xorm
func (User) TableName() string {

View file

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

View file

@ -16,9 +16,14 @@ package router
import (
"net/http"
"net/url"
"github.com/gin-gonic/gin"
"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/metrics"
@ -64,6 +69,18 @@ func Load(noRouteHandler http.HandlerFunc, middleware ...gin.HandlerFunc) http.H
e.GET("/healthz", api.Health)
apiRoutes(e)
setupSwaggerConfigAndRoutes(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>
<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>
</div>