Optimize CI: use pre-built base image and parallelize steps #70

Merged
ldraney merged 3 commits from ci/optimize-pipeline into main 2026-06-04 01:51:54 +00:00
Owner

Summary

  • Switches lint and test CI steps from ruby:3.4.9-slim to the platform's ruby-rails-build image, eliminating apt-get, gem install bundler, and native extension compilation on every run
  • Adds depends_on: [clone] so lint and test run in parallel instead of sequentially
  • Overrides BUNDLE_DEPLOYMENT and BUNDLE_WITHOUT env vars since the base image defaults to production bundle settings

Closes #69

Changes

  • .woodpecker.yaml: Replace step images, remove package installation commands, add parallel execution, add bundle env overrides

Test Plan

  • Pipeline triggers on this PR's push event
  • Lint step passes using the base image
  • Test step passes using the base image with Postgres service container
  • Lint and test run concurrently in Woodpecker UI
  • Build-and-push still works on main merge

Review Checklist

  • Passed automated review-fix loop
  • No secrets committed
  • No unnecessary file changes
  • Commit messages are descriptive
  • ldraney/landscaping-assistant #69 — CI optimization feature issue
  • landscaping-assistant — project
  • ldraney/base-images — source of the ruby-rails-build image
## Summary - Switches lint and test CI steps from `ruby:3.4.9-slim` to the platform's `ruby-rails-build` image, eliminating `apt-get`, `gem install bundler`, and native extension compilation on every run - Adds `depends_on: [clone]` so lint and test run in parallel instead of sequentially - Overrides `BUNDLE_DEPLOYMENT` and `BUNDLE_WITHOUT` env vars since the base image defaults to production bundle settings Closes #69 ## Changes - `.woodpecker.yaml`: Replace step images, remove package installation commands, add parallel execution, add bundle env overrides ## Test Plan - [ ] Pipeline triggers on this PR's push event - [ ] Lint step passes using the base image - [ ] Test step passes using the base image with Postgres service container - [ ] Lint and test run concurrently in Woodpecker UI - [ ] Build-and-push still works on main merge ## Review Checklist - [ ] Passed automated review-fix loop - [ ] No secrets committed - [ ] No unnecessary file changes - [ ] Commit messages are descriptive ## Related Notes - `ldraney/landscaping-assistant #69` — CI optimization feature issue - `landscaping-assistant` — project - `ldraney/base-images` — source of the ruby-rails-build image
Optimize CI: use pre-built base image and parallelize lint + test
Some checks are pending
CI / scan_ruby (pull_request) Waiting to run
CI / scan_js (pull_request) Waiting to run
CI / lint (pull_request) Waiting to run
c159a3721d
- Switch lint and test steps from ruby:3.4.9-slim to the platform's
  ruby-rails-build image, eliminating apt-get, gem install bundler,
  and native extension compilation on every run
- Add depends_on: [clone] to both steps so they run in parallel
- Override BUNDLE_DEPLOYMENT and BUNDLE_WITHOUT env vars since the
  base image defaults to production bundle settings

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Author
Owner

PR #70 Review

DOMAIN REVIEW

Tech stack: Woodpecker CI pipeline configuration (YAML), referencing a Ruby/Rails project with RSpec, RuboCop, Postgres, and Kaniko-based container builds.

Image reference: Both lint and test steps correctly use harbor.harbor.svc.cluster.local/library/ruby-rails-build:latest, which is the k8s-internal DNS for Harbor. This is consistent with the build-and-push step's registry setting on the same hostname. The Dockerfile separately uses the Tailscale hostname (harbor.tail5b443a.ts.net) which is appropriate for its build context.

BUNDLE_DEPLOYMENT / BUNDLE_WITHOUT overrides: The base image is built for production and sets BUNDLE_DEPLOYMENT=true and BUNDLE_WITHOUT=development:test. Overriding both to empty strings in CI is correct -- CI needs dev/test gems (rubocop, rspec, capybara, debug, brakeman, bundler-audit). Without these overrides, bundle install would skip the test/development groups and rubocop/rspec would be missing. Good catch.

