Skip to content

Commit 62c3754

Browse files
committed
ci: automate generation and publishing of docs
1 parent d4ff660 commit 62c3754

File tree

18 files changed

+2827
-145
lines changed

18 files changed

+2827
-145
lines changed

.github/workflows/build-test.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ jobs:
429429
# Benchmarks on Main are ran through a different workflow
430430
if: |
431431
needs.paths-filter.outputs.codechange == 'true' &&
432-
github.ref_name != 'main'
432+
!(github.event_name == 'push' && github.ref_name == 'main')
433433
steps:
434434
- uses: "actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493" # v4.2.2
435435
with:

.github/workflows/docs.yaml

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
---
2+
name: "Update Docs Repo"
3+
on: # yamllint disable-line rule:truthy
4+
push:
5+
branches:
6+
- "main"
7+
env:
8+
DOCS_REPO: "authzed/docs"
9+
TARGET_DOCS_FILE: "pages/spicedb/concepts/commands.mdx"
10+
11+
permissions:
12+
contents: "write"
13+
pull-requests: "write"
14+
actions: "write"
15+
repository-projects: "write"
16+
17+
jobs:
18+
sync-docs:
19+
name: "Generate & Sync Documentation"
20+
runs-on: "ubuntu-latest"
21+
steps:
22+
- name: "Checkout source"
23+
uses: "actions/checkout@v5"
24+
- name: "Checkout target"
25+
uses: "actions/checkout@v5"
26+
with:
27+
token: "${{ secrets.GITHUB_TOKEN }}"
28+
repository: "${{ env.DOCS_REPO }}"
29+
path: "docs-repo"
30+
ref: "main"
31+
32+
- name: "Send changes from source to target"
33+
run: |
34+
cp -v docs/spicedb.md docs-repo/$TARGET_DOCS_FILE
35+
- name: "Check if target changed"
36+
id: "check-changes"
37+
run: |
38+
if [[ -n "$(git status --porcelain ./docs-repo)" ]]; then
39+
git status
40+
echo "docs_changed=true" >> $GITHUB_OUTPUT
41+
else
42+
echo "no changes were made"
43+
echo "docs_changed=false" >> $GITHUB_OUTPUT
44+
fi
45+
- name: "Create commit & pull request in target"
46+
if: "steps.check-changes.outputs.docs_changed == 'true'"
47+
id: "cpr"
48+
uses: "peter-evans/create-pull-request@v7"
49+
with:
50+
token: "${{ secrets.PAT_TO_PUSH_TO_DOCS }}"
51+
path: "docs-repo"
52+
title: "Auto-generated PR: Update spicedb docs"
53+
body: "This PR was auto-generated by GitHub Actions."
54+
branch: "auto-update-branch"
55+
56+
- name: "Approve Pull Request in target"
57+
uses: "juliangruber/approve-pull-request-action@b71c44ff142895ba07fad34389f1938a4e8ee7b0" # v2.0.6
58+
if: "steps.check-changes.outputs.docs_changed == 'true'"
59+
with:
60+
repo: "authzed/docs"
61+
github-token: "${{ secrets.AUTHZEDAPPROVER_REPO_SCOPED_TOKEN }}"
62+
number: "${{ steps.cpr.outputs.pull-request-number }}"
63+
64+
- name: "Enable Pull Request Automerge in target"
65+
if: "steps.check-changes.outputs.docs_changed == 'true'"
66+
run: "gh pr merge ${{ steps.cpr.outputs.pull-request-number }} --merge --auto -R ${{ env.DOCS_REPO }}"
67+
env:
68+
GH_TOKEN: "${{ secrets.AUTHZEDAPPROVER_REPO_SCOPED_TOKEN }}"
69+
70+
- name: "Notify in Slack if failure"
71+
if: "${{ failure() }}"
72+
uses: "slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a" # v2.1.1
73+
with:
74+
webhook: "${{ secrets.SLACK_BUILDS_WEBHOOK_URL }}"
75+
webhook-type: "incoming-webhook"
76+
payload: |
77+
text: "@eng-oss Could not sync docs from "spicedb" repo to "docs" repo"
78+
blocks:
79+
- type: "section"
80+
text:
81+
type: "mrkdwn"
82+
text: |
83+
:x: SpiceDB documentation sync failed.
84+
*Repository:* <${{ github.server_url }}/${{ github.repository }}|${{ github.repository }}>
85+
*Job Run:* <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>

