From 68c1ac237aec685bb929d6f40fdbe93cad10f080 Mon Sep 17 00:00:00 2001 From: Doug Chapman Date: Thu, 23 Apr 2026 12:58:56 -0700 Subject: [PATCH 1/4] chore: simplify the api docs workflow --- .github/workflows/api-docs.yml | 5 +--- util/doc.config | 1 + util/doc.go | 55 +++++++++++++++++++++++++++------- 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/.github/workflows/api-docs.yml b/.github/workflows/api-docs.yml index 76a0eb7fc69..6e53f3b76ea 100644 --- a/.github/workflows/api-docs.yml +++ b/.github/workflows/api-docs.yml @@ -31,10 +31,7 @@ jobs: with: go-version: ">=1.22" - name: Generate API documentation - run: | - mkdir -p api-output - cd util - go run doc.go --config doc.config --out ../pages-output + run: go run util/doc.go - name: Upload pages artifact uses: actions/upload-pages-artifact@v3 with: diff --git a/util/doc.config b/util/doc.config index cea4a5ff171..e5cfec6c2e6 100644 --- a/util/doc.config +++ b/util/doc.config @@ -1,5 +1,6 @@ { "BaseDirectory": "..", + "OutputDirectory": "../pages-output", "Sections": [{ "Name": "Low-level infrastructure", "Headers": [ diff --git a/util/doc.go b/util/doc.go index da4b2907564..497eb99794f 100644 --- a/util/doc.go +++ b/util/doc.go @@ -18,6 +18,7 @@ import ( "os" "path/filepath" "regexp" + "runtime" "strconv" "strings" "unicode" @@ -28,7 +29,10 @@ type Config struct { // BaseDirectory is a path to which other paths in the file are // relative. BaseDirectory string - Sections []ConfigSection + // OutputDirectory is the path where generated files will be written. + // Resolved relative to the config file's location. + OutputDirectory string + Sections []ConfigSection } type ConfigSection struct { @@ -908,23 +912,27 @@ func copyFile(outPath string, inFilePath string) error { return os.WriteFile(filepath.Join(outPath, filepath.Base(inFilePath)), bytes, 0666) } +// sourceDir returns the directory containing this source file. +func sourceDir() string { + _, file, _, ok := runtime.Caller(0) + if !ok { + fmt.Println("Failed to determine source directory") + os.Exit(1) + } + return filepath.Dir(file) +} + func main() { var ( - configFlag *string = flag.String("config", "doc.config", "Location of config file") - outputDir *string = flag.String("out", ".", "Path to the directory where the output will be written") + configFlag *string = flag.String("config", "", "Location of config file (default: doc.config next to doc.go)") + outputDir *string = flag.String("out", "", "Path to the output directory (overrides config)") config Config ) flag.Parse() if len(*configFlag) == 0 { - fmt.Printf("No config file given by --config\n") - os.Exit(1) - } - - if len(*outputDir) == 0 { - fmt.Printf("No output directory given by --out\n") - os.Exit(1) + *configFlag = filepath.Join(sourceDir(), "doc.config") } configBytes, err := os.ReadFile(*configFlag) @@ -938,6 +946,31 @@ func main() { os.Exit(1) } + // Resolve BaseDirectory relative to the config file's location, + // so the tool can be run from any working directory. + configDir := filepath.Dir(*configFlag) + if !filepath.IsAbs(config.BaseDirectory) { + config.BaseDirectory = filepath.Join(configDir, config.BaseDirectory) + } + + // Use --out if provided, otherwise fall back to config, resolved + // relative to the config file's location. + if len(*outputDir) == 0 { + *outputDir = config.OutputDirectory + if !filepath.IsAbs(*outputDir) { + *outputDir = filepath.Join(configDir, *outputDir) + } + } + if len(*outputDir) == 0 { + fmt.Printf("No output directory given by --out or OutputDirectory in config\n") + os.Exit(1) + } + + if err := os.MkdirAll(*outputDir, 0777); err != nil { + fmt.Printf("Failed to create output directory: %s\n", err) + os.Exit(1) + } + headerDescriptions, err := generate(*outputDir, &config) if err != nil { fmt.Printf("Failed to generate output: %s\n", err) @@ -949,7 +982,7 @@ func main() { os.Exit(1) } - if err := copyFile(*outputDir, "doc.css"); err != nil { + if err := copyFile(*outputDir, filepath.Join(filepath.Dir(*configFlag), "doc.css")); err != nil { fmt.Printf("Failed to copy static file: %s\n", err) os.Exit(1) } From f78a3321aba7e2a49c3d4de8aab734a9139f0a68 Mon Sep 17 00:00:00 2001 From: Doug Chapman Date: Tue, 9 Jun 2026 10:20:24 -0700 Subject: [PATCH 2/4] fix: validate OutputDirectory before resolving, update header comment --- util/doc.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/util/doc.go b/util/doc.go index 497eb99794f..d3f0c81e12e 100644 --- a/util/doc.go +++ b/util/doc.go @@ -2,10 +2,11 @@ // doc generates HTML files from the comments in header files. // -// doc expects to be given the path to a JSON file via the --config option. -// From that JSON (which is defined by the Config struct) it reads a list of -// header file locations and generates HTML files for each in the current -// directory. +// doc reads a JSON config file (defined by the Config struct) for a list of +// header file locations and generates HTML files. The config file is located +// automatically relative to this source file, or can be overridden with +// --config. Output is written to OutputDirectory from the config, or +// overridden with --out. package main import ( @@ -956,15 +957,15 @@ func main() { // Use --out if provided, otherwise fall back to config, resolved // relative to the config file's location. if len(*outputDir) == 0 { + if len(config.OutputDirectory) == 0 { + fmt.Printf("No output directory given by --out or OutputDirectory in config\n") + os.Exit(1) + } *outputDir = config.OutputDirectory if !filepath.IsAbs(*outputDir) { *outputDir = filepath.Join(configDir, *outputDir) } } - if len(*outputDir) == 0 { - fmt.Printf("No output directory given by --out or OutputDirectory in config\n") - os.Exit(1) - } if err := os.MkdirAll(*outputDir, 0777); err != nil { fmt.Printf("Failed to create output directory: %s\n", err) From d6e862527a09ce8136474231d3d396a6efd2330c Mon Sep 17 00:00:00 2001 From: Doug Chapman Date: Mon, 6 Jul 2026 16:28:31 -0700 Subject: [PATCH 3/4] chore: address review feedback on api-docs workflow - Add PR validation job to catch malformed header comments before merge - Gate deploy on push events only (not PRs or workflow_dispatch) - Fix MkdirAll permissions 0777 -> 0755 - Add pages-output/ to .gitignore --- .github/workflows/api-docs.yml | 19 +++++++++++++++++++ .gitignore | 1 + util/doc.go | 2 +- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/.github/workflows/api-docs.yml b/.github/workflows/api-docs.yml index d8e53747a1d..88041c0bed8 100644 --- a/.github/workflows/api-docs.yml +++ b/.github/workflows/api-docs.yml @@ -9,6 +9,13 @@ on: - 'util/doc.config' - 'util/doc.css' - '.github/workflows/api-docs.yml' + pull_request: + paths: + - 'include/openssl/**' + - 'util/doc.go' + - 'util/doc.config' + - 'util/doc.css' + - '.github/workflows/api-docs.yml' permissions: contents: read @@ -20,7 +27,19 @@ concurrency: cancel-in-progress: false jobs: + validate-api-docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-go@v6 + with: + go-version: ">=1.22" + - name: Generate API documentation + run: go run util/doc.go + publish-api-docs: + if: github.event_name == 'push' + needs: validate-api-docs runs-on: ubuntu-latest environment: name: github-pages diff --git a/.gitignore b/.gitignore index 1a47f3a0bab..51344911298 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,4 @@ symbols.txt /compile_commands.json /scratch awslcTestTmpFile* +/pages-output diff --git a/util/doc.go b/util/doc.go index d3f0c81e12e..2ec486b7bc3 100644 --- a/util/doc.go +++ b/util/doc.go @@ -967,7 +967,7 @@ func main() { } } - if err := os.MkdirAll(*outputDir, 0777); err != nil { + if err := os.MkdirAll(*outputDir, 0755); err != nil { fmt.Printf("Failed to create output directory: %s\n", err) os.Exit(1) } From f40a084b1a4c36df20b6003dfa4dc644b8715394 Mon Sep 17 00:00:00 2001 From: Doug Chapman Date: Thu, 16 Jul 2026 14:10:21 -0700 Subject: [PATCH 4/4] Address PR nits --- .github/workflows/api-docs.yml | 9 +++++++++ util/doc.go | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/api-docs.yml b/.github/workflows/api-docs.yml index 7fdafb1cfd5..0b81d6f930f 100644 --- a/.github/workflows/api-docs.yml +++ b/.github/workflows/api-docs.yml @@ -28,7 +28,12 @@ concurrency: jobs: validate-api-docs: + concurrency: + group: api-docs-validate-${{ github.ref }} + cancel-in-progress: true runs-on: ubuntu-latest + permissions: + contents: read steps: - uses: actions/checkout@v6 - uses: actions/setup-go@v6 @@ -41,6 +46,10 @@ jobs: if: github.event_name == 'push' needs: validate-api-docs runs-on: ubuntu-latest + permissions: + contents: read + pages: write + id-token: write environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} diff --git a/util/doc.go b/util/doc.go index 2ec486b7bc3..511bb7f9aec 100644 --- a/util/doc.go +++ b/util/doc.go @@ -983,7 +983,7 @@ func main() { os.Exit(1) } - if err := copyFile(*outputDir, filepath.Join(filepath.Dir(*configFlag), "doc.css")); err != nil { + if err := copyFile(*outputDir, filepath.Join(configDir, "doc.css")); err != nil { fmt.Printf("Failed to copy static file: %s\n", err) os.Exit(1) }