CI pipeline: cache bundle install to cut build time #60

Closed
opened 2026-06-02 20:30:27 +00:00 by ldraney · 1 comment
Owner

Type

Feature

Lineage

Standalone — discovered while monitoring pipeline #131. Related to #23 (CI optimization, now closed).

Repo

ldraney/landscaping-assistant

User Story

As a developer
I want CI pipelines to skip redundant bundle install
So that deployments reach prod faster and DORA lead time improves

Context

Every Woodpecker pipeline run does a full bundle install with native extension compilation (debug, bootsnap, psych, date, erb, websocket-driver, etc.). No gem caching between runs. This adds 2-3 minutes to every pipeline. Two approaches:

  1. Woodpecker volume cache for /usr/local/bundle between runs
  2. Pre-built CI image with gems baked in (similar to existing ruby-rails-build Harbor image used for the web container)

Option 2 is more reliable but requires rebuilding the CI image when Gemfile changes.

File Targets

Files the agent should modify or create:

  • .woodpecker.yaml -- add volume cache or switch to pre-built image
  • Possibly a CI-specific Dockerfile if going the baked-image route

Acceptance Criteria

  • Bundle install step takes <10s on a cache hit
  • Pipeline total time reduced by ~2-3 minutes
  • Cache invalidates correctly when Gemfile.lock changes

Test Expectations

  • Run pipeline twice — second run should be significantly faster
  • Change Gemfile, verify cache busts correctly

