6.1 KiB
6.1 KiB
Task 017: Git Publishing Dry Run And Commit
Development description: Implement the Git-backed publishing path that builds a content bundle, runs best-effort generic Markdown/MDX dry-run validation, executes Admin-defined transforms on the runner host, and commits directly to the configured production branch.
Implementation Details
- Backend endpoints:
POST /api/articles/{article_id}/publishing/dry-runPOST /api/articles/{article_id}/publishing/create-commitGET /api/articles/{article_id}/publishing/statusGET /api/articles/{article_id}/publishing/commits
- Content bundle includes:
- Markdown/MDX article file.
- Frontmatter JSON/YAML according to site mapping.
- Referenced approved asset files.
- Bundle manifest.
- Publishing behavior:
- Materialize active versioned YAML/script config into checked-out site repo workspace.
- Run transform script directly on runner host inside site repo workspace.
- Run generic Markdown/MDX dry-run preview validation, not target-site build.
- Commit directly to configured production branch.
- Rely on target repo CI/CD after push.
- Primary done state is
PUBLISH_COMMIT_CREATED.
- Failure behavior:
- Non-fast-forward push or conflict fails publish step.
- No automatic rebase.
- If delayed deployment verification fails, alert Admin/Editor and leave production commit in place.
Public Interface
- Editor runs publishing dry run after final approval.
- Editor creates publish commit after dry run passes.
- UI shows commit SHA, branch, repository, and opportunistic deployment status.
Acceptance Criteria
- TDD pre-requirement: before implementation, write one failing integration test against a temporary local Git repository proving a final-approved article can create a commit; add dry-run and failure tests one behavior at a time and record evidence in
Result. - Publishing cannot dry-run before final approval.
- Dry run fails if generic Markdown/MDX content-shape validation fails.
- Publish commit cannot run until dry run passes.
- Content bundle uses site-configured path templates and frontmatter mapping.
- Active YAML/script config version is included in publish logs/manifest.
- Publish writes commit to configured production branch in a test repository.
- Non-fast-forward push or conflict fails without automatic rebase.
- Publish commit record stores repository URL, branch, commit SHA, bundle manifest, and status.
- UI clearly labels validation as best-effort content-shape validation only.
Verification
- Run publishing integration tests using a local bare Git repository.
- Run generic preview validation tests.
- Run Docker Compose smoke flow from final approval to publish commit against a demo site repo.
Result
-
Status: Done (TDD RED -> GREEN completed).
-
TDD progression:
- Restored and expanded
apps/backend/tests/integration/test_publishing_git_flow_public_api.pyfrom RED baseline. - Added incremental behavior coverage:
- dry-run blocked before final approval,
- dry-run content-shape validation failure path,
- create-commit blocked without successful dry-run,
- successful publish commit into local bare repo
main, - non-fast-forward conflict fail without auto rebase,
- publishing status/commits metadata assertions.
- Implemented publishing backend flow:
- endpoints:
POST /api/articles/{article_id}/publishing/dry-runPOST /api/articles/{article_id}/publishing/create-commitGET /api/articles/{article_id}/publishing/statusGET /api/articles/{article_id}/publishing/commits
- gates:
- dry-run only after final approval,
- create-commit only after successful dry-run.
- content-shape checks:
- non-empty markdown,
- at least one markdown heading,
- balanced fenced code blocks.
- bundle/manifest:
- site-configured
content_path_templateandasset_path_template, - frontmatter mapping usage,
- active script config version id/hash metadata,
- repository/branch/base head/commit sha metadata.
- site-configured
- git publish:
- direct commit+push to configured production branch,
- non-fast-forward detection and fail path without rebase.
- endpoints:
- Added frontend detail-model mapping for validation label and surfaced label in article detail UI.
- Regenerated shared OpenAPI contracts.
- Restored and expanded
-
Green evidence:
- Integration suite passes with all required publishing behaviors in one flow-oriented file:
apps/backend/tests/integration/test_publishing_git_flow_public_api.py(6 tests, all green). - Commit object is present in bare repo (
git cat-file -e <sha>^{commit}in test). - Manifest metadata includes
config_versionandgitblocks and best-effort validation label.
- Integration suite passes with all required publishing behaviors in one flow-oriented file:
-
Refactor notes:
- Added dedicated
PublishCommitsRepositorywith list/latest helpers and status filtering. - Added
articles.update_publishing_status(...)for explicit workflow/publishing-state sync. - Kept implementation scoped to task 017 API/domain/repository/frontend model changes; no unrelated workflow rewrites.
- Added dedicated
-
Verification output:
PYTHONPATH=/private/tmp/pupline-backend-deps python3 -m unittest apps/backend/tests/integration/test_publishing_git_flow_public_api.py->Ran 6 tests ... OKPYTHONPATH=/private/tmp/pupline-backend-deps python3 -m unittest apps/backend/tests/integration/test_final_approval_gate_public_api.py->Ran 7 tests ... OKPYTHONPATH=/private/tmp/pupline-backend-deps python3 -m unittest apps/backend/tests/integration/test_draft_assembly_public_api.py->Ran 5 tests ... OKPYTHONPATH=/private/tmp/pupline-backend-deps python3 -m unittest apps/backend/tests/integration/test_assets_media_library_public_api.py->Ran 7 tests ... OKPYTHONPATH=/private/tmp/pupline-backend-deps python3 scripts/generate_openapi_contracts.py-> wrote:packages/shared/openapi.jsonpackages/shared/src/api-types.ts
node apps/frontend/tests/article_detail.model.test.mjs->OK(exit 0)pnpm --dir apps/frontend typecheck->tsc --noEmitcompleted successfully (exit 0)