Skip to content
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
43 changes: 43 additions & 0 deletions .github/scripts/docs/fix_asset_paths.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env python3
import io
import os
import sys

def rewrite_paths(path: str) -> bool:
if not os.path.isfile(path):
return False
with io.open(path, 'r', encoding='utf-8', errors='ignore') as f:
s = f.read()

# Markdown: ](/docs/... -> ](./docs/...
s = s.replace('](/docs/', '](./docs/')
# Markdown escaped (embedded JSON): ](\/docs\/ -> ](./docs/
s = s.replace('](\\/docs\\/', '](./docs/')

# HTML attributes
s = s.replace('src="/docs/', 'src="./docs/')
s = s.replace("src='/docs/", "src='./docs/")
s = s.replace('href="/docs/', 'href="./docs/')
s = s.replace("href='/docs/", "href='./docs/")

# Generic occurrences in embedded JSON: \/docs\/ -> \.\/docs\/
s = s.replace('\\/docs\\/', '\\./docs\\/')

with io.open(path, 'w', encoding='utf-8') as f:
f.write(s)
print(f"Rewrote /docs -> ./docs in {path}")
return True


def main(argv):
if len(argv) < 2:
print("Usage: fix_asset_paths.py <index.html>", file=sys.stderr)
return 2
path = argv[1]
ok = rewrite_paths(path)
return 0 if ok else 0


if __name__ == '__main__':
raise SystemExit(main(sys.argv))

84 changes: 84 additions & 0 deletions .github/scripts/docs/inject_mermaid.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#!/usr/bin/env bash
set -euo pipefail

# Usage:
# bash scripts/docs/inject_mermaid.sh <INDEX_HTML> [MERMAID_VERSION]
# or with env vars INDEX and MERMAID_VERSION

INDEX="${1:-${INDEX:-}}"
MERMAID_VERSION="${2:-${MERMAID_VERSION:-10}}"

if [[ -z "${INDEX}" ]]; then
echo "INDEX path not provided" >&2
exit 1
fi

if [[ ! -f "${INDEX}" ]]; then
echo "Index not found: ${INDEX}"
exit 0
fi

export INDEX MERMAID_VERSION
python3 - << 'PY'
import os, io

p = os.environ['INDEX']
version = os.environ.get('MERMAID_VERSION', '10')

with io.open(p, 'r', encoding='utf-8', errors='ignore') as f:
s = f.read()

if '<!-- MERMAID_INJECT_START -->' in s:
print('Mermaid already injected; skipping.')
else:
inject = '''\
<!-- MERMAID_INJECT_START -->
<style>.mermaid{max-width:100%;overflow-x:auto}</style>
<script src="https://cdn.jsdelivr.net/npm/mermaid@__VER__/dist/mermaid.min.js"></script>
<script>
(function(){
function convertBlocks(root){
var blocks = root.querySelectorAll('pre code.language-mermaid, pre code.lang-mermaid, code.mermaid');
blocks.forEach(function(code){
var txt = code.textContent;
var pre = code.closest && code.closest('pre') || code;
var div = document.createElement('div');
div.className = 'mermaid';
div.textContent = txt;
if (pre && pre.parentNode) pre.parentNode.replaceChild(div, pre); else code.parentNode.replaceChild(div, code);
});
}
function renderAll(){
try {
if (window.mermaid) {
mermaid.initialize({ startOnLoad: false, securityLevel: 'loose' });
if (mermaid.run) { mermaid.run({ querySelector: '.mermaid' }); }
else if (mermaid.init) { mermaid.init(undefined, '.mermaid'); }
}
} catch(e){ console.error('Mermaid init error', e); }
}
function process(){ convertBlocks(document); renderAll(); }
window.addEventListener('load', function(){
process();
var obs = new MutationObserver(function(){
if (document.querySelector('pre code.language-mermaid, pre code.lang-mermaid, code.mermaid')) {
process();
}
});
obs.observe(document.body, { childList: true, subtree: true });
});
})();
</script>
<!-- MERMAID_INJECT_END -->'''
inject = inject.replace('__VER__', version)

if '</body>' in s:
s = s.replace('</body>', inject + '\n</body>', 1)
else:
s = s + inject

with io.open(p, 'w', encoding='utf-8') as f:
f.write(s)
print('Injected Mermaid support into', p)
PY

