Skip to content

refactor: move workflow command handlers to workflows/_commands.py (PR-8/8)#3159

Open
darion-yaphet wants to merge 2 commits into
github:mainfrom
darion-yaphet:refactor/split-init-pr8
Open

refactor: move workflow command handlers to workflows/_commands.py (PR-8/8)#3159
darion-yaphet wants to merge 2 commits into
github:mainfrom
darion-yaphet:refactor/split-init-pr8

Conversation

@darion-yaphet

Copy link
Copy Markdown
Contributor

Summary

Final PR in the __init__.py split series (PR-8/8). Moves all workflow command handlers out of src/specify_cli/__init__.py into a dedicated src/specify_cli/workflows/_commands.py, registered back via register(app) to preserve the exact CLI surface.

With this, src/specify_cli/__init__.py drops from ~5914 lines (series start) to 642 lines.

Changes

  • Move: workflow / workflow catalog / workflow step Typer apps and all handlers (run, resume, status, list/show/add/remove for catalogs and steps) → workflows/_commands.py.
  • Shim: __init__.py now just imports register from workflows._commands and calls it — CLI behavior unchanged.
  • Rebased onto current main: ported the gate-outcome / structured-JSON and process-exit-code features main added to workflow run/resume after this branch's base (_workflow_run_payload gate block, _is_gate_step, _gate_outcome, _normalize_gate_options, _run_outcome_exit_code) into the new module.
  • Tests: updated 6 _gate_outcome imports to the new module path (specify_cli.workflows._commands), matching the convention used by other moved-helper tests.

Test plan

  • pytest tests/test_workflows.py — 308 passed
  • Syntax check on both modified modules
  • Verified the remaining full-suite failures (integrations/extensions/upgrade/bundler) are pre-existing on clean main (offline/network-dependent), not introduced here

Depends on / follows #3014 (PR-7), now merged.

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

Refactors the CLI by extracting all specify workflow * Typer apps and handlers from src/specify_cli/__init__.py into a dedicated src/specify_cli/workflows/_commands.py, re-attached via a register(app) shim to keep the CLI interface intact.

Changes:

  • Moved all workflow command groups/handlers (run/resume/status, catalogs, step catalogs) into workflows/_commands.py.
  • Updated src/specify_cli/__init__.py to register the workflow command group via workflows._commands.register(app).
  • Updated workflow tests to import moved private helpers (_gate_outcome, _stdout_to_stderr_when) from the new module path.
Show a summary per file
File Description
tests/test_workflows.py Updates imports to reference workflow helper functions in the new specify_cli.workflows._commands module.
src/specify_cli/workflows/_commands.py New module containing the extracted workflow Typer apps, handlers, and helper functions plus register(app).
src/specify_cli/__init__.py Removes inlined workflow command handlers and registers the workflow command group via the new module.

Copilot's findings

Tip

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

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

Comment on lines +871 to +874
def workflow_catalog_add(
url: str = typer.Argument(..., help="Catalog URL to add"),
name: str = typer.Option(None, "--name", help="Catalog name"),
):
Comment on lines +1523 to +1526
def workflow_step_catalog_add(
url: str = typer.Argument(..., help="Catalog URL to add"),
name: str = typer.Option(None, "--name", help="Catalog name"),
):

@mnriem mnriem left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please address Copilot feedback

@darion-yaphet darion-yaphet force-pushed the refactor/split-init-pr8 branch 2 times, most recently from a900a0a to ed73f34 Compare June 25, 2026 13:21
@mnriem mnriem requested a review from Copilot June 25, 2026 13:23

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: 3/3 changed files
  • Comments generated: 1

Comment on lines +480 to +483
project_root = _require_specify_project()
registry = WorkflowRegistry(project_root)
workflows_dir = project_root / ".specify" / "workflows"

@mnriem

mnriem commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

Please address Copilot feedback

@darion-yaphet darion-yaphet force-pushed the refactor/split-init-pr8 branch 2 times, most recently from 86ff4db to 938a389 Compare June 25, 2026 13:39
@mnriem mnriem requested a review from Copilot June 25, 2026 13:46

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: 4/4 changed files
  • Comments generated: 2

Comment thread src/specify_cli/workflows/_commands.py Outdated
Comment on lines +52 to +54
def _require_specify_project(*args, **kwargs):
from .. import _require_specify_project as _f
return _f(*args, **kwargs)
Comment on lines +244 to +246
project_root = Path.cwd()
_reject_unsafe_dir(project_root / ".specify", ".specify")
else:
@mnriem

mnriem commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

Please address Copilot feedback

…R-8/8)

Final PR of the __init__.py split. Moves the workflow command group out of
__init__.py into the existing workflows/ package, completing the domain-dir
layout established in PR-5 (integrations), PR-6 (presets) and PR-7
(extensions).

- New workflows/_commands.py holds the four Typer apps (workflow / catalog /
  step / step-catalog), all 25 command handlers, the six workflow-only
  helpers (_parse_input_values, _workflow_run_payload, _emit_workflow_json,
  _stdout_to_stderr_when, _validate_step_id_or_exit,
  _resolve_steps_base_dir_or_exit), and a register(app) entry point.
- workflows is already a package, so no rename is needed; intra-package
  imports change from `.workflows.x` to `.x`. The only root-helper dep
  (_require_specify_project) is reached through a call-time shim so test
  monkeypatching of specify_cli._require_specify_project keeps working.
- __init__.py drops ~1445 lines (2066 -> 621); the workflow group is
  re-attached via register(app). Dead `contextlib` import removed.
- tests/test_workflows.py: import the now-relocated _stdout_to_stderr_when
  helper from its new home (workflows._commands) instead of the package root.

No behavior change. Full suite green (3847 passed), ruff clean.
Workflow commands persist run state under .specify/workflows/runs, so the command-local project shim now rejects symlinked workflow storage before any workflow command proceeds. The standalone YAML path uses the same guard because it intentionally bypasses the normal project requirement while still creating workflow state under the current directory.

Constraint: Local YAML workflow runs do not require an existing .specify project directory but still create .specify/workflows/runs state

Rejected: Guard only .specify in the file-source path | .specify/workflows and runs can independently redirect writes

Confidence: high

Scope-risk: narrow

Directive: Keep workflow storage symlink checks centralized before constructing WorkflowEngine

Tested: .venv/bin/python -m pytest tests/test_workflow_run_without_project.py tests/test_workflows.py::TestWorkflowAddSymlinkGuard -v

Tested: .venv/bin/python -m py_compile src/specify_cli/workflows/_commands.py tests/test_workflow_run_without_project.py tests/test_workflows.py

Not-tested: Ruff lint; ruff is not installed in the repo virtualenv

Assisted-by: OpenAI Codex (model: GPT-5, autonomous)

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: 4/4 changed files
  • Comments generated: 2

Comment on lines +562 to +565
from specify_cli._github_http import resolve_github_release_asset_api_url as _resolve_gh_asset

_wf_url_extra_headers = None
_resolved_wf_url = _resolve_gh_asset(source, _open_url, timeout=30)
Comment on lines +668 to +672
from specify_cli.authentication.http import open_url as _open_url
from specify_cli._github_http import resolve_github_release_asset_api_url as _resolve_gh_asset

_wf_cat_extra_headers = None
_resolved_workflow_url = _resolve_gh_asset(workflow_url, _open_url, timeout=30)
@mnriem

mnriem commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

Please address Copilot feedback

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.

3 participants