-
Notifications
You must be signed in to change notification settings - Fork 196
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add github action to sync api docs to the user docs site #276
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
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 | ||
- uses: actions/setup-go@v5 | ||
with: | ||
cache-dependency-path: | | ||
tools/api-docs-generator/go.sum | ||
- name: generate | ||
id: generate | ||
working-directory: ./tools/api-docs-generator | ||
run: | | ||
make run | tee /tmp/run.log | ||
result_code=${PIPESTATUS[0]} | ||
echo 'MENU<<EOF' >> $GITHUB_OUTPUT | ||
cat /tmp/run.log >> $GITHUB_OUTPUT | ||
echo 'EOF' >> $GITHUB_OUTPUT | ||
exit $result_code | ||
- 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.MENU }} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we need to have a bit more explanation about what to do with this menu in the pull request. At the moment it is tribal knowledge that can easily be misunderstood. |
||
``` | ||
branch: docs/automatic-api-docs-update | ||
base: main |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
name: Test API Docs Generator | ||
|
||
on: | ||
workflow_dispatch: | ||
push: | ||
paths: | ||
- 'tools/api-docs-generator/**' | ||
- '.github/workflows/test-generator.yml' | ||
|
||
jobs: | ||
test: | ||
name: test-api-docs-generator | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- 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 |
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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
test: tidy lint | ||
go test ./... | ||
|
||
run: | ||
@go run . config.yml ../.. | ||
|
||
lint: tidy | ||
go run github.com/golangci/golangci-lint/cmd/golangci-lint run | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please pin the version, there are occasionally breaking changes There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. version is pinned in the go.mod file |
||
|
||
format: tidy | ||
go run golang.org/x/tools/cmd/goimports -w -local=github.com/snyk/user-docs/tools/api-docs-generator . | ||
|
||
tidy: | ||
go mod tidy | ||
Comment on lines
+1
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: all of these should be marked |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# API Docs Generator | ||
|
||
This utility generates API documentation from the openapi specification files. See `config.yml` for the configuration options. | ||
|
||
By default the utility will: | ||
1. Fetch the latest rest specification from `api.snyk.io` and update the copy in the docs repo | ||
2. Use the v1 specification in the docs repo as a source of truth for the API documentation | ||
3. Generate the API documentation in the `docs/snyk-api/reference` directory based on the v1 and REST specs | ||
|
||
## Usage | ||
|
||
To generate the API documentation locally, run: | ||
|
||
```bash | ||
make run | ||
``` | ||
|
||
## Development | ||
|
||
To test the utility, run: | ||
```bash | ||
make test | ||
``` |
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 |
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 | ||
} |
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() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't you write to
$GITHUB_OUTPUT
directly? I don't see why/tmp/run.log
is necessaryThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looses the exit status of the run; it will return the exit status of echo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or
if you want to preserve stdout
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way multi line strings work in GHA needs the closing delimiter: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#multiline-strings