207 changes: 207 additions & 0 deletions .github/workflows/backend-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
name: backend-docs

on:
workflow_call:
inputs:
docs_dir:
description: Directory contenente description.md e openapi
required: false
default: "docs"
type: string
openapi_path:
description: Path a openapi (se non usare autodetect)
required: false
default: ""
type: string
mermaid_version:
description: Versione di Mermaid JS da iniettare (es. 10 o 10.9.1)
required: false
default: "10"
type: string
description_md:
description: Path a description.md (se diverso da default)
required: false
default: ""
type: string
output_dir:
description: Directory di output static site (per Pages)
required: false
default: "site"
type: string
node_version:
description: Versione Node per npx (@redocly/cli/marked)
required: false
default: "20"
type: string
deploy_pages:
description: Esegui deploy su GitHub Pages
required: false
default: "true"
type: string
checkout_submodules:
description: Checkout Git submodules as part of docs (true/false)
required: false
default: "false"
type: string
publish:
description: When 'true' uploads artifact and deploys Pages
required: false
default: "true"
type: string

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: "pages"
cancel-in-progress: false

jobs:
build-and-publish-docs:
name: Build Redoc HTML and Publish
runs-on: ubuntu-22.04
timeout-minutes: 20
defaults:
run:
working-directory: ${{ github.workspace }}

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: ${{ inputs.checkout_submodules == 'true' }}
# If you use submodules to pull docs from private repos, set submodules: true in the caller
# with:
# submodules: true

- name: Check gh-pages branch availability
if: ${{ inputs.publish == 'true' && (inputs.deploy_pages || 'true') == 'true' }}
id: ghpages
shell: bash
run: |
set -euo pipefail
if git ls-remote --exit-code --heads "https://github.com/${GITHUB_REPOSITORY}.git" gh-pages >/dev/null 2>&1; then
echo "exists=true" >> "$GITHUB_OUTPUT"
else
echo "exists=false" >> "$GITHUB_OUTPUT"
echo "::notice title=gh-pages branch::No gh-pages branch found. Building from empty site state."
fi

- name: Checkout existing Pages (gh-pages)
if: ${{ inputs.publish == 'true' && (inputs.deploy_pages || 'true') == 'true' && steps.ghpages.outputs.exists == 'true' }}
uses: actions/checkout@v4
with:
ref: gh-pages
path: .gh-pages-prev

- name: Setup Node.js ${{ inputs.node_version }}
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node_version || '20' }}

- name: Resolve BRANCH_DIR (head_ref or ref_name)
id: branchdir
shell: bash
run: |
set -euo pipefail
if [[ -n "${GITHUB_HEAD_REF:-}" ]]; then
RAW="$GITHUB_HEAD_REF"
else
RAW="$GITHUB_REF_NAME"
fi
SANITIZED="${RAW//\//-}"
echo "Resolved BRANCH values: raw='$RAW' sanitized='$SANITIZED'"
echo "::notice title=BRANCH_DIR::Using '$SANITIZED' (raw: '$RAW')"
echo "BRANCH_RAW=$RAW" >> "$GITHUB_ENV"
echo "BRANCH_DIR=$SANITIZED" >> "$GITHUB_ENV"
echo "dir=$SANITIZED" >> "$GITHUB_OUTPUT"
echo "raw=$RAW" >> "$GITHUB_OUTPUT"

- name: Build docs with @redocly/cli (bundle per branch)
shell: bash
run: |
set -euo pipefail
DOCS_DIR="${{ inputs.docs_dir || 'docs' }}"
OPENAPI="${{ inputs.openapi_path || '' }}"
OUT_DIR="${{ inputs.output_dir || 'site' }}"
BRANCH_DIR="${BRANCH_DIR}"
mkdir -p "$OUT_DIR"
if [[ -d .gh-pages-prev ]]; then
rsync -a --exclude '.git' .gh-pages-prev/ "$OUT_DIR/" || true
fi
if [[ -z "$OPENAPI" ]]; then
for f in "$DOCS_DIR"/openapi.yaml "$DOCS_DIR"/openapi.yml "$DOCS_DIR"/openapi.json; do
if [[ -f "$f" ]]; then OPENAPI="$f"; break; fi
done
fi
if [[ -z "$OPENAPI" || ! -f "$OPENAPI" ]]; then
echo "File OpenAPI non trovato (cerca in ${DOCS_DIR}/openapi.yaml|yml|json o specifica input openapi_path)" >&2
exit 2
fi
mkdir -p "$OUT_DIR/$BRANCH_DIR"