Parallel execution: Adding depends_on: [clone] to both lint and test means they fan out after clone completes and run concurrently. The build-and-push step already has depends_on: [lint, test], so it correctly gates on both completing. The DAG is sound: clone -> (lint | test) -> build-and-push.

Removed apt-get / gem install: The base image (ruby-rails-build) includes build-essential, libpq-dev, libyaml-dev, git, and bundler. Removing these install commands from CI is the entire point of the pre-built image strategy. No dependencies are missing.

:latest tag risk: Both steps pin to :latest. This is a minor concern -- a breaking change to the base image would silently affect CI. However, since ldraney/base-images is also under your control and the Dockerfile already uses :latest for the same image, this is a consistent policy choice, not an oversight. Noted as a nit below.

Postgres service container: The database service is unchanged and correct. The test step's DATABASE_URL points to it properly.

BLOCKERS

None.

This PR modifies CI configuration only -- no application code, no new functionality requiring tests, no user input handling, no secrets in code, no auth logic. None of the BLOCKER criteria apply.

NITS

  1. :latest tag on CI images -- Consider pinning to a SHA digest or semver tag (e.g., ruby-rails-build:3.4.9-1) to make CI reproducible. A bad push to base-images would break CI silently with :latest. This is a platform-wide decision, not specific to this PR.

  2. DRY opportunity -- The BUNDLE_DEPLOYMENT: "" and BUNDLE_WITHOUT: "" environment block is duplicated across lint and test. Woodpecker supports top-level environment or YAML anchors to deduplicate. Low priority since there are only two steps.

SOP COMPLIANCE

  • Branch naming: ci/optimize-pipeline -- does not follow {issue-number}-{kebab-case-purpose} convention (would be 69-optimize-ci-pipeline). This is a minor deviation. The branch uses a ci/ prefix convention instead.
  • PR body has Summary, Changes, Test Plan, Related sections
  • Related section references plan slug -- no plan slug exists (acknowledged in task context)
  • No secrets committed -- Harbor credentials use from_secret, no plaintext secrets
  • No unnecessary file changes -- single file changed, tightly scoped
  • Commit messages -- PR title is descriptive

PROCESS OBSERVATIONS

This change directly improves DORA lead time by eliminating ~30-60s of apt-get and gem install per CI step and running lint/test in parallel instead of sequentially. Net effect: CI wall-clock time should roughly halve for the lint+test phase. The pre-built image strategy centralizes dependency management in base-images, which is the right architectural call -- dependency drift between CI and production is a common source of change failure.

The branch naming deviation (ci/optimize-pipeline vs 69-optimize-ci-pipeline) is worth noting for process consistency but is not blocking.

VERDICT: APPROVED

