mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-01-12 03:21:33 +00:00
docs: improve swagger
- use markdown files in swagger - automate version, use swager.conf template - embed swagger ui index.html as docs.html
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -70,4 +70,7 @@ usr/bin/aptly
|
||||
dpkgs/
|
||||
debian/changelog.dpkg-bak
|
||||
|
||||
docs/
|
||||
docs/docs.go
|
||||
docs/swagger.json
|
||||
docs/swagger.yaml
|
||||
docs/swagger.conf
|
||||
|
||||
10
Makefile
10
Makefile
@@ -45,6 +45,9 @@ version: ## Print aptly version
|
||||
swagger-install:
|
||||
# Install swag
|
||||
@test -f $(BINPATH)/swag || GOOS=linux GOARCH=amd64 go install github.com/swaggo/swag/cmd/swag@latest
|
||||
# Generate swagger.conf
|
||||
cp docs/swagger.conf.tpl docs/swagger.conf
|
||||
echo "// @version $(VERSION)" >> docs/swagger.conf
|
||||
|
||||
azurite-start:
|
||||
azurite & \
|
||||
@@ -55,7 +58,7 @@ azurite-stop:
|
||||
|
||||
swagger: swagger-install
|
||||
# Generate swagger docs
|
||||
@PATH=$(BINPATH)/:$(PATH) swag init --markdownFiles docs
|
||||
@PATH=$(BINPATH)/:$(PATH) swag init --markdownFiles docs --generalInfo docs/swagger.conf
|
||||
|
||||
etcd-install:
|
||||
# Install etcd
|
||||
@@ -107,7 +110,7 @@ serve: prepare swagger-install ## Run development server (auto recompiling)
|
||||
test -f $(BINPATH)/air || go install github.com/air-verse/air@v1.52.3
|
||||
cp debian/aptly.conf ~/.aptly.conf
|
||||
sed -i /enableSwaggerEndpoint/s/false/true/ ~/.aptly.conf
|
||||
PATH=$(BINPATH):$$PATH air -build.pre_cmd 'swag init -q --markdownFiles docs' -build.exclude_dir docs,system,debian,pgp/keyrings,pgp/test-bins,completion.d,man,deb/testdata,console,_man,systemd,obj-x86_64-linux-gnu -- api serve -listen 0.0.0.0:3142
|
||||
PATH=$(BINPATH):$$PATH air -build.pre_cmd 'swag init -q --markdownFiles docs --generalInfo docs/swagger.conf' -build.exclude_dir docs,system,debian,pgp/keyrings,pgp/test-bins,completion.d,man,deb/testdata,console,_man,systemd,obj-x86_64-linux-gnu -- api serve -listen 0.0.0.0:3142
|
||||
|
||||
dpkg: prepare swagger ## Build debian packages
|
||||
@test -n "$(DEBARCH)" || (echo "please define DEBARCH"; exit 1)
|
||||
@@ -205,7 +208,8 @@ man: ## Create man pages
|
||||
|
||||
clean: ## remove local build and module cache
|
||||
# Clean all generated and build files
|
||||
test -d .go/ && chmod u+w -R .go/ && rm -rf .go/ || true
|
||||
find .go/ -type d ! -perm -u=w -exec chmod u+w {} \;
|
||||
rm -rf .go/
|
||||
rm -rf build/ obj-*-linux-gnu* tmp/
|
||||
rm -f unit.out aptly.test VERSION docs/docs.go docs/swagger.json docs/swagger.yaml docs/swagger.conf
|
||||
find system/ -type d -name __pycache__ -exec rm -rf {} \; 2>/dev/null || true
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
_ "github.com/aptly-dev/aptly/docs" // import docs
|
||||
"github.com/aptly-dev/aptly/docs"
|
||||
swaggerFiles "github.com/swaggo/files"
|
||||
ginSwagger "github.com/swaggo/gin-swagger"
|
||||
)
|
||||
@@ -27,26 +27,22 @@ func apiMetricsGet() gin.HandlerFunc {
|
||||
}
|
||||
|
||||
func redirectSwagger(c *gin.Context) {
|
||||
if c.Request.URL.Path == "/docs/index.html" {
|
||||
c.Redirect(http.StatusMovedPermanently, "/docs.html")
|
||||
return
|
||||
}
|
||||
if c.Request.URL.Path == "/docs/" {
|
||||
c.Redirect(http.StatusMovedPermanently, "/docs/index.html")
|
||||
c.Redirect(http.StatusMovedPermanently, "/docs.html")
|
||||
return
|
||||
}
|
||||
if c.Request.URL.Path == "/docs" {
|
||||
c.Redirect(http.StatusMovedPermanently, "/docs.html")
|
||||
return
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
|
||||
// Router returns prebuilt with routes http.Handler
|
||||
// @title Aptly API
|
||||
// @version 1.0
|
||||
// @description Aptly REST API Documentation
|
||||
|
||||
// @contact.name Aptly
|
||||
// @contact.url http://github.com/aptly-dev/aptly
|
||||
// @contact.email support@aptly.info
|
||||
|
||||
// @license.name MIT License
|
||||
// @license.url http://www.
|
||||
|
||||
// @BasePath /api
|
||||
func Router(c *ctx.AptlyContext) http.Handler {
|
||||
if aptly.EnableDebug {
|
||||
gin.SetMode(gin.DebugMode)
|
||||
@@ -73,6 +69,9 @@ func Router(c *ctx.AptlyContext) http.Handler {
|
||||
router.Use(gin.Recovery(), gin.ErrorLogger())
|
||||
|
||||
if c.Config().EnableSwaggerEndpoint {
|
||||
router.GET("docs.html", func(c *gin.Context) {
|
||||
c.Data(http.StatusOK, "text/html; charset=utf-8", docs.DocsHTML)
|
||||
})
|
||||
router.Use(redirectSwagger)
|
||||
url := ginSwagger.URL("/docs/doc.json")
|
||||
router.GET("/docs/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, url))
|
||||
|
||||
1
docs/Database.md
Normal file
1
docs/Database.md
Normal file
@@ -0,0 +1 @@
|
||||
# Aptly Database Operations
|
||||
29
docs/Publish.md
Normal file
29
docs/Publish.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Aptly Publish Points
|
||||
<div>
|
||||
|
||||
Publish snapshot or local repo as Debian repository which could be
|
||||
served by HTTP/FTP/rsync server. Repository is signed by user's key with
|
||||
GnuPG. Key should be created beforehand (see section GPG Keys below).
|
||||
Published repository could be consumed directly by apt.
|
||||
|
||||
Repositories could be published to Amazon S3 service: create bucket,
|
||||
[configure publishing endpoint](/doc/feature/s3/) and use S3 endpoint when
|
||||
publishing.
|
||||
|
||||
|
||||
#### GPG Keys
|
||||
|
||||
GPG key is required to sign any published repository. Key should be
|
||||
generated before publishing first repository.
|
||||
|
||||
Key generation, storage, backup and revocation is out of scope of this
|
||||
document, there are many tutorials available, e.g. [this one](http://fedoraproject.org/wiki/Creating_GPG_Keys).
|
||||
|
||||
Publiс part of the key should be exported from your keyring using `gpg --export --armor` and
|
||||
imported into apt keyring using `apt-key` tool on all machines that would be using published
|
||||
repositories.
|
||||
|
||||
Signing releases is highly recommended, but if you want to skip it, you
|
||||
can either use `gpgDisableSign` configuration option or `--skip-signing`
|
||||
flag.
|
||||
</div>
|
||||
10
docs/Status.md
Normal file
10
docs/Status.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# Aptly Status Information
|
||||
<div>
|
||||
|
||||
## Something
|
||||
|
||||
Very interesting ... asd wer
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
112
docs/api.md
Normal file
112
docs/api.md
Normal file
@@ -0,0 +1,112 @@
|
||||
|
||||
Using aptly via REST API allows to achieve two goals:
|
||||
|
||||
1. Remote access to aptly service: e.g. uploading packages and publishing them from CI server.
|
||||
2. Concurrent access to aptly by multiple users.
|
||||
|
||||
#### Quickstart
|
||||
|
||||
Run `aptly api serve` to start HTTP service:
|
||||
|
||||
$ aptly api serve
|
||||
Starting web server at: :8080 (press Ctrl+C to quit)...
|
||||
[GIN-debug] GET /api/version --> github.com/aptly-dev/aptly/api.apiVersion (4 handlers)
|
||||
...
|
||||
|
||||
By default aptly would listen on `:8080`, but it could be changed with `-listen` flag.
|
||||
|
||||
Usage:
|
||||
|
||||
$ aptly api serve -listen=:8080
|
||||
|
||||
Flags:
|
||||
|
||||
- `-listen=":8080"`: host:port for HTTP listening
|
||||
- `-no-lock`: don't lock the database
|
||||
|
||||
When `-no-lock` option is enabled, API server acquires and drops the lock
|
||||
around all the operations, so that API and CLI could be used concurrently.
|
||||
|
||||
Try some APIs:
|
||||
|
||||
$ curl http://localhost:8080/api/version
|
||||
{"Version":"0.9~dev"}
|
||||
|
||||
$ curl -F file=@aptly_0.8_i386.deb http://localhost:8080/api/files/aptly_0.8
|
||||
["aptly_0.8/aptly_0.8_i386.deb"]
|
||||
|
||||
$ curl -X POST -H 'Content-Type: application/json' --data '{"Name": "aptly-repo"}' http://localhost:8080/api/repos
|
||||
{"Name":"aptly-repo","Comment":"","DefaultDistribution":"","DefaultComponent":""}
|
||||
|
||||
$ curl -X POST http://localhost:8080/api/repos/aptly-repo/file/aptly_0.8
|
||||
{"failedFiles":[],"report":{"warnings":[],"added":["aptly_0.8_i386 added"],"removed":[]}}
|
||||
|
||||
$ curl http://localhost:8080/api/repos/aptly-repo/packages
|
||||
["Pi386 aptly 0.8 966561016b44ed80"]
|
||||
|
||||
$ curl -X POST -H 'Content-Type: application/json' --data '{"Distribution": "wheezy", "Sources": [{"Name": "aptly-repo"}]}' http://localhost:8080/api/publish//repos
|
||||
{"Architectures":["i386"],"Distribution":"wheezy","Label":"","Origin":"","Prefix":".","SourceKind":"local","Sources":[{"Component":"main","Name":"aptly-repo"}],"Storage":""}
|
||||
|
||||
#### Security
|
||||
|
||||
For security reasons it is advised to let Aptly listen on a Unix domain socket rather than a port. Sockets are subject to file permissions and thus allow for user-level access control while binding to a port only gives host-level access control. To use a socket simply run Aptly with a suitable listen flag such as `aptly api serve -listen=unix:///var/run/aptly.sock`.
|
||||
|
||||
Aptly's HTTP API shouldn't be directly exposed to the Internet: there's no authentication/protection of APIs. To publish the API it could be proxied through a HTTP proxy or server (e.g. nginx) to add an authentication mechanism or disallow all non-GET requests. [Reference example](https://github.com/sepich/nginx-ldap) for LDAP based per-repo access with nginx.
|
||||
|
||||
#### Notes
|
||||
|
||||
1. Some things (for example, S3 publishing endpoints) could be set up only using configuration file, so it requires restart of aptly HTTP server in order for changes to take effect.
|
||||
1. GPG key passphrase can't be input on console, so either passwordless GPG keys are required or passphrase should be specified in API parameters.
|
||||
1. Some script might be required to start/stop aptly HTTP service.
|
||||
1. Some parameters are given as part of URLs, which requires proper url encoding. Unfortunately, at the moment it's not possible to pass URL arguments with `/` in them.
|
||||
|
||||
### How to implement equivalent of aptly commands using API
|
||||
|
||||
* `aptly mirror`: [mirror API](/doc/api/mirror)
|
||||
* `list`: list
|
||||
* `create`: create
|
||||
* `drop`: delete
|
||||
* `show`: show
|
||||
* `search`: show packages/search
|
||||
* `update`: update mirror
|
||||
* `aptly repo`: [local repos API](/doc/api/repos)
|
||||
* `add`: [file upload API](/doc/api/files) + add packages from uploaded file
|
||||
* `copy`: show packages/search + add packages by key
|
||||
* `create`: create
|
||||
* `drop`: delete
|
||||
* `edit`: edit
|
||||
* `import`: not available, as mirror API is not implemented yet
|
||||
* `list`: list
|
||||
* `move`: show packages/search + add packages by key + delete packages by key
|
||||
* `remove`: show packages/search + delete packages by key
|
||||
* `rename`: not available yet, should be part of edit API
|
||||
* `search`: show packages/search
|
||||
* `show`: show
|
||||
* `aptly snapshot`: [snapshots API](/doc/api/snapshots)
|
||||
* `create`:
|
||||
* empty: create snapshot with empty package references
|
||||
* from mirror: not available yet
|
||||
* from local repo: create snapshot from local repo
|
||||
* `diff`: snapshot difference API
|
||||
* `drop`: delete
|
||||
* `filter`: show packages/search + create snapshot from package references
|
||||
* `list`: list
|
||||
* `merge`: show packages/search + processing + create snapshot from package references
|
||||
* `pull`: show packages/search + processing + create snapshot from package references (might be implemented as API in future versions)
|
||||
* `rename`: edit
|
||||
* `search`: show packages/search
|
||||
* `show`: show
|
||||
* `verify`: not available yet
|
||||
* `aptly publish`: [publish API](/doc/api/publish)
|
||||
* `drop`: delete
|
||||
* `list`: list
|
||||
* `repo`: publish repo
|
||||
* `snapshot`: publish snapshot
|
||||
* `switch`: switch/update
|
||||
* `update`: switch/update
|
||||
* `aptly package`: [packages API](/doc/api/packages)
|
||||
* `search`: not available yet
|
||||
* `show`: only one format, with package key as input
|
||||
* `aptly graph`: [graph API](/doc/api/misc)
|
||||
* `aptly version`: [version API](/doc/api/misc)
|
||||
* `aptly db`: not available yet
|
||||
142
docs/docs.html
Normal file
142
docs/docs.html
Normal file
@@ -0,0 +1,142 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Swagger UI</title>
|
||||
<link rel="stylesheet" type="text/css" href="/docs/swagger-ui.css" >
|
||||
<link rel="icon" type="image/png" href="/docs/favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="/docs/favicon-16x16.png" sizes="16x16" />
|
||||
<style>
|
||||
html
|
||||
{
|
||||
box-sizing: border-box;
|
||||
overflow: -moz-scrollbars-vertical;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
*,
|
||||
*:before,
|
||||
*:after
|
||||
{
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
body {
|
||||
margin:0;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
/* no json link */
|
||||
.swagger-ui a.link {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* API Summary */
|
||||
.swagger-ui .opblock-summary-description {
|
||||
flex: 0 0 auto !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: 2em;
|
||||
font-weight: bold;
|
||||
font-size: 14pt !important;
|
||||
}
|
||||
|
||||
/* Tag Group */
|
||||
.swagger-ui .opblock-tag-section > .opblock-tag > a {
|
||||
color: grey !important;
|
||||
align-self: flex-start;
|
||||
font-size: 14pt;
|
||||
width: 7em;
|
||||
}
|
||||
|
||||
/* */
|
||||
.swagger-ui .opblock-tag-section .opblock-tag .markdown > h1 {
|
||||
font-size: 16pt;
|
||||
}
|
||||
|
||||
/* Show Tag Group description only if opened */
|
||||
.swagger-ui .opblock-tag-section:not(.is-open) .opblock-tag .markdown > div {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Keep open button on top */
|
||||
.swagger-ui .expand-operation {
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position:absolute;width:0;height:0">
|
||||
<defs>
|
||||
<symbol viewBox="0 0 20 20" id="unlocked">
|
||||
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V6h2v-.801C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8z"></path>
|
||||
</symbol>
|
||||
|
||||
<symbol viewBox="0 0 20 20" id="locked">
|
||||
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8zM12 8H8V5.199C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8z"/>
|
||||
</symbol>
|
||||
|
||||
<symbol viewBox="0 0 20 20" id="close">
|
||||
<path d="M14.348 14.849c-.469.469-1.229.469-1.697 0L10 11.819l-2.651 3.029c-.469.469-1.229.469-1.697 0-.469-.469-.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-.469-.469-.469-1.228 0-1.697.469-.469 1.228-.469 1.697 0L10 8.183l2.651-3.031c.469-.469 1.228-.469 1.697 0 .469.469.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c.469.469.469 1.229 0 1.698z"/>
|
||||
</symbol>
|
||||
|
||||
<symbol viewBox="0 0 20 20" id="large-arrow">
|
||||
<path d="M13.25 10L6.109 2.58c-.268-.27-.268-.707 0-.979.268-.27.701-.27.969 0l7.83 7.908c.268.271.268.709 0 .979l-7.83 7.908c-.268.271-.701.27-.969 0-.268-.269-.268-.707 0-.979L13.25 10z"/>
|
||||
</symbol>
|
||||
|
||||
<symbol viewBox="0 0 20 20" id="large-arrow-down">
|
||||
<path d="M17.418 6.109c.272-.268.709-.268.979 0s.271.701 0 .969l-7.908 7.83c-.27.268-.707.268-.979 0l-7.908-7.83c-.27-.268-.27-.701 0-.969.271-.268.709-.268.979 0L10 13.25l7.418-7.141z"/>
|
||||
</symbol>
|
||||
|
||||
|
||||
<symbol viewBox="0 0 24 24" id="jump-to">
|
||||
<path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z"/>
|
||||
</symbol>
|
||||
|
||||
<symbol viewBox="0 0 24 24" id="expand">
|
||||
<path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>
|
||||
</symbol>
|
||||
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
<div id="swagger-ui"></div>
|
||||
|
||||
<script src="/docs/swagger-ui-bundle.js"> </script>
|
||||
<script src="/docs/swagger-ui-standalone-preset.js"> </script>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
|
||||
const ui = SwaggerUIBundle({
|
||||
url: "\/docs\/doc.json",
|
||||
dom_id: '#swagger-ui',
|
||||
validatorUrl: null,
|
||||
oauth2RedirectUrl: `${window.location.protocol}//${window.location.host}${window.location.pathname.split('/').slice(0, window.location.pathname.split('/').length - 1).join('/')}/oauth2-redirect.html`,
|
||||
persistAuthorization: false ,
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIStandalonePreset.slice(1) // remote topbar
|
||||
],
|
||||
plugins: [
|
||||
SwaggerUIBundle.plugins.DownloadUrl
|
||||
],
|
||||
layout: "StandaloneLayout",
|
||||
docExpansion: "list",
|
||||
deepLinking: true ,
|
||||
defaultModelsExpandDepth: 5
|
||||
})
|
||||
|
||||
const defaultClientId = "";
|
||||
if (defaultClientId) {
|
||||
ui.initOAuth({
|
||||
clientId: defaultClientId
|
||||
})
|
||||
}
|
||||
|
||||
window.ui = ui
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,3 +1,9 @@
|
||||
package docs
|
||||
|
||||
import _ "github.com/swaggo/swag" // make sure swag is in go.mod
|
||||
import (
|
||||
_ "embed"
|
||||
_ "github.com/swaggo/swag" // make sure swag is in go.mod
|
||||
)
|
||||
|
||||
//go:embed docs.html
|
||||
var DocsHTML []byte
|
||||
|
||||
16
docs/swagger.conf.tpl
Normal file
16
docs/swagger.conf.tpl
Normal file
@@ -0,0 +1,16 @@
|
||||
package docs
|
||||
|
||||
// @title Aptly API
|
||||
// @description.markdown
|
||||
|
||||
// @contact.name Aptly
|
||||
// @contact.url http://github.com/aptly-dev/aptly
|
||||
|
||||
// @Tag.name Publish
|
||||
// @Tag.description.markdown
|
||||
// @Tag.name Database
|
||||
// @Tag.description.markdown
|
||||
// @Tag.name Status
|
||||
// @Tag.description.markdown
|
||||
|
||||
// version will be appended here:
|
||||
Reference in New Issue
Block a user