Constraints

  • Must work with single-worker Woodpecker setup (scaling tracked in #62)
  • No system tests in CI — test suite is request + model specs only (RSpec)

Checklist

  • Approach chosen
  • PR opened
  • Pipeline timing verified
  • landscaping-assistant -- project
  • #23 -- CI optimization (closed, work complete)
  • #62 -- Woodpecker agent scaling (related CI improvement)
### Type Feature ### Lineage Standalone — discovered while monitoring pipeline #131. Related to #23 (CI optimization, now closed). ### Repo `ldraney/landscaping-assistant` ### User Story As a developer I want CI pipelines to skip redundant bundle install So that deployments reach prod faster and DORA lead time improves ### Context Every Woodpecker pipeline run does a full `bundle install` with native extension compilation (debug, bootsnap, psych, date, erb, websocket-driver, etc.). No gem caching between runs. This adds 2-3 minutes to every pipeline. Two approaches: 1. Woodpecker volume cache for `/usr/local/bundle` between runs 2. Pre-built CI image with gems baked in (similar to existing `ruby-rails-build` Harbor image used for the web container) Option 2 is more reliable but requires rebuilding the CI image when Gemfile changes. ### File Targets Files the agent should modify or create: - `.woodpecker.yaml` -- add volume cache or switch to pre-built image - Possibly a CI-specific Dockerfile if going the baked-image route ### Acceptance Criteria - [ ] Bundle install step takes <10s on a cache hit - [ ] Pipeline total time reduced by ~2-3 minutes - [ ] Cache invalidates correctly when Gemfile.lock changes ### Test Expectations - [ ] Run pipeline twice — second run should be significantly faster - [ ] Change Gemfile, verify cache busts correctly ### Constraints - Must work with single-worker Woodpecker setup (scaling tracked in #62) - No system tests in CI — test suite is request + model specs only (RSpec) ### Checklist - [ ] Approach chosen - [ ] PR opened - [ ] Pipeline timing verified ### Related - `landscaping-assistant` -- project - #23 -- CI optimization (closed, work complete) - #62 -- Woodpecker agent scaling (related CI improvement)
Author
Owner

Ticket Scope Review -- Board Item #1297

FILE TARGETS VERIFICATION

File Exists Correct Target
.woodpecker.yaml Yes Correct -- both lint and test steps do full bundle install with apt-get on every run. This is the file to modify.
CI-specific Dockerfile (conditional) Does not exist yet Correct -- ticket notes this is only needed if the baked-image approach (Option 2) is chosen.

The current .woodpecker.yaml confirms the problem statement: both the lint step (line 17-21) and test step (line 27-31) independently run apt-get update, gem install bundler, and bundle install --jobs=4 on bare ruby:3.4.9-slim. This is redundant work on every pipeline run.

ACCEPTANCE CRITERIA REVIEW

Criterion Testable Notes
Bundle install <10s on cache hit Yes Measurable from Woodpecker step logs. Clear threshold.
Pipeline total time reduced ~2-3min Yes Compare before/after pipeline durations.
Cache invalidates on Gemfile.lock change Yes Modify Gemfile, push, verify full install runs.

All three criteria are testable and have clear pass/fail conditions.

DEPENDENCY ANALYSIS

  • Issue #23 (Optimize CI: Harbor base image + registry URL) is still open in backlog. Its scope explicitly says "Does NOT add caching layers" -- so #60 is complementary, not dependent. However, #23 proposes switching lint/test steps to the Harbor base image, which would partially overlap with #60's Option 2 (baked-image approach). If #23 lands first and lint/test use ruby-rails-build, then #60 becomes much simpler (cache is baked in). If #60 lands first with volume caching, #23's scope narrows.
  • No hard blockers. The Woodpecker volume cache approach (Option 1) works with the current ruby:3.4.9-slim image. Option 2 would depend on Harbor image availability, which is already proven (the production Dockerfile uses harbor.tail5b443a.ts.net/library/ruby-rails-build:latest).
  • Woodpecker single-worker constraint is noted. Volume caching on a single worker is straightforward (local directory mount). Multi-worker would require shared storage, but that is out of scope per the constraint.

SCOPE CLARITY

The ticket is well-scoped for agent execution:

  • Two clear approaches are documented (volume cache vs. baked image), with tradeoffs noted.
  • Constraints are explicit (single-worker, don't break system tests/Chromium).
  • Test plan is concrete (run twice, change Gemfile, verify cache bust).

One gap: The ticket does not specify which option to choose. An executing agent would need to make that decision or ask. Recommendation: add a note indicating the preferred approach, or explicitly state "agent's discretion based on complexity." Given the overlap with #23, Option 1 (volume cache) is the cleaner choice -- it is independent of #23 and can coexist with a future base image switch.

LABELS

Current labels: type:feature, arch:ci-pipeline, story:ci-optimization, devops -- appropriate.

SOP COMPLIANCE

  • Forgejo issue exists with user story, context, file targets, acceptance criteria, test expectations, constraints, and related references.
  • Labels include the traceability triangle (type:, arch:, story:).
  • Related issues are cross-referenced (#23).
  • No secrets or credentials in the ticket.

VERDICT: APPROVED

Scope is clear, acceptance criteria are testable, file targets are verified, and dependencies are non-blocking. Minor recommendation: note a preferred approach (Option 1 volume cache vs. Option 2 baked image) to reduce agent decision-making, but this is not a blocker for moving to todo. The overlap with #23 should be noted when either ticket moves to next_up.

## Ticket Scope Review -- Board Item #1297 ### FILE TARGETS VERIFICATION | File | Exists | Correct Target | |------|--------|----------------| | `.woodpecker.yaml` | Yes | Correct -- both `lint` and `test` steps do full `bundle install` with `apt-get` on every run. This is the file to modify. | | CI-specific Dockerfile (conditional) | Does not exist yet | Correct -- ticket notes this is only needed if the baked-image approach (Option 2) is chosen. | The current `.woodpecker.yaml` confirms the problem statement: both the `lint` step (line 17-21) and `test` step (line 27-31) independently run `apt-get update`, `gem install bundler`, and `bundle install --jobs=4` on bare `ruby:3.4.9-slim`. This is redundant work on every pipeline run. ### ACCEPTANCE CRITERIA REVIEW | Criterion | Testable | Notes | |-----------|----------|-------| | Bundle install <10s on cache hit | Yes | Measurable from Woodpecker step logs. Clear threshold. | | Pipeline total time reduced ~2-3min | Yes | Compare before/after pipeline durations. | | Cache invalidates on Gemfile.lock change | Yes | Modify Gemfile, push, verify full install runs. | All three criteria are testable and have clear pass/fail conditions. ### DEPENDENCY ANALYSIS - **Issue #23** (Optimize CI: Harbor base image + registry URL) is still open in backlog. Its scope explicitly says "Does NOT add caching layers" -- so #60 is complementary, not dependent. However, #23 proposes switching lint/test steps to the Harbor base image, which would partially overlap with #60's Option 2 (baked-image approach). If #23 lands first and lint/test use `ruby-rails-build`, then #60 becomes much simpler (cache is baked in). If #60 lands first with volume caching, #23's scope narrows. - **No hard blockers.** The Woodpecker volume cache approach (Option 1) works with the current `ruby:3.4.9-slim` image. Option 2 would depend on Harbor image availability, which is already proven (the production `Dockerfile` uses `harbor.tail5b443a.ts.net/library/ruby-rails-build:latest`). - **Woodpecker single-worker constraint** is noted. Volume caching on a single worker is straightforward (local directory mount). Multi-worker would require shared storage, but that is out of scope per the constraint. ### SCOPE CLARITY The ticket is well-scoped for agent execution: - **Two clear approaches** are documented (volume cache vs. baked image), with tradeoffs noted. - **Constraints** are explicit (single-worker, don't break system tests/Chromium). - **Test plan** is concrete (run twice, change Gemfile, verify cache bust). **One gap:** The ticket does not specify which option to choose. An executing agent would need to make that decision or ask. Recommendation: add a note indicating the preferred approach, or explicitly state "agent's discretion based on complexity." Given the overlap with #23, Option 1 (volume cache) is the cleaner choice -- it is independent of #23 and can coexist with a future base image switch. ### LABELS Current labels: `type:feature, arch:ci-pipeline, story:ci-optimization, devops` -- appropriate. ### SOP COMPLIANCE - Forgejo issue exists with user story, context, file targets, acceptance criteria, test expectations, constraints, and related references. - Labels include the traceability triangle (`type:`, `arch:`, `story:`). - Related issues are cross-referenced (#23). - No secrets or credentials in the ticket. ### VERDICT: APPROVED Scope is clear, acceptance criteria are testable, file targets are verified, and dependencies are non-blocking. Minor recommendation: note a preferred approach (Option 1 volume cache vs. Option 2 baked image) to reduce agent decision-making, but this is not a blocker for moving to `todo`. The overlap with #23 should be noted when either ticket moves to `next_up`.
Sign in to join this conversation.
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#60
No description provided.