npx -y @redocly/cli build-docs "$OPENAPI" -o "$OUT_DIR/$BRANCH_DIR/index.html"
rsync -a --include='*/' --include='*.png' --exclude='*' "$DOCS_DIR"/ "$OUT_DIR/$BRANCH_DIR/docs/" || true


- name: Fix asset paths in generated HTML (HTML + embedded JSON)
shell: bash
continue-on-error: true
run: |
set -euo pipefail
OUT_DIR="${{ inputs.output_dir || 'site' }}"
BRANCH_DIR="${BRANCH_DIR}"
INDEX="$OUT_DIR/$BRANCH_DIR/index.html"

if [[ ! -f "$INDEX" ]]; then
echo "Index not found: $INDEX"
exit 0
fi
python3 ".github/scripts/docs/fix_asset_paths.py" "$INDEX"

- name: Enable Mermaid diagrams (inject script)
shell: bash
continue-on-error: true
run: |
set -euo pipefail
OUT_DIR="${{ inputs.output_dir || 'site' }}"
BRANCH_DIR="${BRANCH_DIR}"
INDEX="$OUT_DIR/$BRANCH_DIR/index.html"
MERMAID_VERSION="${{ inputs.mermaid_version || '10' }}"
bash ".github/scripts/docs/inject_mermaid.sh" "$INDEX" "$MERMAID_VERSION"
# --- publish gating (artifact + deploy) ---

- name: Upload Pages artifact
if: ${{ inputs.publish == 'true' && (inputs.deploy_pages || 'true') == 'true' }}
uses: actions/upload-pages-artifact@v3
with:
name: github-pages-${{ github.run_id }}-${{ github.run_attempt }}
path: ${{ inputs.output_dir || 'site' }}

- name: Deploy to GitHub Pages
if: ${{ inputs.publish == 'true' && (inputs.deploy_pages || 'true') == 'true' }}
id: deployment
uses: actions/deploy-pages@v4
with:
artifact_name: github-pages-${{ github.run_id }}-${{ github.run_attempt }}

- name: Report GitHub Pages URLs
if: ${{ inputs.publish == 'true' && (inputs.deploy_pages || 'true') == 'true' && steps.deployment.outputs.page_url != '' }}
shell: bash
run: |
set -euo pipefail
BASE_URL="${{ steps.deployment.outputs.page_url }}"
BRANCH_URL="${BASE_URL%/}/${BRANCH_DIR}/"
echo "::notice title=Pages base URL::${BASE_URL}"
echo "::notice title=Pages branch URL::${BRANCH_URL}"
{
echo "### GitHub Pages"
echo "- Base URL: ${BASE_URL}"
echo "- Branch URL (${BRANCH_RAW}): ${BRANCH_URL}"
} >> "$GITHUB_STEP_SUMMARY"

- name: Skipping publish (publish='${{ inputs.publish }}', deploy_pages='${{ inputs.deploy_pages }}')
if: ${{ inputs.publish != 'true' || (inputs.deploy_pages || 'true') != 'true' }}
run: echo "Skipping artifact upload and deploy (publish=${{ inputs.publish }}, deploy_pages=${{ inputs.deploy_pages }})"
10 changes: 8 additions & 2 deletions .github/workflows/docs-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,16 @@ on:
pull_request:
paths:
- "docs/**"
- "openapi.json"
- ".github/workflows/docs-build.yml"
- ".github/workflows/backend-docs.yml"
- ".github/scripts/docs/**"

jobs:
build:
name: Reusable Docs Build
uses: FlowPay/ci-templates/.github/workflows/backend-docs.yml@main
secrets: inherit
uses: ./.github/workflows/backend-docs.yml
with:
docs_dir: docs
openapi_path: openapi.json
publish: ${{ github.event_name == 'push' && 'true' || 'false' }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ openapi.html
postman_collection.json
Simplified Flow.pdf
old-openapi.json
.tmp/
1 change: 0 additions & 1 deletion .tmp/gateway.client
Submodule gateway.client deleted from 1f23fe
Loading