Workflows
Generate GitHub Actions workflow files under .github/workflows/ from the "workflows" array in nova.config.json.
The generator reads each entry, validates triggers and targets, substitutes variables from the template metadata, validates the output YAML, and writes the result to disk.
Why Use This Command?
- Bootstraps a full set of CI/CD workflows without writing YAML by hand.
- Publishes one project to multiple destinations (npm, GitHub Packages, Docker, hosting) from a single build, instead of each destination running its own pipeline from scratch.
- Serializes dependent publishes (e.g., preset waits for its core dependency to be on the registry) via
needson publish targets. - Keeps workflow definitions consistent across Nova-managed repositories.
Requirements
- Node.js runtime — Use any Node.js LTS release.
- Project root — Run the command from the directory containing the top-level
package.json. - Configured workflows — The
"workflows"array must exist innova.config.json. Usenova utility initializeto configure it interactively.
Usage
Options
| Flag | Description |
|---|---|
-d, --dry-run | Preview the target file path without writing anything to disk. |
-r, --replace-file | Overwrite the existing file instead of creating a .nova-backup copy. |
Config-Driven Workflow Entries
Each entry in the "workflows" array maps to one output file. An entry contains:
| Field | Required | Description |
|---|---|---|
template | Yes | The name of a bundled workflow template (see Available Templates). |
suffix | Yes | A label appended to the output filename and workflow name. Must be unique within the same template. |
triggers | Yes | An array of trigger names (see Available Triggers). Use an empty array to omit triggers. |
depends-on | No | An array of workflow references in {template}-{suffix} format. Required when using workflow-run-* triggers. |
scopes | No | An array of workspace paths (keys from workspaces) to include in the check / build step filter. |
targets | No | An array of publish destinations for the publish template. See Target Fields. |
settings | No | Key-value pairs that remap secret / variable names or supply values for literal template variables. |
Target Fields
Each entry in the targets array pins one publish destination to a workspace.
| Field | Required | Description |
|---|---|---|
type | Yes | One of the 8 target types (see Available Target Types). |
workingDir | Yes | Path to the workspace that owns the target (e.g., "./packages/nova"). |
needs | No | Working directories of other same-type targets that must finish publishing before this one starts. |
Config Examples
Publish a single package to npm:
{
"template": "publish",
"suffix": "project",
"triggers": ["release"],
"scopes": ["./packages/core"],
"targets": [
{
"type": "npm",
"workingDir": "./packages/core"
}
],
"settings": {
"NPM_TOKEN": "NPM_TOKEN",
"ROOT_WORKING_DIR": "./"
}
}
Serialize dependent publishes with needs:
{
"template": "publish",
"suffix": "project",
"triggers": ["release"],
"scopes": [
"./packages/core",
"./packages/preset"
],
"targets": [
{
"type": "npm",
"workingDir": "./packages/core"
},
{
"type": "npm",
"workingDir": "./packages/preset",
"needs": ["./packages/core"]
}
],
"settings": {
"NPM_TOKEN": "NPM_TOKEN",
"ROOT_WORKING_DIR": "./"
}
}
The preset target waits for core to finish publishing before it starts, so consumers that pull [email protected] can always resolve its declared dependency on [email protected].
Publish to multiple destinations from one build:
{
"template": "publish",
"suffix": "project",
"triggers": ["release"],
"scopes": [
"./packages/sdk",
"./apps/docs"
],
"targets": [
{
"type": "npm",
"workingDir": "./packages/sdk"
},
{
"type": "github-packages",
"workingDir": "./packages/sdk"
},
{
"type": "cloudflare-pages-docusaurus",
"workingDir": "./apps/docs"
}
],
"settings": {
"CLOUDFLARE_ACCOUNT_ID": "CLOUDFLARE_ACCOUNT_ID",
"CLOUDFLARE_API_TOKEN": "CLOUDFLARE_API_TOKEN",
"CLOUDFLARE_PROJECT_NAME": "CLOUDFLARE_PROJECT_NAME",
"NPM_TOKEN": "NPM_TOKEN",
"ROOT_WORKING_DIR": "./"
}
}
Each target becomes its own publish job. Jobs run in parallel off a shared build job, except where needs declares an explicit ordering.
Available Templates
The generator currently bundles three templates, each with its own trigger set.
| Template | Description | Notes |
|---|---|---|
publish | Build once and publish to one or more targets | Requires targets. Each target declares its own secret / variable setup. |
lock-inactive-issues | Lock stale issues and pull requests | No manual setup needed (uses automatic GITHUB_TOKEN). Pick a cadence via triggers. |
check-sponsor-gated-issues | Gate issues by GitHub sponsor status | Requires PERSONAL_ACCESS_TOKEN secret plus several literal settings. |
Available Target Types
The publish template supports the following type values for each entry in targets. Each type has its own template under targets/ and declares its own secrets and variables.
| Type | Description |
|---|---|
npm | Publish a package to npm |
github-packages | Publish a package to GitHub Packages |
docker-hub | Publish a Docker image to Docker Hub |
ghcr | Publish a Docker image to GitHub Container Registry |
cloudflare-pages-docusaurus | Deploy a Docusaurus site to Cloudflare Pages |
github-pages-docusaurus | Deploy a Docusaurus site to GitHub Pages |
aws-amplify-nextjs | Deploy a Next.js app to AWS Amplify |
vercel-nextjs | Deploy a Next.js app to Vercel |
Available Triggers
Each template supports a specific set of triggers. The generator reads the available triggers from the template's triggers/ folder.
| Template | Triggers |
|---|---|
publish | release, workflow-run-success, workflow-run-failure, workflow-run-any |
lock-inactive-issues | schedule-daily, schedule-weekly, schedule-monthly |
check-sponsor-gated-issues | issues, issue-comment |
| Trigger | Requires depends-on |
|---|---|
release | No |
schedule-daily | No |
schedule-weekly | No |
schedule-monthly | No |
issues | No |
issue-comment | No |
workflow-run-success | Yes |
workflow-run-failure | Yes |
workflow-run-any | Yes |
All templates also include workflow_dispatch (manual trigger with dry-run option) automatically.
Variable Formats
Each template declares variables with one of three formats. The format determines how the value is substituted into the generated YAML:
| Format | Substitution behavior |
|---|---|
secret | Produces ${{ secrets.NAME }} in the output. If a setting is provided, the secret reference uses the setting value as the name instead. |
var | Produces ${{ vars.NAME }} in the output. If a setting is provided, the variable reference uses the setting value as the name instead. |
literal | Replaces the placeholder with the exact string from settings. All literal variables must have a corresponding setting or the entry is skipped. |
Output Filename Convention
Generated files are written to .github/workflows/ with the naming pattern:
nova-{template}-{suffix}.yml
Examples:
nova-lock-inactive-issues-project.ymlnova-publish-project.ymlnova-check-sponsor-gated-issues-project.yml
How It Works
Reading Config
The generator loads nova.config.json and reads the "workflows" array. If the array is missing or empty, the generator exits with no changes.
Validation
Before generating each file, the generator checks:
- The template name matches a known bundled template.
- The template directory and base file exist on disk.
- Each trigger in
triggershas a corresponding file in the template'striggers/folder. - When a trigger requires
depends-on, the config entry provides it and the referenced workflow exists. - Circular
depends-onreferences are detected and rejected. - Each target's
typehas a matching target template. - Each target's
workingDirexists as a workspace key. - Each entry in a target's
needsarray references a same-type target defined in the same workflow. - All
literal-format variables have a corresponding entry insettings. - No two entries produce the same output filename.
If any check fails, the entry is skipped with an error message.
File Generation
Each valid entry produces one YAML file under .github/workflows/. The generator composes the template's base.yml with the resolved triggers and targets, substitutes variable placeholders based on the template metadata and the entry's settings, and emits needs: ["build", ...] on each target job that declares dependencies.
If the target file already exists, a .nova-backup copy is created unless --replace-file is set.
Orphan Cleanup
After generation, the generator scans .github/workflows/ for existing nova-*.yml files that are not in the current config. These orphaned files are backed up (renamed with a .nova-backup timestamp) or deleted when --replace-file is set.
Setup Instructions
After all files are generated, the generator prints a summary of secrets and variables that need to be configured on GitHub. This covers every non-automatic secret and var format variable across all generated workflows.