Skip to content

Commit

Permalink
Add github action to sync api docs to the user docs site
Browse files Browse the repository at this point in the history
  • Loading branch information
tinygrasshopper committed May 22, 2024
1 parent 7789602 commit b19185b
Show file tree
Hide file tree
Showing 17 changed files with 1,886 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@
# https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners

* @snyk/docs
tools/api-docs-generator/* @snyk/api
.github/workflows/* @snyk/api
38 changes: 38 additions & 0 deletions .github/workflows/sync-api-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Synchronize API Docs

on:
workflow_dispatch:
schedule:
- cron: '0 * * * 1-5' # Mon-Fri every hour
push:

branches: [chore/docs-action]

jobs:
build:
name: synchronize-api-docs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
#TODO: Remove before merge
ref: chore/docs-action
- uses: actions/setup-go@v5
with:
cache-dependency-path: |
tools/api-docs-generator/go.sum
- name: generate
working-directory: ./tools/api-docs-generator
run: make run > "$GITHUB_OUTPUT"
- uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "docs: synchronizing api spec with user-docs"
title: "Generate API docs from spec"
body: |
This PR was automatically generated by the API docs synchronization action. Please review the changes and merge if they look good.
```
${{ steps.generate.outputs.output }}
```
branch: docs/automatic-api-docs-update
base: main
25 changes: 25 additions & 0 deletions .github/workflows/test-generator.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Test API Docs Generator

on:
workflow_dispatch:
push:
paths:
- 'tools/api-docs-generator/**'
- '.github/workflows/test-generator.yml'

jobs:
test:
name: synchronize-api-docs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
#TODO: Remove before merge
ref: chore/docs-action
- uses: actions/setup-go@v5
with:
cache-dependency-path: |
tools/api-docs-generator/go.sum
- name: test
working-directory: ./tools/api-docs-generator
run: make test
123 changes: 123 additions & 0 deletions tools/api-docs-generator/.golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
---
run:
build-tags:
- integration
concurrency: 4
issues-exit-code: 1
skip-dirs:
- internal/rest/api/versions
- internal/rest/api_hidden/versions
tests: true
timeout: 5m

linters-settings:
errcheck:
check-blank: true
check-type-assertions: true
exhaustive:
default-signifies-exhaustive: true
gocritic:
enabled-tags:
- diagnostic
- experimental
- opinionated
- performance
- style
settings:
hugeParam:
# Docs say this is the default, but for some reason without this set
# the rule doesn't trigger locally.
sizeThreshold: 80
gocyclo:
min-complexity: 10
gofmt:
simplify: true
goimports:
local-prefixes: github.com/snyk/user-docs/tools/api-docs-generator
gosec:
config:
G306: "0644"
gomnd:
checks:
- argument
- assign
- case
- condition
- operation
- return
govet:
check-shadowing: true
lll:
line-length: 160
misspell:
locale: US
nolintlint:
allow-leading-space: true
allow-unused: false
require-explanation: true
require-specific: true
prealloc:
simple: true
range-loops: true
for-loops: true
staticcheck:
checks:
- all
- -SA1019
go: "1.18"
stylecheck:
checks:
- all
go: "1.18"
varcheck:
exported-fields: true

linters:
enable:
- asciicheck
- bidichk
- bodyclose
- contextcheck
- dogsled
- dupl
- durationcheck
- errname
- errorlint
- exhaustive
- exportloopref
- forcetypeassert
- goconst
- gocritic
- gocyclo
- godot
- goimports
- gosec
- lll
- misspell
- nakedret
- nestif
- nilerr
- nilnil
- noctx
- nolintlint
- prealloc
- promlinter
- sqlclosecheck
- stylecheck
- tenv
- thelper
- tparallel
- unconvert
- unparam
- wastedassign
- whitespace

issues:
exclude-rules:
- path: _test\.go
linters:
- bodyclose
- goconst
- path: test/
linters:
- testpackage
11 changes: 11 additions & 0 deletions tools/api-docs-generator/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
test: lint
go test ./...

run:
go run . config.yml ../..

lint:
go run github.com/golangci/golangci-lint/cmd/golangci-lint run

format:
go run golang.org/x/tools/cmd/goimports -w -local=github.com/snyk/user-docs/tools/api-docs-generator .
3 changes: 3 additions & 0 deletions tools/api-docs-generator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# API Docs Generator

This tool generates API documentation from the openapi specification files.
12 changes: 12 additions & 0 deletions tools/api-docs-generator/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
fetcher:
source: https://api.snyk.io/rest/openapi
destination: docs/.gitbook/assets/rest-spec.json
specs:
- path: docs/.gitbook/assets/spec.yaml
suffix: " (v1)"
docsHint: This document uses the v1 API. For more details, see the [v1 API](../v1-api).
- path: docs/.gitbook/assets/rest-spec.json
docsHint: This document uses the REST API. For more details, see the [Authentication for API](../authentication-for-api/) page.

output:
apiReferencePath: docs/snyk-api/reference
38 changes: 38 additions & 0 deletions tools/api-docs-generator/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package config

import (
"os"

"gopkg.in/yaml.v3"
)

type Fetcher struct {
Source string `yaml:"source"`
Destination string `yaml:"destination"`
}

type Spec struct {
Path string `yaml:"path"`
Suffix string `yaml:"suffix,omitempty"`
DocsHint string `yaml:"docsHint,omitempty"`
}

type Output struct {
APIReferencePath string `yaml:"apiReferencePath"`
}

type Config struct {
Fetcher Fetcher `yaml:"fetcher"`
Specs []Spec `yaml:"specs"`
Output Output `yaml:"output"`
}

func Parse(filename string) (Config, error) {
cfg := Config{}
file, err := os.Open(filename)
if err != nil {
return cfg, err
}
err = yaml.NewDecoder(file).Decode(&cfg)
return cfg, err
}
74 changes: 74 additions & 0 deletions tools/api-docs-generator/config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package config

import (
"os"
"reflect"
"testing"
)

func TestParse(t *testing.T) {
tests := []struct {
name string
args func() string
want Config
wantErr bool
}{
{
name: "parses the config file",
args: func() string {
return createTempFile(t, `fetcher:
source: source
destination: destination
specs:
- path: .gitbook/assets/spec.yaml
suffix: " (v1)"
docsHint: hint 1
- path: .gitbook/assets/rest-spec.json
docsHint: hint 2
output:
apiReferencePath: snyk-api/reference`)
},
want: Config{
Fetcher: Fetcher{"source", "destination"},
Specs: []Spec{
{".gitbook/assets/spec.yaml", " (v1)", "hint 1"},
{".gitbook/assets/rest-spec.json", "", "hint 2"},
},
Output: Output{"snyk-api/reference"},
},
},
{
name: "invalid config",
args: func() string {
return createTempFile(t, `test 12`)
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := Parse(tt.args())
if (err != nil) != tt.wantErr {
t.Errorf("Parse() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Parse() got = %v, want %v", got, tt.want)
}
})
}
}

func createTempFile(t *testing.T, content string) string {
t.Helper()
file, err := os.CreateTemp("", "config")
if err != nil {
t.Fatal(err)
}
_, err = file.WriteString(content)
if err != nil {
t.Fatal(err)
}
return file.Name()
}
Loading

0 comments on commit b19185b

Please sign in to comment.