diff --git a/packages/cli/src/manifest.ts b/packages/cli/src/manifest.ts index 8c6e7d9..8c1d52e 100644 --- a/packages/cli/src/manifest.ts +++ b/packages/cli/src/manifest.ts @@ -58,6 +58,14 @@ export interface PrecisaManifest { */ siteProjectName?: string; + /** + * Path prefix (relative to repo root, trailing slash) treated as site + * source for change detection in `_deploy-site.yml`. Defaults to + * `site/` — override to `packages/site/` for monorepos where the site + * lives under `packages/`. + */ + siteSourcePath?: string; + /** Public-OSS or private-internal. Controls which templates are rendered. */ visibility: 'oss' | 'private'; } @@ -134,6 +142,7 @@ export function tokenContext(manifest: PrecisaManifest): Record SECURITY_EMAIL: manifest.contactEmails.security, SITE_FILTER: manifest.siteFilter ?? '', SITE_PROJECT_NAME: manifest.siteProjectName ?? '', + SITE_SOURCE_PATH: manifest.siteSourcePath ?? 'site/', VISIBILITY: manifest.visibility, }; } @@ -197,6 +206,9 @@ export function validateManifest(raw: unknown): ManifestValidationError[] { if (m.siteFilter !== undefined && typeof m.siteFilter !== 'string') { errors.push({ message: 'must be a string', path: 'siteFilter' }); } + if (m.siteSourcePath !== undefined && typeof m.siteSourcePath !== 'string') { + errors.push({ message: 'must be a string', path: 'siteSourcePath' }); + } if (!m.contactEmails || typeof m.contactEmails !== 'object') { errors.push({ message: 'must be an object', path: 'contactEmails' }); } else { diff --git a/templates/github/workflows/_deploy-site.yml b/templates/github/workflows/_deploy-site.yml index 153a0cb..67a403a 100644 --- a/templates/github/workflows/_deploy-site.yml +++ b/templates/github/workflows/_deploy-site.yml @@ -19,6 +19,10 @@ on: description: 'Output directory to deploy (default: site/dist)' type: string default: 'site/dist' + site_source_path: + description: 'Path prefix treated as site source files for change detection (default: site/)' + type: string + default: 'site/' jobs: build-site: @@ -57,7 +61,8 @@ jobs: ); filenames = pages.flatMap(p => (p.files ?? []).map(f => f.filename)); } - const siteChanged = filenames.some(f => f.startsWith('site/')); + const sourcePath = `${{ inputs.site_source_path }}`; + const siteChanged = filenames.some(f => f.startsWith(sourcePath)); core.setOutput('site_changed', siteChanged ? 'true' : 'false'); - uses: actions/checkout@v6 diff --git a/templates/github/workflows/ci.yml b/templates/github/workflows/ci.yml index 7c15af1..90e3b25 100644 --- a/templates/github/workflows/ci.yml +++ b/templates/github/workflows/ci.yml @@ -82,5 +82,6 @@ jobs: with: project_name: '{{SITE_PROJECT_NAME}}' site_filter: '{{SITE_FILTER}}' + site_source_path: '{{SITE_SOURCE_PATH}}' secrets: inherit # {{/if}}