.github/workflows/lint.yaml

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,32 +23,30 @@ jobs:
2323
uses: "authzed/actions/go-license-check@11667c9b2e8b3649ad2af4d788e57d18f8e8eaf1" # main
2424
with:
2525
ignore: "buf.build" # Has no license information
26-
27-
go-lint:
28-
name: "Lint Go"
26+
ensure-docs-uptodate:
27+
name: "Ensure Docs are up to date"
2928
runs-on: "depot-ubuntu-24.04-4"
3029
steps:
3130
- uses: "actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493" # v4.2.2
3231
- uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main
33-
- name: "Lint Go"
34-
run: "go run mage.go lint:go"
32+
- name: "Generate docs"
33+
run: "go run mage.go gen:docs"
3534
- uses: "chainguard-dev/actions/nodiff@1b32103f5aa389c31ab0be75a8edc38d7e4750d8" # main
3635
with:
3736
path: ""
38-
fixup-command: "go run mage.go lint:go"
39-
40-
extra-lint:
41-
name: "Lint YAML & Markdown"
42-
runs-on: "depot-ubuntu-24.04-small"
37+
fixup-command: "mage gen:docs"
38+
lint-everything:
39+
name: "Lint Everything"
40+
runs-on: "depot-ubuntu-24.04-4"
4341
steps:
4442
- uses: "actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493" # v4.2.2
4543
- uses: "authzed/actions/setup-go@6cde6aeb82fab36d8383c2f55bed8128955af34d" # main
46-
- name: "Lint Everything Else"
47-
run: "go run mage.go lint:extra"
44+
- name: "Lint Everything"
45+
run: "go run mage.go lint:all"
4846
- uses: "chainguard-dev/actions/nodiff@1b32103f5aa389c31ab0be75a8edc38d7e4750d8" # main
4947
with:
5048
path: ""
51-
fixup-command: "go run mage.go lint:extra"
49+
fixup-command: "go run mage.go lint:all"
5250

5351
conventional-commits:
5452
name: "Lint Commit Messages"

.markdownlint.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,8 @@ line-length: false
33
no-hard-tabs: false
44
no-inline-html: false
55
no-bare-urls: false
6+
first-line-heading: false
7+
no-multiple-blanks: false
8+
fenced-code-language: false
9+
no-duplicate-heading: false
10+
blanks-around-fences: false

cmd/spicedb/main.go

Lines changed: 2 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -2,114 +2,20 @@ package main
22

33
import (
44
"errors"
5-
"fmt"
65
"os"
76

8-
mcobra "github.com/muesli/mango-cobra"
9-
"github.com/muesli/roff"
107
"github.com/rs/zerolog"
118
"github.com/sercand/kuberesolver/v5"
12-
"github.com/spf13/cobra"
139
"google.golang.org/grpc/balancer"
1410
_ "google.golang.org/grpc/xds"
1511

1612
log "github.com/authzed/spicedb/internal/logging"
1713
"github.com/authzed/spicedb/pkg/cmd"
1814
cmdutil "github.com/authzed/spicedb/pkg/cmd/server"
19-
"github.com/authzed/spicedb/pkg/cmd/testserver"
2015
_ "github.com/authzed/spicedb/pkg/runtime"
2116
"github.com/authzed/spicedb/pkg/spiceerrors"
2217
)
2318

