Skip to content
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

Json-schema-validation #14

Merged
merged 4 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 131 additions & 0 deletions .github/workflows/docs-as-code-pr-commit-validation.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
name: Docs as Code PR and Commit Validation

on:
push:
branches:
- '*'
pull_request:
branches:
- '*'
workflow_dispatch:
inputs:
log_level:
description: 'Log level: 1=DEBUG, 2=INFO, 3=WARNING, 4=ERROR'
required: false
default: '2' # Set the default log level to INFO
skip_api_linting:
description: 'Skip the API linting job'
required: false
default: 'false'

env:
SWAGGERHUB_API_KEY: ${{ secrets.SWAGGERHUB_API_KEY }}
LOG_LEVEL: ${{ github.event.inputs.log_level }}

jobs:
spell-check:
runs-on: ubuntu-latest
environment: Production

steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Install Node.js
uses: actions/setup-node@v2
with:
node-version: '18'

- name: Install cspell
run: npm install -g cspell

- name: Run cspell
run: cspell --config ./.cspell.json "./products/**/*.md"

validate-manifests:
runs-on: ubuntu-latest
environment: Production
needs: spell-check

steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Install Node.js
uses: actions/setup-node@v2
with:
node-version: '18'

- name: Install AJV CLI
run: npm install -g ajv-cli

- name: Validate manifests
run: |
# source the utility script
. ./scripts/utilities.sh

for product in ./products/*; do
if [[ -d "$product" ]]; then
product_name=${product#./products/}
manifest="./products/$product_name/manifest.json"
if [[ -f "$manifest" ]]; then
# Further actions...
log_message $INFO "Validating manifest in product: $product_name"
log_message $DEBUG "Validating manifest: $manifest"
ajv validate -s ./schemas/manifest.schema.json -d "$manifest" --spec=draft2020
fi
fi
done

lint-api:
runs-on: ubuntu-latest
if: github.event.inputs.skip_api_linting != 'true'
environment: Production
needs: validate-manifests

steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Install SwaggerHub CLI
run: npm install -g swaggerhub-cli

- name: Iterate over product folders and validate APIs
shell: bash
run: |
# source the utility script
. ./scripts/utilities.sh

for product in ./products/*; do
log_message $DEBUG "Product: $product"
if [[ -d "$product" ]]; then
log_message $DEBUG "Product is a directory"
product_name=${product#./products/}
log_message $DEBUG "Product name: $product_name"
manifest="./products/$product_name/manifest.json"
log_message $DEBUG "Manifest: $manifest"
if [[ -f "$manifest" ]]; then
log_message $DEBUG "Manifest is a file"
validateAPIs=$(jq -r '.productMetadata.validateAPIs' "$manifest")
if [[ "$validateAPIs" == "true" ]]; then
log_message $INFO "Validating APIs for product: $product_name"
contentMetadata=$(jq -c '.contentMetadata[] | select(.type | ascii_downcase == "apiurl")' "$manifest")
echo "$contentMetadata" | jq -c '.' | while IFS= read -r contentMetadataItem; do
slug=$(echo "$contentMetadataItem" | jq -r '.slug')
log_message $INFO "Validating API: $slug"
swaggerhub api:validate "${SWAGGERHUB_ORG_NAME}/$slug" --fail-on-critical
done
else
log_message $WARNING "API validation is not enabled for product: $product_name"
fi
else
log_message $ERROR "Manifest is not a file"
fi
else
log_message $ERROR "Product is not a directory"
fi
done
env:
SWAGGERHUB_API_KEY: ${{ secrets.SWAGGERHUB_API_KEY }}
SWAGGERHUB_ORG_NAME: ${{ vars.SWAGGERHUB_ORG_NAME }}

36 changes: 36 additions & 0 deletions .github/workflows/docs-as-code.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,46 @@ jobs:
- name: Run cspell
run: cspell --config ./.cspell.json "./products/**/*.md"

validate-manifests:
runs-on: ubuntu-latest
environment: Production
needs: spell-check

steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Install Node.js
uses: actions/setup-node@v2
with:
node-version: '14'

- name: Install AJV CLI
run: npm install -g ajv-cli

- name: Validate manifests
run: |
# source the utility script
. ./scripts/utilities.sh

