feat: Woodpecker CI pipeline + Forgejo PyPI publishing #6
No reviewers
Labels
No labels
domain:backend
domain:devops
domain:frontend
status:approved
status:in-progress
status:needs-fix
status:qa
type:bug
type:devops
type:feature
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
ldraney/woodpecker-sdk!6
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "5-forgejo-pypi-registry-woodpecker-ci-pipe"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Changes
.woodpecker.yml: New 3-step CI pipeline (lint, test, publish to Forgejo PyPI)pyproject.toml: Added[tool.ruff]section (Python 3.10+, line-length 120, E/F/W/I rules)src/woodpecker_sdk/client.py: Broke long method signatures across multiple lines (E501)src/woodpecker_sdk/{cron_jobs,organizations,pipelines,repo_registries,repo_secrets,repositories,secrets,users}.py: Ruff format fixes (line wrapping, dict formatting)tests/test_{agents,debug,organizations,pipeline_queues,pipelines,repositories,system}.py: Import sorting (I001), unused import removal (F401), format fixesTest Plan
twine uploadto Forgejo succeeded,pip install --extra-index-urlresolves correctlyReview Checklist
Related Notes
issue-woodpecker-sdk-pypi-pipeline-- the issue this PR addressesplan-2026-02-28-woodpecker-sdk-mcp-- Phase 2: Forgejo PyPI registry + Woodpecker CI pipelineReview-fix round 1:
Pipeline #1 and #2 errored due to deprecated
secretsshorthand syntax. Woodpecker now requiresenvironmentwithfrom_secretinstead.Changes in commit
ccad6eb:secrets: [woodpecker_url, woodpecker_token]with explicitenvironment/from_secretmappingssecrets: [forgejo_publish_user, forgejo_publish_token]with explicitenvironment/from_secretmappingswhenevent filter to suppress "bad_habit" linter warnings$$escaping for secret env vars in the twine upload command per Woodpecker docsReview-fix round 2:
Pipeline #3 showed 65 passed, 1 failed, 4 skipped. The single failure was
test_get_user_feed-- a pre-existing test bug wherebranchandrefwere marked as required Feed fields, but the Woodpecker API omits them from certain event types (e.g. pull_request).Changes in commit
b5203f0:branchandreffromFEED_REQUIRED_FIELDStoFEED_OPTIONAL_FIELDSintests/test_user.pyPR #6 Review
Reviewer: QA Agent (fresh context)
Branch:
5-forgejo-pypi-registry-woodpecker-ci-pipe->mainPlan:
plan-2026-02-28-woodpecker-sdk-mcp-- Phase 2BLOCKERS
None.
NITS
Pip install overhead per step. Each step (
lint,test,build,publish) runspip installfrom scratch since they use separate containers. This is functionally correct (Woodpecker shares workspace, not the Python environment), but future optimization could use a custom image with pre-installed tools or pip caching to speed up CI runs. Non-blocking -- the current approach is clear and simple.Hardcoded Forgejo URL in pipeline. The twine upload command contains the literal URL
https://forgejo.tail5b443a.ts.net/api/packages/forgejo_admin/pypi. If the Forgejo instance URL ever changes, this must be updated manually. Consider extracting to a secret (e.g.,forgejo_publish_url) for future reusability across repos. Non-blocking -- the plan explicitly notes this is the first pipeline and will become a template.No
--non-interactiveflag on twine. If twine ever prompts for input (e.g., package already exists at that version), the CI step would hang. Adding--non-interactiveor--skip-existingwould make the publish step more resilient. Non-blocking -- manual version bumping is the current decision per the plan.SOP COMPLIANCE
5-forgejo-pypi-registry-woodpecker-ci-pipereferences Forgejo issue #5.template-pr-body-- All required sections present: Summary, Changes, Test Plan, Review Checklist, Related Notes.plan-2026-02-28-woodpecker-sdk-mcp(Phase 2) andissue-woodpecker-sdk-pypi-pipeline.branch/refmoved to optional) is a legitimate correctness fix.from_secretinjection. No.env,.pypirc, or credential files in repo..gitignoreis clean.branch/refFeed schema fix is directly related (discovered during CI test runs).feat:for the pipeline,fix:for thefrom_secretsyntax correction,fix:for the Feed schema field move. Each describes what changed and why.CODE QUALITY
.woodpecker.yml: Correct Woodpecker v2 syntax.from_secretused properly for secret injection.$$escaping for shell-time variable expansion is correct.whenconditions properly gatebuildandpublishtopushonmainonly. Lint and test run on all events (push + PR).pyproject.tomlruff config: Matches the plan decision (colocated in pyproject.toml, no standalone ruff.toml). Rule selection["E", "F", "W", "I"]is appropriate (pycodestyle errors/warnings, pyflakes, import sorting).target-version = "py310"matchesrequires-python = ">=3.10".pytestimport removal in files that don't usepytest.markorpytest.skip. Thetest_user.pyFeed schema change movingbranchandreffrom required to optional is a correctness fix (the Woodpecker API can return Feed entries without these fields).SECURITY
forgejo.tail5b443a.ts.net) is on Tailnet -- not publicly accessible. Acceptable in pipeline config.from_secretis the correct mechanism for Woodpecker secret injection.VERDICT: APPROVED
The PR cleanly implements Phase 2 of the plan: a 4-step Woodpecker CI pipeline (lint, test, build, publish) and ruff linting configuration. All changes are in scope, secrets are handled properly, the PR body follows the template, and commit messages are descriptive. The nits are non-blocking optimization suggestions for future iterations.
Nit fixes applied (Phase 2)
Three nits addressed in commit
c78bd38:1. Hardcoded Forgejo URL extracted to secret
The publish step previously had
https://forgejo.tail5b443a.ts.net/api/packages/forgejo_admin/pypihardcoded in the twine command. This has been replaced with aFORGEJO_PYPI_URLenvironment variable sourced from the new global secretforgejo_pypi_url(already created in Woodpecker). The pipeline is now portable across Forgejo instances.2. Added
--non-interactiveflag to twineThe
twine uploadcommand now includes--non-interactiveto prevent twine from ever hanging on input prompts in CI.3. Merged build and publish into a single step
The separate
buildandpublishsteps have been combined into onepublishstep. Since publish depends on thedist/artifacts from build, merging them avoids a redundantpip installand keeps the artifacts in the same workspace. Lint and test remain as separate steps.PR #6 Review (Round 2)
BLOCKERS
None.
NITS
PR body says "4-step CI pipeline" but
.woodpecker.ymlhas 3 steps. The Summary and Changes sections both reference "4-step CI pipeline (lint, test, build, publish)" but the implementation correctly merged build+publish into a singlepublishstep. The PR body text should say "3-step" to match reality. Non-blocking -- the implementation is the correct choice.Ruff version not pinned in CI. The lint step runs
pip install ruffwithout a version pin. A future ruff release could introduce new rules or change formatting behavior, causing CI to fail on code that hasn't changed. Considerpip install ruff==0.9.x(or whatever current version is). This is standard CI hygiene but non-blocking for initial merge.twine uploadwill fail on re-publish of same version. If the publish step runs on a main push but the version inpyproject.tomlhasn't been bumped,twine uploadwill fail because Forgejo's PyPI registry rejects duplicate versions. The plan acknowledges "manual version bumping (for now)" but there's no guard in the pipeline (e.g.,twine upload --skip-existingor a version-check step). This is acceptable for v1 since the team knows to bump versions, but worth noting. Non-blocking.SOP COMPLIANCE
5-forgejo-pypi-registry-woodpecker-ci-pipe-- starts with issue number5, follows convention.template-pr-body: All five required sections present (Summary, Changes, Test Plan, Review Checklist, Related Notes).plan-2026-02-28-woodpecker-sdk-mcpandissue-woodpecker-sdk-pypi-pipelineboth present.branch/refmoved to optional) is a correctness fix validated against the live API.from_secretdirectives. No.env,.pypirc, or credential files in the repo.$$escaping used correctly in twine command to prevent Woodpecker from logging secrets.feat:,fix:) describing exactly what changed.CODE QUALITY NOTES
whenevent filter at top level plus the per-stepwhenon publish correctly gates publishing to main-only pushes. Secrets are properly injected viaenvironment+from_secret.py310target matchesrequires-python = ">=3.10". Rule selection (E,F,W,I) covers pycodestyle errors/warnings, pyflakes, and isort -- good baseline without being overly aggressive.pytestremoved from files that don't use it directly since it's picked up via conftest), and string concatenation flattening.branchandreffrom required to optional intests/test_user.pymatches the Woodpecker API's actual behavior where these fields can be absent.VERDICT: APPROVED
Clean implementation of Phase 2. The pipeline follows the plan's spec (with the reasonable optimization of merging build+publish). No secrets exposed, no scope creep, SOP compliance is complete. The three nits are all non-blocking suggestions for future improvement.
Nit fixes applied (review round 2):
PR body: "4-step" -> "3-step" -- The build step was merged into the publish step in commit
c78bd38, but the PR body still referenced a "4-step CI pipeline". Updated the PR body to accurately say "3-step" and removed the separate "build" mention from the Changes and Test Plan sections.Pin ruff version in CI -- Changed
pip install rufftopip install ruff==0.15.2in.woodpecker.ymlto avoid non-deterministic lint failures from unpinned dependency. Version matches what is currently installed locally.PR #6 Review (Round 3)
BLOCKERS
None.
NITS
Ruff version pin could be fresher (non-blocking):
.woodpecker.ymlpinsruff==0.15.2(released 2026-02-19). The latest is 0.15.4 (released 2026-02-26). Not a blocker since 0.15.2 is valid and stable, but worth updating when convenient.$$env-var syntax in twine command: Line 28 of.woodpecker.ymluses$$FORGEJO_PYPI_URL,$$FORGEJO_PUBLISH_USER,$$FORGEJO_PUBLISH_TOKEN. The$$prefix is the correct Woodpecker syntax for referencing environment variables defined viafrom_secretin the same step'senvironmentblock -- this is correct. Just noting for future readers that$$prevents Woodpecker from interpreting$as a pipeline substitution variable.Publish step re-installs build + twine on every main push: A minor CI runtime cost. Could be optimized with a custom image later, but perfectly fine for the initial pipeline pattern.
SOP COMPLIANCE
5-forgejo-pypi-registry-woodpecker-ci-pipe-- follows{issue-num}-{slug}convention.template-pr-body: All five required sections present: Summary, Changes, Test Plan, Review Checklist, Related Notes.plan-2026-02-28-woodpecker-sdk-mcpandissue-woodpecker-sdk-pypi-pipeline..envfiles, credentials, or tokens found in the diff. All sensitive values usefrom_secretin the pipeline..gitignoreexcludes common sensitive patterns.feat:,fix:) with clear descriptions:feat: add Woodpecker CI pipeline and ruff lintingfix: use from_secret syntax and add event filters in pipelinefix: move branch and ref to optional fields in Feed schemafix: harden CI publish step -- extract URL secret, add non-interactive flag, merge build+publishfix: pin ruff==0.15.2 in CI lint stepCODE REVIEW
.woodpecker.yml(new file, 38 lines):whenblock at top correctly triggers onpushandpull_requestevents.event: push, branch: mainonly.environment+from_secret-- correct Woodpecker syntax.--non-interactiveflag on twine prevents hangs in CI -- good practice.pyproject.tomlchanges:target-version = "py310"matchesrequires-python = ">=3.10"-- consistent.["E", "F", "W", "I"]covers pycodestyle errors, pyflakes, pycodestyle warnings, and isort -- reasonable baseline.Source file changes (8 files):
Test file changes (7 files):
pytestremoved fromtest_organizations.py,test_repositories.py).test_user.py:branchandrefmoved from required to optional Feed fields -- this is a bug fix for a schema mismatch against the actual API, not a formatting change. Correctly addressed.No security concerns: No hardcoded secrets, no credential files, no suspicious patterns.
VERDICT: APPROVED
Clean PR. The pipeline matches the Phase 2 specification from
plan-2026-02-28-woodpecker-sdk-mcp. All SOP compliance checks pass. Code changes are well-scoped -- a new CI pipeline file, colocated ruff config, and the mechanical formatting fixes that follow from introducing the linter. The Feed schema fix (branch/refto optional) is a legitimate correctness improvement discovered during this work. No blockers.