Files
content-factory/tasks/017-git-publishing-dry-run-and-commit.md
T

111 lines
6.1 KiB
Markdown

# 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-run`
- `POST /api/articles/{article_id}/publishing/create-commit`
- `GET /api/articles/{article_id}/publishing/status`
- `GET /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
- [x] 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`.
- [x] Publishing cannot dry-run before final approval.
- [x] Dry run fails if generic Markdown/MDX content-shape validation fails.
- [x] Publish commit cannot run until dry run passes.
- [x] Content bundle uses site-configured path templates and frontmatter mapping.
- [x] Active YAML/script config version is included in publish logs/manifest.
- [x] Publish writes commit to configured production branch in a test repository.
- [x] Non-fast-forward push or conflict fails without automatic rebase.
- [x] Publish commit record stores repository URL, branch, commit SHA, bundle manifest, and status.
- [x] 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:
1. Restored and expanded `apps/backend/tests/integration/test_publishing_git_flow_public_api.py` from RED baseline.
2. 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.
3. Implemented publishing backend flow:
- endpoints:
- `POST /api/articles/{article_id}/publishing/dry-run`
- `POST /api/articles/{article_id}/publishing/create-commit`
- `GET /api/articles/{article_id}/publishing/status`
- `GET /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_template` and `asset_path_template`,
- frontmatter mapping usage,
- active script config version id/hash metadata,
- repository/branch/base head/commit sha metadata.
- git publish:
- direct commit+push to configured production branch,
- non-fast-forward detection and fail path without rebase.
4. Added frontend detail-model mapping for validation label and surfaced label in article detail UI.
5. Regenerated shared OpenAPI contracts.
- 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_version` and `git` blocks and best-effort validation label.
- Refactor notes:
- Added dedicated `PublishCommitsRepository` with 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.
- 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 ... OK`
- `PYTHONPATH=/private/tmp/pupline-backend-deps python3 -m unittest apps/backend/tests/integration/test_final_approval_gate_public_api.py` -> `Ran 7 tests ... OK`
- `PYTHONPATH=/private/tmp/pupline-backend-deps python3 -m unittest apps/backend/tests/integration/test_draft_assembly_public_api.py` -> `Ran 5 tests ... OK`
- `PYTHONPATH=/private/tmp/pupline-backend-deps python3 -m unittest apps/backend/tests/integration/test_assets_media_library_public_api.py` -> `Ran 7 tests ... OK`
- `PYTHONPATH=/private/tmp/pupline-backend-deps python3 scripts/generate_openapi_contracts.py` -> wrote:
- `packages/shared/openapi.json`
- `packages/shared/src/api-types.ts`
- `node apps/frontend/tests/article_detail.model.test.mjs` -> `OK` (exit 0)
- `pnpm --dir apps/frontend typecheck` -> `tsc --noEmit` completed successfully (exit 0)