for product in ./products/*; do
if [[ -d "$product" ]]; then
product_name=${product#./products/}
manifest="./products/$product_name/manifest.json"
if [[ -f "$manifest" ]]; then
# Further actions...
log_message $INFO "Validating manifest in product: $product_name"
log_message $DEBUG "Validating manifest: $manifest"
ajv validate -s ./schemas/manifest-schema.json -d "$manifest" --spec=draft2020
fi
fi
done

lint-api:
runs-on: ubuntu-latest
if: github.event.inputs.skip_api_linting != 'true'
environment: Production
needs: validate-manifests

steps:
- name: Checkout repository
Expand Down
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ The following product structure must be adhered to allow for the automation to p
- product One _folder_ - contains all data relevant to "Product One"
- *.md _files_ - contains the markdown documents to be published within "Product One". The file name is used as the table-of-contents entry name.
- images _folder_ - a folder to house the product logo and _embedded_ sub-folder
- *.png / *.jpeg - a root level image to be used as the product logo (needs to be reference from the `manifest.json`)
- `*.png / *.jpeg` - a root level image to be used as the product logo (needs to be reference from the `manifest.json`)
- embedded _folder_ - a folder to storing all images to be embedded within the product markdown pages. See [Image Embedding Conventions](#image-embedding-convention) for more info on how to reference.
- manifest.json - stores product metadata (like description, slug, logo url, visibility, etc.) and content metadata (like table of contents order, page nesting, etc.)
- product Two ...
- product N ...
- product Two _folder_ ...
- product N _folder_ ...

### Image Embedding Convention

Expand Down Expand Up @@ -63,7 +63,7 @@ Check out the products operation at [`/products`](https://frankkilcommins.portal

### Table of Contents Conventions

The table of contents is completely driven by the `manifest.json` file contained within each Product folder.
The table of contents is completely driven by the `manifest.json` file contained within each Product folder. The specified manifest file MUST validate against [mainfest.schema.json](./schemas/manifest.schema.json).

A sample manifest is as follows:

Expand Down Expand Up @@ -152,7 +152,7 @@ The `contentMetadata` defines the following properties:

## GitHub Action

This repo comes with a simple boilerplate action that can be trigger manually or upon merge into the `main` branch.
This repo comes with a simple boilerplate action that can be triggered manually or upon merge into the `main` branch.

The action requires the following **repository secrets** to be configured:
- `SWAGGERHUB-API-KEY` - an API key associated to a user with the appropriate permission to be able to publish Portal content. See [Portal User Management](https://support.smartbear.com/swaggerhub-portal/docs/en/user-management.html) for more info.
Expand All @@ -166,5 +166,6 @@ The action requires the following **repository environment variables** to be con

The action performs the following jobs:
1. `spell-check`: Performs spell checking on all of the markdown files under the _products_ folder (**note** to add a list of known good custom words update the ./custom-words.txt file)
2. `lint-api`: Performs API standardization checks against each API referenced by a product manifest.json file. There is the ability to skip API validation for a specific API product via the productMetadata in the manifest.json.
3. `publish`: Publishes all of configured products into the referenced SwaggerHub Portal instance.
2. `validate-manifests`: Performs a JSON Schema validation check against the defined product manifest.json files to ensure they are correctly specified.
3. `lint-api`: Performs API standardization checks against each API referenced by a product manifest.json file. There is the ability to skip API validation for a specific API product via the productMetadata in the manifest.json.
4. `publish`: Publishes all of configured products into the referenced SwaggerHub Portal instance.
81 changes: 81 additions & 0 deletions schemas/manifest.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"productMetadata": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"slug": {
"type": "string"
},
"public": {
"type": "boolean"
},
"hidden": {
"type": "boolean"
},
"logo": {
"type": "string"
},
"logoDark": {
"type": "string"
},
"autoPublish": {
"type": "boolean"
},
"validateAPIs": {
"type": "boolean"
}
},
"required": [
"description",
"slug",
"public",
"hidden",
"logo",
"autoPublish",
"validateAPIs"
]
},
"contentMetadata": {
"type": "array",
"items": {
"type": "object",
"properties": {
"order": {
"type": "integer"
},
"parent": {
"type": "string"
},
"name": {
"type": "string"
},
"slug": {
"type": "string"
},
"type": {
"type": "string"
},
"contentUrl": {
"type": "string"
}
},
"required": [
"order",
"name",
"slug",
"type",
"contentUrl"
]
}
}
},
"required": [
"productMetadata",
"contentMetadata"
]
}
Loading