## PR #70 Review ### DOMAIN REVIEW **Tech stack**: Woodpecker CI pipeline configuration (YAML), referencing a Ruby/Rails project with RSpec, RuboCop, Postgres, and Kaniko-based container builds. **Image reference**: Both lint and test steps correctly use `harbor.harbor.svc.cluster.local/library/ruby-rails-build:latest`, which is the k8s-internal DNS for Harbor. This is consistent with the build-and-push step's `registry` setting on the same hostname. The Dockerfile separately uses the Tailscale hostname (`harbor.tail5b443a.ts.net`) which is appropriate for its build context. **BUNDLE_DEPLOYMENT / BUNDLE_WITHOUT overrides**: The base image is built for production and sets `BUNDLE_DEPLOYMENT=true` and `BUNDLE_WITHOUT=development:test`. Overriding both to empty strings in CI is correct -- CI needs dev/test gems (rubocop, rspec, capybara, debug, brakeman, bundler-audit). Without these overrides, `bundle install` would skip the test/development groups and rubocop/rspec would be missing. Good catch. **Parallel execution**: Adding `depends_on: [clone]` to both lint and test means they fan out after clone completes and run concurrently. The build-and-push step already has `depends_on: [lint, test]`, so it correctly gates on both completing. The DAG is sound: clone -> (lint | test) -> build-and-push. **Removed apt-get / gem install**: The base image (`ruby-rails-build`) includes build-essential, libpq-dev, libyaml-dev, git, and bundler. Removing these install commands from CI is the entire point of the pre-built image strategy. No dependencies are missing. **`:latest` tag risk**: Both steps pin to `:latest`. This is a minor concern -- a breaking change to the base image would silently affect CI. However, since `ldraney/base-images` is also under your control and the Dockerfile already uses `:latest` for the same image, this is a consistent policy choice, not an oversight. Noted as a nit below. **Postgres service container**: The database service is unchanged and correct. The test step's `DATABASE_URL` points to it properly. ### BLOCKERS None. This PR modifies CI configuration only -- no application code, no new functionality requiring tests, no user input handling, no secrets in code, no auth logic. None of the BLOCKER criteria apply. ### NITS 1. **`:latest` tag on CI images** -- Consider pinning to a SHA digest or semver tag (e.g., `ruby-rails-build:3.4.9-1`) to make CI reproducible. A bad push to `base-images` would break CI silently with `:latest`. This is a platform-wide decision, not specific to this PR. 2. **DRY opportunity** -- The `BUNDLE_DEPLOYMENT: ""` and `BUNDLE_WITHOUT: ""` environment block is duplicated across lint and test. Woodpecker supports top-level `environment` or YAML anchors to deduplicate. Low priority since there are only two steps. ### SOP COMPLIANCE - [x] Branch naming: `ci/optimize-pipeline` -- does not follow `{issue-number}-{kebab-case-purpose}` convention (would be `69-optimize-ci-pipeline`). This is a minor deviation. The branch uses a `ci/` prefix convention instead. - [x] PR body has Summary, Changes, Test Plan, Related sections - [ ] Related section references plan slug -- no plan slug exists (acknowledged in task context) - [x] No secrets committed -- Harbor credentials use `from_secret`, no plaintext secrets - [x] No unnecessary file changes -- single file changed, tightly scoped - [x] Commit messages -- PR title is descriptive ### PROCESS OBSERVATIONS This change directly improves DORA lead time by eliminating ~30-60s of apt-get and gem install per CI step and running lint/test in parallel instead of sequentially. Net effect: CI wall-clock time should roughly halve for the lint+test phase. The pre-built image strategy centralizes dependency management in `base-images`, which is the right architectural call -- dependency drift between CI and production is a common source of change failure. The branch naming deviation (`ci/optimize-pipeline` vs `69-optimize-ci-pipeline`) is worth noting for process consistency but is not blocking. ### VERDICT: APPROVED
Fix depends_on: clone is a special section, not a step name
Some checks failed
CI / scan_ruby (pull_request) Waiting to run
CI / scan_js (pull_request) Waiting to run
CI / lint (pull_request) Waiting to run
ci/woodpecker/pr/woodpecker Pipeline failed
ci/woodpecker/push/woodpecker Pipeline failed
4cfc1b1637
Use empty depends_on array to signal no inter-step dependency,
which lets Woodpecker run lint and test in parallel after the
implicit clone stage completes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use external Harbor URL for CI step images
Some checks failed
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/pr/woodpecker Pipeline was successful
CI / scan_ruby (pull_request) Has been cancelled
CI / scan_js (pull_request) Has been cancelled
CI / lint (pull_request) Has been cancelled
5a62416c2d
The internal URL (harbor.harbor.svc.cluster.local) fails for step
image pulls — the node's container runtime doesn't have it configured
as an insecure registry. The external URL works for pulls (TLS-secured)
and is already used in the Dockerfile FROM statements.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ldraney deleted branch ci/optimize-pipeline 2026-06-04 01:51:54 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ldraney/landscaping-assistant!70
No description provided.