msayson / smithy-gh-pages-action

GitHub Action to generate API documentation from Smithy models and deploy to GitHub Pages
GNU General Public License v3.0
0 stars 0 forks source link

Feature request: support maintaining API docs for multiple concurrent versions #1

Closed msayson closed 3 months ago

msayson commented 3 months ago

Feature request

Add support for generating/maintaining API documentation across multiple API versions.

Background

The current GitHub Action only supports deploying a single version of API documentation to GitHub Pages at a given time.

For example, if you run the action with api-docs-filepath: v1/docs.html, and later run the action with api-docs-filepath: v2/docs.html, only the most recent run's API documentation will be deployed to your GitHub Page, even if they have distinct filepaths.

Current workaround

Clients who want to use this GitHub Action to maintain API docs for multiple versions of their API package must maintain a separate GitHub repository for each version they want to generate API docs for.

This is not practical, so for all intents and purposes this GitHub Action currently only supports automated API documentation for a single API version, and should likely be scoped to only run against a single Git branch representing the latest supported version.

Feasibility/effort required

Unknown.

Unclear if there is a straightforward way to support this based on how GitHub Pages deployments and GitHub Actions work.

msayson commented 3 months ago

Ideal future scenario would be for clients to be able to pass in some type of API version identifier, such as by including ${{ github.ref_name }} in their API doc filepath as shown below, and to have the Action leave existing deployed files and only write to the specified filepaths.

name: Generate API docs and deploy to GitHub Pages

on:
  # Automatically trigger when push to any branch
  push:
  # Enable running workflow manually from GitHub Actions
  workflow_dispatch:

# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
  contents: read
  pages: write
  id-token: write

jobs:
  generate-api-docs:
    name: Generate API Documentation
    runs-on: ubuntu-latest
    steps:
      - name: Generate API docs and deploy to GitHub Pages
        uses: msayson/smithy-gh-pages-action@v1.1.0
        with:
          gradle-smithy-task-name: build
          openapi-json-filepath: build/smithyprojections/consent-management-api-models/source/openapi/ConsentManagementApi.openapi.json
          api-docs-filepath: ${{ github.ref_name }}/docs.html

Even if possible, this would have the caveat of leading to more edge cases around accumulating stale files if clients make multiple changes to their API doc filepath, which may increase confusion for end consumers of the API docs.

msayson commented 3 months ago

See https://github.com/orgs/community/discussions/21582 and https://stackoverflow.com/questions/47643881/github-pages-maintaining-multiple-versions, this is a general issue around how GitHub Pages works.

Work-arounds would include having a client have all the versions of their API spec files in the same repository/branch, and passing in an array of API specs and corresponding preferred filepaths, so that we can make a single GitHub Pages deployment that includes all the API docs at various filepaths.

Another more customized approach some folks have taken that may not fit into this type of GitHub Action is pushing files from multiple sources/packages/branches to a single repository that is then deployed to GitHub Pages.

msayson commented 3 months ago

Using JSON string inputs to support multiple API configs

GitHub Actions doesn't directly support array inputs as per the GitHub Actions workflow syntax for jobs.<job_id>.with and jobs.<job_id>.steps[*].with.args, however, as per https://stackoverflow.com/a/75420778, it is possible to take in and parse a JSON string in Actions, or have other custom parsing against a single string input.

We could have clients pass in a JSON object of all their API configs, eg.

with:
  api-configs: '[{"openapi-json-filepath":"openapi-specs/v1/openapi.json","api-doc-filepath":"v1/docs.html"},{"openapi-json-filepath":"openapi-specs/v2/openapi.json","api-doc-filepath":"v2/docs.html"}]'

and define a script that pipes this through jq and iteratively generates API HTML documentation files for each config via ReDoc, and then upload them all to GitHub Pages in one go.

Caveat: actions/upload-pages-artifact only accepts a single directory as input.

Supporting API docs across multiple branches

To support auto-generating API docs across multiple code branches, we could build on the above approach by adding an optional "source-repository-branch" parameter to each JSON object in the input. We would then fetch the OpenAPI spec from each branch within our script.

This increases this action's complexity since we'd have to duplicate logic currently abstracted to third-party actions.

This all seems feasible while it would significantly increase user-facing complexity, since it will be more difficult to use versus the simple current approach of giving a single OpenAPI spec input and a single destination filepath input.

msayson commented 3 months ago

Note for the above approach around taking in a JSON string containing multiple API versions' configs:

Since we'd be piping through jq anyway, we can use YAML's block string style and accept slightly more readable/maintainable inputs such as the following:

with:
  api-docs-dir: docs
  api-configs: |-
    [{
      "source-git-branch": "releases/v1",
      "openapi-json-filepath": "openapi-specs/v1/openapi.json",
      "api-doc-filepath": "v1/docs.html"
    },
    {
      "source-git-branch": "releases/v2",
      "openapi-json-filepath": "openapi-specs/v2/openapi.json",
      "api-doc-filepath": "v2/docs.html"
    }]

Our script would run git fetch --all to fetch context on all the remote branches, then pipe the api configs JSON string through jq and for each config call another sh script to:

  1. Fetch the specified OpenAPI JSON file from the given branch of the GitHub repository
    • git checkout origin/$SOURCE_BRANCH_NAME -- $SOURCE_OPENAPI_JSON_FILEPATH
  2. Convert the JSON file to YAML via yq
  3. Generate ReDoc API HTML documentation from that YAML in the specified final directory of $COMMON_API_DOCS_DIR/$SPECIFIC_API_DOC_FILEPATH

After the ReDoc API docs are all produced, the subsequent action-level steps would proceed as before, just using the api-docs-dir input for the actions/upload-pages-artifact call.

msayson commented 3 months ago

Forked this repository to msayson/openapi-github-pages-action which focuses solely on generating API documentation from OpenAPI specs, where have also implemented this functionality to support generating/maintaining API docs across multiple API versions that may have specs from different Git branches.

Was not trivial and does increase the complexity of usage for clients not familiar with YAML/JSON, but would expect to want this for many production use cases where we have multiple supported API versions.

https://github.com/msayson/openapi-github-pages-action/releases/tag/v1.0.0 starts with only supporting a single OpenAPI spec file and output HTML doc, but is very simple to use.

https://github.com/msayson/openapi-github-pages-action/releases/tag/v2.0.0 implements support for documenting multiple API versions across branches, major version upgrade since involves significant breaking changes to the user-facing interface.

Resolving this issue since it's now solved in the fork which better serves that use case and completely abstracts away from Smithy/Gradle.

Will focus this repo on Smithy/Gradle workflows, where we will assume that OpenAPI spec files do not yet exist.