Monorepo Support
Overviewโ
All reusable workflows now support Python monorepos (multiple packages in one repository) while maintaining 100% backward compatibility with single-project repositories.
Key Featuresโ
โ
Multiple packages in one repository - Test, build, and release packages independently
โ
Project-specific artifacts - No naming collisions between packages
โ
Independent releases - Each package can have its own version and release cycle
โ
Configurable paths - Specify working directories and file paths per package
โ
Backward compatible - Existing single-project workflows work unchanged
Quick Startโ
Monorepo Structure Exampleโ
my-monorepo/
โโโ packages/
โ โโโ core/
โ โ โโโ src/
โ โ โโโ tests/
โ โ โโโ pyproject.toml
โ โโโ utils/
โ โ โโโ src/
โ โ โโโ tests/
โ โ โโโ pyproject.toml
โ โโโ api/
โ โโโ src/
โ โโโ tests/
โ โโโ pyproject.toml
โโโ .github/workflows/
Basic Example: Testing Multiple Packagesโ
name: Test All Packages
on: [push, pull_request]
jobs:
test-core:
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_uv_run_test.yaml@master
with:
project_name: core # Package identifier
test_working_directory: ./packages/core # Package directory
test_type: unit-test
all_test_items_paths: '["./packages/core/tests"]'
test-utils:
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_uv_run_test.yaml@master
with:
project_name: utils
test_working_directory: ./packages/utils
test_type: unit-test
all_test_items_paths: '["./packages/utils/tests"]'
Essential Parametersโ
Core Monorepo Parametersโ
| Parameter | Used In | Purpose | Example |
|---|---|---|---|
project_name | Most workflows | Package identifier for artifact naming | core, utils, api |
test_working_directory | Test workflows | Directory for running tests | ./packages/core |
package_working_directory | Build workflows | Directory for building packages | ./packages/core |
build_context | Docker workflows | Docker build context directory | ./services/api |
tag_prefix | Release workflows | Git tag prefix for releases | core/ โ core/v1.2.3 |
Parameter Usage by Workflowโ
Testing Workflowsโ
rw_uv_run_test.yaml:project_name,test_working_directoryrw_poetry_run_test.yaml:project_name,test_working_directoryrw_run_test.yaml:project_name,test_working_directory,requirements_path,requirements_test_pathrw_get_tests.yaml:test_working_directory
Building & Publishingโ
rw_python_package.yaml:project_name,package_working_directoryrw_push_pypi.yaml:package_working_directory
Coverage & Qualityโ
rw_organize_test_cov_reports.yaml:project_namerw_upload_test_cov_report.yaml:project_namerw_sonarqube_scan.yaml:project_name,project_working_directory,sonar_project_key
Release & Deploymentโ
rw_build_git-tag_and_create_github-release.yaml:package_working_directory,tag_prefixrw_docker_operations.yaml:build_context,dockerfile_path,project_namerw_documentation_deployment.yaml:docs_working_directory,project_name
Complete Examplesโ
Example 1: Full CI/CD Pipelineโ
name: CI/CD - Core Package
on:
push:
branches: [main]
paths:
- 'packages/core/**'
- '.github/workflows/ci-core.yaml'
jobs:
# Test
test:
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_poetry_run_test.yaml@master
with:
project_name: core
test_working_directory: ./packages/core
test_type: unit-test
all_test_items_paths: '["./tests"]'
# Organize coverage
coverage:
needs: test
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_organize_test_cov_reports.yaml@master
with:
project_name: core
test_type: unit-test
# Upload to Codecov
codecov:
needs: coverage
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_upload_test_cov_report.yaml@master
with:
project_name: core
test_type: unit-test
upload-to-codecov: true
secrets:
codecov_token: ${{ secrets.CODECOV_TOKEN }}
# Build package
build:
needs: test
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_python_package.yaml@master
with:
operation: build
package_working_directory: ./packages/core
project_name: core
upload-artifacts: true
Example 2: Tag-Triggered Releases ๐ท๏ธโ
The standard Git workflow - Push a tag to trigger automatic releases.
Single-Project Tag Releaseโ
Workflow (.github/workflows/release.yaml):
name: Release on Tag
on:
push:
tags:
- 'v*.*.*' # Matches v1.0.0, v2.1.3, etc.
permissions:
contents: write
packages: write
id-token: write
jobs:
release:
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_release_complete.yaml@master
secrets: inherit
Usage:
git tag v1.2.3
git push origin v1.2.3
# Automatic release triggered!
Monorepo Tag Releaseโ
Tag Format: {package-name}/v{version}
Workflow (.github/workflows/release.yaml):
name: Monorepo Release on Tag
on:
push:
tags:
- '*/v*.*.*' # Matches core/v1.0.0, utils/v2.1.3, etc.
jobs:
# Step 1: Extract package from tag
extract-package:
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_extract_package_from_tag.yaml@master
# Step 2: Release the package
release:
needs: extract-package
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_release_complete.yaml@master
with:
package-name: ${{ needs.extract-package.outputs.package_name }}
secrets: inherit
Usage:
# Release core package
git tag core/v1.2.3
git push origin core/v1.2.3
# Release utils package
git tag utils/v2.0.0
git push origin utils/v2.0.0
Complete Examples:
Example 3: Centralized Configuration with Intent.yamlโ
Combine tag-triggered releases with centralized configuration!
Intent.yaml Configurationโ
# .github/tag_and_release/intent.yaml
packages:
- name: core
working_directory: ./packages/core
tag_prefix: core/
python:
auth_method: oidc
docker:
registries:
dockerhub: docker.io
ghcr: ghcr.io
- name: utils
working_directory: ./packages/utils
tag_prefix: utils/
python:
auth_method: token # Override default
- name: api
working_directory: ./services/api
tag_prefix: api/
# Uses all defaults
defaults:
git:
commit:
name: "GitHub Actions Bot"
email: "actions@github.com"
python:
auth_method: oidc
docker:
registries:
dockerhub: docker.io
ghcr: ghcr.io
health_check:
port: 8000
path: "/health"
Release Workflow Using Intent.yamlโ
name: Release Package
on:
push:
tags:
- 'core/v*.*.*'
- 'utils/v*.*.*'
- 'api/v*.*.*'
jobs:
# Extract package name from tag
parse-tag:
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_extract_package_from_tag.yaml@master
# Release with intent.yaml configuration
release:
needs: parse-tag
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_release_complete.yaml@master
with:
package-name: ${{ needs.parse-tag.outputs.package_name }} # Loads from intent.yaml
secrets: inherit
Benefits of Intent.yaml:
- โ Centralized configuration - single source of truth
- โ Shared defaults across packages
- โ Per-package overrides for flexibility
- โ Validated by JSON schema
- โ No workflow duplication
Example 3: Independent Package Releases (Direct Parameters)โ
name: Release Package
on:
push:
tags:
- 'core/v*.*.*'
- 'utils/v*.*.*'
jobs:
# Parse tag to determine package
parse-tag:
runs-on: ubuntu-latest
outputs:
package: ${{ steps.parse.outputs.package }}
version: ${{ steps.parse.outputs.version }}
steps:
- name: Parse tag
id: parse
run: |
TAG=${GITHUB_REF#refs/tags/}
PACKAGE=$(echo $TAG | cut -d'/' -f1)
VERSION=$(echo $TAG | cut -d'/' -f2 | sed 's/^v//')
echo "package=$PACKAGE" >> $GITHUB_OUTPUT
echo "version=$VERSION" >> $GITHUB_OUTPUT
# Build and release
release:
needs: parse-tag
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_build_git-tag_and_create_github-release.yaml@master
with:
project_type: python-package
project_name: ${{ needs.parse-tag.outputs.package }}
package_working_directory: ./packages/${{ needs.parse-tag.outputs.package }}
tag_prefix: ${{ needs.parse-tag.outputs.package }}/
secrets:
github_auth_token: ${{ secrets.GITHUB_TOKEN }}
Example 3: Docker Multi-Service Buildโ
name: Build Docker Images
on:
push:
branches: [main]
paths:
- 'services/**'
jobs:
build-services:
strategy:
matrix:
service: [api, worker, admin]
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_docker_operations.yaml@master
with:
operation: build
build_context: ./services/${{ matrix.service }}
dockerfile_path: Dockerfile
project_name: ${{ matrix.service }}
image-name: myorg/${{ matrix.service }}
version: ${{ github.sha }}
Artifact Namingโ
Single-Project (Backward Compatible)โ
coverage_unit-test_ubuntu-latest_3.13
unit-test_coverage_data_file
Monorepo (with project_name)โ
coverage_core_unit-test_ubuntu-latest_3.13
core_unit-test_coverage_data_file
This prevents naming collisions when multiple packages are tested simultaneously.
Git Tagging Strategyโ
Single-Projectโ
git tag v1.2.3
git push origin v1.2.3
Monorepoโ
# Tag individual packages
git tag core/v1.2.3
git tag utils/v2.0.0
git tag api/v1.5.0
git push origin --tags
Benefits:
- Clear package identification
- Independent versioning
- Automated release detection
- Better GitHub release organization
Best Practicesโ
1. Consistent Namingโ
Use the same project_name across all workflows for a package:
# โ
Good - consistent naming
test:
with:
project_name: core
build:
with:
project_name: core
release:
with:
project_name: core
2. Path-Based Triggersโ
Only run workflows when specific packages change:
on:
push:
paths:
- 'packages/core/**'
- '.github/workflows/ci-core.yaml'
3. Matrix Strategy for Multiple Packagesโ
Test all packages efficiently:
jobs:
test:
strategy:
matrix:
package: [core, utils, api]
uses: ./.github/workflows/rw_uv_run_test.yaml
with:
project_name: ${{ matrix.package }}
test_working_directory: ./packages/${{ matrix.package }}
test_type: unit-test
4. Independent Coverage Reportsโ
Configure separate coverage for each package:
jobs:
upload-coverage:
strategy:
matrix:
package: [core, utils]
uses: ./.github/workflows/rw_upload_test_cov_report.yaml
with:
project_name: ${{ matrix.package }}
upload-to-codecov: true
Migration Guideโ
Step 1: Update Workflow Structureโ
Add project_name and working directory parameters to existing workflows.
Before (Single-Project):
test:
uses: ./.github/workflows/rw_uv_run_test.yaml
with:
test_type: unit-test
After (Monorepo):
test-core:
uses: ./.github/workflows/rw_uv_run_test.yaml
with:
project_name: core
test_working_directory: ./packages/core
test_type: unit-test
Step 2: Update Artifact Dependenciesโ
Ensure artifact downloads use correct project names:
organize-coverage:
with:
project_name: core # Downloads coverage_core* artifacts
Step 3: Configure SonarQube (if used)โ
Set up project-specific SonarQube keys:
sonar:
with:
project_name: core
project_working_directory: ./packages/core
sonar_project_key: myorg_monorepo_core
Backward Compatibilityโ
All changes are optional with sensible defaults. Existing workflows continue to work without modifications:
# This still works - no changes needed!
test:
uses: ./.github/workflows/rw_uv_run_test.yaml
with:
test_type: unit-test
all_test_items_paths: '["./tests"]'
Advanced Documentationโ
For comprehensive guides and examples, see:
- Planning Document:
.ai/prompt/2026.4.4/monorepo-support-planning.md - Usage Guide:
.ai/prompt/2026.4.4/monorepo-usage-guide.md - Migration Guide:
.ai/prompt/2026.4.4/migration-guide-single-to-monorepo.md - Release & Docker Guide:
.ai/prompt/2026.4.4/phase-3-release-docker-guide.md - Implementation Summary:
.ai/prompt/2026.4.4/IMPLEMENTATION-COMPLETE.md
Troubleshootingโ
Issue: Artifacts Not Foundโ
Symptom: Workflow can't find coverage artifacts
Solution: Ensure project_name matches across test and coverage workflows
# Test workflow
with:
project_name: core # Must match
# Coverage workflow
with:
project_name: core # Must match
Issue: Wrong Working Directoryโ
Symptom: Dependencies not found during test/build
Solution: Verify working directory points to package location
with:
test_working_directory: ./packages/core # Correct path
Issue: Tag Conflictsโ
Symptom: Git tag already exists
Solution: Use package-specific tag prefixes
with:
tag_prefix: core/ # Creates core/v1.2.3
FAQโ
Q: Do I need to change my existing workflows?
A: No! All monorepo parameters are optional. Existing workflows work unchanged.
Q: Can I use both single-project and monorepo workflows?
A: Yes! You can gradually migrate or use different approaches per project.
Q: How do I handle shared dependencies?
A: Each package can have its own dependencies. For shared code, consider creating a shared package.
Q: What about coverage aggregation across packages?
A: Currently, each package has separate coverage. Use external tools for cross-package aggregation if needed.
Q: Can I release packages independently?
A: Yes! Use tag prefixes (core/v1.2.3) to trigger package-specific releases.