feat: add Woodpecker CI pipeline, Dockerfile, and k8s manifests #2
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/linkedin-scheduler-remote!2
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "1-add-woodpecker-ci-pipeline-dockerfile-an"
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
Dockerfile: Multi-stage build (python:3.12-slim), PIP_INDEX_URL build arg for Forgejo PyPI, BUILD_SHA label, port 8000,python server.pyentrypoint.woodpecker.yml: Lint step (ruff==0.15.2 check + format), build-and-push step (Kaniko to Harborlinkedin-scheduler-remote/server), ArgoCD path exclusionk8s/deployment.yaml: Deployment (harbor image, imagePullSecrets harbor-creds, env from linkedin-mcp-secrets, PVC at /app/data, resource limits, health probes), Service (port 8000), PVC (100Mi local-path).dockerignore: Exclude .env, .venv, .git, k8s, systemd, build artifactspyproject.toml: Add[tool.ruff]config (py312, line-length 120, E/F/I/W rules), add[project.optional-dependencies]dev groupserver.py: Addruff: noqa: I001directive for intentional import ordering (monkey-patch pattern)client_patch.py: Ruff format fixes (line length normalization)Test Plan
ruff check .passesruff format --check .passesReview Checklist
Related Notes
plan-2026-02-25-mcp-gateway-migration-- Phase 3+4 implementationReview-fix round 1:
Self-review found the
.woodpecker.ymlwas missing thepip install .[dev]andpython -m pytest tests/ || truecommands from the task spec. The lint-only step has been renamed totestand expanded to include dev dependency installation and a soft-fail pytest invocation, matching the standard pattern.Pushed fix in commit
3237ef5.PR #2 Review
BLOCKERS
B1.
${CI_COMMIT_SHA}uses curly braces in.woodpecker.yml(2 occurrences)Per
deployment-lessonsSOP: "Use$CI_COMMIT_SHA(without curly braces) in plugin settings. Curly braces (${CI_COMMIT_SHA}) conflict with Woodpecker's compiler." Both thetags:field and theBUILD_SHAbuild arg must use$CI_COMMIT_SHA.B2. Test step uses
|| true, silently swallowing failuresThis means CI will never fail on broken tests. Per the plan's Phase 2 decisions: "Tests that silently skip when creds are missing are lazy and give false confidence. If credentials are missing, tests should fail." The
|| truecontradicts this philosophy. If tests require runtime secrets, those secrets should be added to Woodpecker and the step should fail honestly when they are missing.B3. Missing
k8s/kustomization.yamlThe plan Phase 3 explicitly requires: "Add k8s/ directory to each repo: kustomization.yaml, deployment.yaml, servicemonitor.yaml." The
kustomization.yamlis missing. ArgoCD can work in directory mode, but the plan mandates it. At minimum it should listdeployment.yamlas a resource.B4. Missing
k8s/servicemonitor.yamlSame as B3 -- the plan Phase 3 requires a
servicemonitor.yamlfor Prometheus scraping. Even a basic ServiceMonitor targeting port 8000 on/healthor/metricsis needed.NITS
N1. Ruff target-version is
py312, task checklist sayspy310The
pyproject.tomlsetstarget-version = "py312"which is consistent with thepython:3.12-slimDockerfile base image. If py312 is intentional (it appears to be), this is fine. Just flagging the discrepancy with the task description.N2.
pyproject.tomlURLs still point to GitHubThese should be updated to Forgejo URLs since the repo has been migrated. Non-blocking but worth fixing.
N3.
.dockerignoredoes not excludetests/Tests are not needed in the container image. Adding
tests/to.dockerignorewould reduce image size slightly. Non-blocking.SOP COMPLIANCE
1-add-woodpecker-ci-pipeline-dockerfile-an-- references issue #1)template-pr-body(Summary, Changes, Test Plan, Review Checklist, Related Notes -- all present)plan-2026-02-25-mcp-gateway-migration)|| true, cannot verify)namespace-conventions)harbor-credsdeployment-lessonsminimum).argocd-source-*path excluded from CI triggersVERDICT: NOT APPROVED
4 blockers must be resolved: curly braces in CI_COMMIT_SHA (B1), silent test failures (B2), missing kustomization.yaml (B3), missing servicemonitor.yaml (B4).
Fixed 4 QA blockers:
$CI_COMMIT_SHA(2 places)|| truefrom pytest (no tests/ directory exists, removed entire line)k8s/kustomization.yamlk8s/servicemonitor.yamlPR #2 Review
BLOCKERS
1. Service port not named -- ServiceMonitor will fail to scrape metrics
In
k8s/deployment.yaml, the Service defines its port without aname:But
k8s/servicemonitor.yamlreferencesport: http:The ServiceMonitor matches endpoints by port name, not by number. Since the Service port has no name, the ServiceMonitor will find zero endpoints and no metrics will be scraped.
Fix: Add
name: httpto the Service port definition:NITS
None.
SOP COMPLIANCE
1-add-woodpecker-ci-pipeline-dockerfile-anmatches Closes #1)template-pr-body(Summary, Changes, Test Plan, Review Checklist, Related Notes)plan-2026-02-25-mcp-gateway-migration)namespace-conventions)$CI_COMMIT_SHAwithout curly braces (perdeployment-lessons)|| truein pipeline.argocd-source-*path exclusion present (perargocd-image-updater)linkedin-scheduler-remote/server)deployment-lessons)kustomization.yamlexists and lists all resourcesservicemonitor.yamlexistsVERDICT: NOT APPROVED
One blocker: the Service port must be named
httpfor the ServiceMonitor to function. Everything else is clean.Fixed: added
name: httpto Service port so ServiceMonitor can match by port name.Commit:
3cf6bcd—fix: add named port to Service for ServiceMonitor compatibilityPR #2 Review
BLOCKERS
None.
NITS
Dockerfile runs as root. No
USERdirective -- the container runs as root. Best practice is to create a non-root user (RUN adduser --system appuser && USER appuser). However, this may conflict with PVC write permissions onlocal-pathstorage class, so flagging as a nit rather than a blocker. Consider addressing in a follow-up if volume permissions allow it.Stale GitHub URLs in
pyproject.toml. The[project.urls]section still points togithub.com/ldraney/linkedin-scheduler-remote. Pre-existing, not introduced by this PR -- out of scope, but worth noting for a future cleanup pass.SOP COMPLIANCE
1-add-woodpecker-ci-pipeline-dockerfile-anreferences issue #1)template-pr-body(Summary, Changes, Test Plan, Review Checklist, Related Notes -- all present)plan-2026-02-25-mcp-gateway-migrationnamespace-conventions)name: http(previous QA issue -- fix confirmed)port: httpmatches named Service portimagePullSecrets: harbor-credspresent/health:8000k8s/.argocd-source-*in pipelinesecrets:field)--no-cache-dirVERDICT: APPROVED
Clean PR. The previous QA finding (missing
name: httpon the Service port) has been fixed. All Phase 3 deliverables are present and correct: Woodpecker pipeline, multi-stage Dockerfile, k8s manifests (Deployment, Service, PVC, ServiceMonitor, Kustomization). Port convention, namespace convention, and SOP compliance all check out. The two nits are non-blocking observations for future consideration.