24-
var errParsing = errors.New("parsing error")
25-
26-
// buildRootCommand creates and configures the complete SpiceDB CLI command structure
27-
func buildRootCommand() (*cobra.Command, error) {
28-
// Create a root command
29-
rootCmd := cmd.NewRootCommand("spicedb")
30-
rootCmd.SetFlagErrorFunc(func(cmd *cobra.Command, err error) error {
31-
cmd.Println(err)
32-
cmd.Println(cmd.UsageString())
33-
return errParsing
34-
})
35-
if err := cmd.RegisterRootFlags(rootCmd); err != nil {
36-
return nil, fmt.Errorf("failed to register root flags: %w", err)
37-
}
38-
39-
// Add a version command
40-
versionCmd := cmd.NewVersionCommand(rootCmd.Use)
41-
cmd.RegisterVersionFlags(versionCmd)
42-
rootCmd.AddCommand(versionCmd)
43-
44-
// Add datastore commands
45-
datastoreCmd, err := cmd.NewDatastoreCommand(rootCmd.Use)
46-
if err != nil {
47-
return nil, fmt.Errorf("failed to register datastore command: %w", err)
48-
}
49-
50-
cmd.RegisterDatastoreRootFlags(datastoreCmd)
51-
rootCmd.AddCommand(datastoreCmd)
52-
53-
// Add deprecated head command
54-
headCmd := cmd.NewHeadCommand(rootCmd.Use)
55-
cmd.RegisterHeadFlags(headCmd)
56-
headCmd.Hidden = true
57-
headCmd.RunE = cmd.DeprecatedRunE(headCmd.RunE, "spicedb datastore head")
58-
rootCmd.AddCommand(headCmd)
59-
60-
// Add deprecated migrate command
61-
migrateCmd := cmd.NewMigrateCommand(rootCmd.Use)
62-
migrateCmd.Hidden = true
63-
migrateCmd.RunE = cmd.DeprecatedRunE(migrateCmd.RunE, "spicedb datastore migrate")
64-
cmd.RegisterMigrateFlags(migrateCmd)
65-
rootCmd.AddCommand(migrateCmd)
66-
67-
// Add server commands
68-
serverConfig := cmdutil.NewConfigWithOptionsAndDefaults()
69-
serveCmd := cmd.NewServeCommand(rootCmd.Use, serverConfig)
70-
if err := cmd.RegisterServeFlags(serveCmd, serverConfig); err != nil {
71-
return nil, fmt.Errorf("failed to register server flags: %w", err)
72-
}
73-
rootCmd.AddCommand(serveCmd)
74-
75-
lspConfig := new(cmd.LSPConfig)
76-
lspCmd := cmd.NewLSPCommand(rootCmd.Use, lspConfig)
77-
if err := cmd.RegisterLSPFlags(lspCmd, lspConfig); err != nil {
78-
return nil, fmt.Errorf("failed to register lsp flags: %w", err)
79-
}
80-
rootCmd.AddCommand(lspCmd)
81-
82-
var testServerConfig testserver.Config
83-
testingCmd := cmd.NewTestingCommand(rootCmd.Use, &testServerConfig)
84-
cmd.RegisterTestingFlags(testingCmd, &testServerConfig)
85-
rootCmd.AddCommand(testingCmd)
86-
87-
rootCmd.AddCommand(&cobra.Command{
88-
Use: "man",
89-
Short: "Generate man page",
90-
Long: `Generate a man page for SpiceDB.
91-
92-
The output can be redirected to a file and installed to the system:
93-
spicedb man > spicedb.1
94-
sudo mv spicedb.1 /usr/share/man/man1/
95-
sudo mandb # Update man page database`,
96-
SilenceUsage: true,
97-
DisableFlagsInUseLine: true,
98-
Args: cobra.NoArgs,
99-
RunE: func(cmd *cobra.Command, args []string) error {
100-
manPage, err := mcobra.NewManPage(1, cmd.Root())
101-
if err != nil {
102-
return err
103-
}
104-
105-
_, err = fmt.Fprint(os.Stdout, manPage.Build(roff.NewDocument()))
106-
return err
107-
},
108-
})
109-
110-
return rootCmd, nil
111-
}
112-
11319
func main() {
11420
// Set up root logger
11521
// This will typically be overwritten by the logging setup for a given command.
@@ -122,13 +28,13 @@ func main() {
12228
balancer.Register(cmdutil.ConsistentHashringBuilder)
12329

12430
// Build the complete command structure
125-
rootCmd, err := buildRootCommand()
31+
rootCmd, err := cmd.BuildRootCommand()
12632
if err != nil {
12733
log.Fatal().Err(err).Msg("failed to build root command")
12834
}
12935

13036
if err := rootCmd.Execute(); err != nil {
131-
if !errors.Is(err, errParsing) {
37+
if !errors.Is(err, cmd.ErrParsing) {
13238
log.Err(err).Msg("terminated with errors")
13339
}
13440
var termErr spiceerrors.TerminationError

cmd/spicedb/main_test.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ import (
88

99
"github.com/stretchr/testify/require"
1010

11+
"github.com/authzed/spicedb/pkg/cmd"
1112
"github.com/authzed/spicedb/pkg/spiceerrors"
1213
)
1314

1415
func TestMainCommandStructure(t *testing.T) {
1516
// Use the same root command structure as main()
16-
rootCmd, err := buildRootCommand()
17+
rootCmd, err := cmd.BuildRootCommand()
1718
require.NoError(t, err)
1819
require.NotNil(t, rootCmd)
1920

@@ -49,7 +50,7 @@ func TestMainCommandStructure(t *testing.T) {
4950
}
5051

5152
func TestMainCommandFlagErrorFunc(t *testing.T) {
52-
rootCmd, err := buildRootCommand()
53+
rootCmd, err := cmd.BuildRootCommand()
5354
require.NoError(t, err)
5455

5556
var buf bytes.Buffer
@@ -59,14 +60,14 @@ func TestMainCommandFlagErrorFunc(t *testing.T) {
5960
testErr := errors.New("test flag error")
6061
resultErr := rootCmd.FlagErrorFunc()(rootCmd, testErr)
6162

62-
require.Equal(t, errParsing, resultErr)
63+
require.Equal(t, cmd.ErrParsing, resultErr)
6364
output := buf.String()
6465
require.Contains(t, output, "test flag error")
6566
require.Contains(t, output, "Usage:")
6667
}
6768

6869
func TestBuildRootCommand(t *testing.T) {
69-
rootCmd, err := buildRootCommand()
70+
rootCmd, err := cmd.BuildRootCommand()
7071
require.NoError(t, err)
7172
require.NotNil(t, rootCmd)
7273
require.Equal(t, "spicedb", rootCmd.Use)
@@ -76,7 +77,7 @@ func TestBuildRootCommand(t *testing.T) {
7677
}
7778

7879
func TestErrorParsing(t *testing.T) {
79-
require.Equal(t, "parsing error", errParsing.Error())
80+
require.Equal(t, "parsing error", cmd.ErrParsing.Error())
8081
}
8182

8283
func TestTerminationErrorHandling(t *testing.T) {
@@ -106,7 +107,7 @@ func TestMainIntegration(t *testing.T) {
106107
os.Args = []string{"spicedb", "--help"}
107108

108109
// Use the same command structure as main()
109-
rootCmd, err := buildRootCommand()
110+
rootCmd, err := cmd.BuildRootCommand()
110111
require.NoError(t, err)
111112

112113
// Close write end and read the output
@@ -123,7 +124,7 @@ func TestMainIntegration(t *testing.T) {
123124
}
124125

125126
func TestManCommandExecution(t *testing.T) {
126-
rootCmd, err := buildRootCommand()
127+
rootCmd, err := cmd.BuildRootCommand()
127128
require.NoError(t, err)
128129

129130
manCmd, _, err := rootCmd.Find([]string{"man"})

0 commit comments

Comments
 (0)