Skip to content

Add init workflow step to bootstrap projects like specify init#2838

Open
Copilot wants to merge 6 commits into
mainfrom
copilot/add-init-step-bootstrap-project
Open

Add init workflow step to bootstrap projects like specify init#2838
Copilot wants to merge 6 commits into
mainfrom
copilot/add-init-step-bootstrap-project

Conversation

Copilot AI commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Workflows had no way to scaffold a project; users had to run specify init manually before any workflow could drive the spec-driven process. This adds an init step type so a workflow can bootstrap (or merge into) a project itself.

Changes

  • New InitStep (type: init) in src/specify_cli/workflows/steps/init/ — runs the bundled specify init command in-process against context.project_root, capturing exit_code/stdout/stderr and returning FAILED on non-zero exit.
    • Config fields (all optional): project, here, integration, script, force, no_git, ignore_agent_tools, preset, branch_numbering; string fields resolve {{ }} expressions.
    • Integration falls back to the workflow-level default; defaults to --ignore-agent-tools since workflows run unattended.
    • validate() rejects script values other than sh/ps.
  • Registration — added to STEP_REGISTRY and the engine's valid-step-types fallback.
  • Docsworkflows/ARCHITECTURE.md and workflows/README.md updated (step table, module tree, new "Init Steps" section).
  • Tests — coverage for bootstrap, default-integration fallback, project-name subdirectory, invalid-integration failure, and validation.

Example

- id: bootstrap
  type: init
  here: true
  integration: copilot   # optional; defaults to workflow integration
  script: sh

Copilot AI requested review from Copilot and removed request for Copilot June 3, 2026 21:49
Copilot AI linked an issue Jun 3, 2026 that may be closed by this pull request
Copilot AI requested review from Copilot and removed request for Copilot June 3, 2026 21:56
Copilot AI changed the title [WIP] Add InitStep for bootstrapping project workflow Add init workflow step to bootstrap projects like specify init Jun 3, 2026
Copilot finished work on behalf of mnriem June 3, 2026 21:58
Copilot AI requested a review from mnriem June 3, 2026 21:58
@mnriem mnriem requested a review from Copilot June 3, 2026 22:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new workflow step type (type: init) so workflows can bootstrap (or merge into) a Spec Kit project by invoking the bundled specify init logic in-process, enabling end-to-end “scaffold → run steps” workflows without requiring a manual pre-step.

Changes:

  • Introduces InitStep (src/specify_cli/workflows/steps/init/) that builds specify init argv from step config, runs it via CliRunner, and captures exit_code/stdout/stderr.
  • Registers the new step type in the workflow step registry and engine’s valid-step-type fallback, and updates architecture/README docs.
  • Adds tests covering argv building, workflow-default integration fallback, directory creation via project, invalid integration failure, and validation.
Show a summary per file
File Description
workflows/README.md Documents the new init step type and provides a YAML example.
workflows/ARCHITECTURE.md Updates step-type counts/table and module tree to include init.
tests/test_workflows.py Adds test coverage for the new InitStep.
src/specify_cli/workflows/steps/init/init.py Implements InitStep execution, expression resolution, and validation.
src/specify_cli/workflows/engine.py Adds init to the engine’s valid step-type fallback set.
src/specify_cli/workflows/init.py Registers InitStep in the built-in STEP_REGISTRY.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 6/6 changed files
  • Comments generated: 3

Comment thread workflows/README.md Outdated
Comment thread src/specify_cli/workflows/steps/init/__init__.py
Comment thread src/specify_cli/workflows/steps/init/__init__.py

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 1

Comment thread src/specify_cli/workflows/steps/init/__init__.py

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 3

Comment on lines +101 to +105
base = context.project_root or os.getcwd()
try:
not_empty = any(os.scandir(base))
except OSError:
not_empty = False

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit — replaced any(os.scandir(base)) with a with os.scandir(base) as it: context manager so the iterator is always closed even when any() short-circuits.

Comment on lines +202 to +205
try:
result = runner.invoke(app, argv, catch_exceptions=True)
finally:
os.chdir(prev_cwd)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — wrapped os.chdir(prev_cwd) in the finally block with try/except OSError: pass so a stale working directory can't bypass returning the captured StepResult.

Comment on lines +223 to +228
script = config.get("script")
if (
isinstance(script, str)
and "{{" not in script
and script not in VALID_SCRIPT_TYPES
):

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — validate() now checks not isinstance(script, str) first (before the string-value check), so non-string values like script: true are rejected immediately with a clear error message.

finally:
try:
os.chdir(prev_cwd)
except OSError:
@mnriem mnriem marked this pull request as ready for review June 8, 2026 19:53
Copilot AI review requested due to automatic review settings June 8, 2026 19:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 2

Comment on lines +72 to +74
integration = config.get("integration") or context.default_integration
integration = self._resolve(integration, context)

Comment on lines +225 to +242
def validate(self, config: dict[str, Any]) -> list[str]:
errors = super().validate(config)
script = config.get("script")
if script is not None and not isinstance(script, str):
errors.append(
f"Init step {config.get('id', '?')!r}: 'script' must be a string "
f"({' or '.join(repr(s) for s in VALID_SCRIPT_TYPES)})."
)
elif (
isinstance(script, str)
and "{{" not in script
and script not in VALID_SCRIPT_TYPES
):
errors.append(
f"Init step {config.get('id', '?')!r}: 'script' must be "
f"{' or '.join(repr(s) for s in VALID_SCRIPT_TYPES)}."
)
return errors
Copilot AI added 6 commits June 8, 2026 15:05
- Use `with os.scandir(...)` context manager so the iterator is always
  closed even when `any()` short-circuits, preventing file-descriptor
  leaks in long-running workflow runs.
- Guard `os.chdir(prev_cwd)` in the `finally` block with a try/except
  so an `OSError` (e.g. directory deleted) doesn't bypass returning
  the captured `StepResult`.
- Reject non-string `script` values in `validate()` with a clear error
  message, rather than silently passing them through to become
  `--script True` at runtime.
@mnriem mnriem force-pushed the copilot/add-init-step-bootstrap-project branch from 1746289 to fc8d6c3 Compare June 8, 2026 20:07
@mnriem mnriem requested a review from Copilot June 8, 2026 20:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 0 new

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a InitStep so we can use a workflow to bootstrap a project

3 participants