Goal: Integrate the normalize-issues service into a GitHub Actions workflow.
Estimated Time: 15 minutes
- Overview
- Prerequisites
- Basic Workflow Setup
- Customization Options
- Complete Pipeline: Collector → Builder → Generator
- Pipeline Orchestration Patterns
- Error Handling
- Best Practices
- Troubleshooting
- Additional Resources
This recipe shows how to run the normalize-issues service in GitHub Actions, either as a standalone job or as part of a complete living documentation pipeline (Collector → Builder → Generator).
Workflow File: docs/recipes/github-actions-normalize-issues.yml
- GitHub repository with Actions enabled
- Input file (
doc-issues.json) available in the repository or from a previous job - Write access to repository settings (for workflow configuration)
Copy docs/recipes/github-actions-normalize-issues.yml to your repository:
mkdir -p .github/workflows
cp docs/recipes/github-actions-normalize-issues.yml \
.github/workflows/normalize-issues.ymlEdit .github/workflows/normalize-issues.yml to match your needs:
name: Normalize Issues
on:
push:
branches:
- main # Trigger on push to main
workflow_dispatch: # Allow manual trigger
jobs:
normalize-issues:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.14
uses: actions/setup-python@v5
with:
python-version: '3.14'
cache: 'pip'
- name: Install living-doc-toolkit
run: |
pip install --upgrade pip
pip install -r requirements.txt
- name: Normalize issues
run: |
living-doc normalize-issues \
--input doc-issues.json \
--output pdf_ready.json \
--document-title "Product Requirements" \
--document-version "${{ github.ref_name }}"
- name: Upload PDF-ready JSON
uses: actions/upload-artifact@v4
with:
name: pdf-ready-json
path: pdf_ready.jsongit add .github/workflows/normalize-issues.yml
git commit -m "Add normalize-issues workflow"
git push- Go to your repository on GitHub
- Click Actions tab
- Find the "Normalize Issues" workflow
- Check that it runs successfully
- Download the
pdf-ready-jsonartifact to verify output
Override document metadata using workflow inputs:
on:
workflow_dispatch:
inputs:
document_title:
description: 'Document title'
required: true
default: 'Product Requirements'
document_version:
description: 'Document version'
required: true
default: '1.0.0'
jobs:
normalize-issues:
steps:
- name: Normalize issues
run: |
living-doc normalize-issues \
--input doc-issues.json \
--output pdf_ready.json \
--document-title "${{ inputs.document_title }}" \
--document-version "${{ inputs.document_version }}"Use Git tags or branch names for versioning:
- name: Get version from Git
id: version
run: echo "version=$(git describe --tags --always)" >> $GITHUB_OUTPUT
- name: Normalize issues
run: |
living-doc normalize-issues \
--input doc-issues.json \
--output pdf_ready.json \
--document-version "${{ steps.version.outputs.version }}"Process multiple collector outputs:
- name: Normalize multiple files
run: |
for input in outputs/*.json; do
output="normalized/$(basename $input)"
living-doc normalize-issues \
--input "$input" \
--output "$output"
doneThe full living documentation pipeline consists of three stages:
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ COLLECTOR │──────>│ BUILDER │──────>│ GENERATOR │
│ (GitHub) │ │ (Toolkit) │ │ (PDF) │
└─────────────┘ └─────────────┘ └─────────────┘
doc-issues.json pdf_ready.json living-doc.pdf
jobs:
collect:
name: Collect Issues
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Collect issues
uses: AbsaOSS/living-doc-collector-gh@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
output-file: doc-issues.json
labels: 'documentation'
- name: Upload collector output
uses: actions/upload-artifact@v4
with:
name: collector-output
path: doc-issues.json normalize:
name: Normalize Issues
needs: collect
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Download collector output
uses: actions/download-artifact@v4
with:
name: collector-output
- name: Set up Python 3.14
uses: actions/setup-python@v5
with:
python-version: '3.14'
cache: 'pip'
- name: Install living-doc-toolkit
run: |
pip install --upgrade pip
pip install -r requirements.txt
- name: Normalize issues
run: |
living-doc normalize-issues \
--input doc-issues.json \
--output pdf_ready.json \
--document-title "Product Requirements - Sprint ${{ github.run_number }}" \
--document-version "${{ github.ref_name }}"
- name: Upload PDF-ready JSON
uses: actions/upload-artifact@v4
with:
name: pdf-ready-json
path: pdf_ready.json generate:
name: Generate PDF
needs: normalize
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Download PDF-ready JSON
uses: actions/download-artifact@v4
with:
name: pdf-ready-json
- name: Generate PDF
uses: AbsaOSS/living-doc-generator-pdf@v1
with:
input-file: pdf_ready.json
output-file: living-documentation.pdf
- name: Upload PDF
uses: actions/upload-artifact@v4
with:
name: living-documentation
path: living-documentation.pdfRun stages sequentially with needs dependencies:
jobs:
collect:
# ... collector job
normalize:
needs: collect
# ... builder job
generate:
needs: normalize
# ... generator jobPros:
- Clear dependency chain
- Artifacts passed between stages
- Easy to debug
Cons:
- Longer total runtime (sequential execution)
Process multiple inputs in parallel:
jobs:
collect:
# ... collect issues from multiple repositories
normalize:
needs: collect
strategy:
matrix:
repo: [repo1, repo2, repo3]
steps:
- name: Normalize ${{ matrix.repo }}
run: |
living-doc normalize-issues \
--input doc-issues-${{ matrix.repo }}.json \
--output pdf_ready-${{ matrix.repo }}.jsonRun the pipeline on a schedule:
on:
schedule:
- cron: '0 2 * * 1' # Every Monday at 2 AM UTC
workflow_dispatch:Add error handling to continue on non-critical failures:
- name: Normalize issues
id: normalize
continue-on-error: true
run: |
living-doc normalize-issues \
--input doc-issues.json \
--output pdf_ready.json
- name: Check normalization result
if: steps.normalize.outcome == 'failure'
run: |
echo "❌ Normalization failed"
echo "Check logs for details"
exit 1Add retries for transient failures:
- name: Normalize issues
uses: nick-fields/retry@v2
with:
timeout_minutes: 10
max_attempts: 3
command: |
living-doc normalize-issues \
--input doc-issues.json \
--output pdf_ready.jsonAlways pin Python to 3.14 to ensure compatibility:
- uses: actions/setup-python@v5
with:
python-version: '3.14'Enable pip caching to speed up workflow:
- uses: actions/setup-python@v5
with:
python-version: '3.14'
cache: 'pip'Version your documents using semantic versioning:
--document-version "1.2.3"Always upload artifacts for debugging:
- uses: actions/upload-artifact@v4
with:
name: pdf-ready-json
path: pdf_ready.json
retention-days: 30Use --verbose flag in workflows for detailed logs:
- name: Normalize issues
run: |
living-doc normalize-issues \
--input doc-issues.json \
--output pdf_ready.json \
--verboseCause: Toolkit not installed correctly
Solution:
- name: Install living-doc-toolkit
run: |
pip install --upgrade pip
pip install -r requirements.txtCause: Input file not available from previous job
Solution:
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: collector-output
- name: Verify input file
run: ls -l doc-issues.jsonCause: Large input file or slow processing
Solution:
- name: Normalize issues
timeout-minutes: 15
run: |
living-doc normalize-issues \
--input doc-issues.json \
--output pdf_ready.json- Workflow YAML — Ready-to-use workflow file
- Cookbook: normalize-issues — How detection, compatibility, and normalization work
- Troubleshooting — Exit codes, common errors, FAQ
- GitHub Actions Documentation — Official GitHub Actions docs