Skip to content

1839 daps fix ci image retag#1840

Merged
JoshuaSBrown merged 5 commits intodevelfrom
1839-DAPS-fix-ci-image-retag
Feb 4, 2026
Merged

1839 daps fix ci image retag#1840
JoshuaSBrown merged 5 commits intodevelfrom
1839-DAPS-fix-ci-image-retag

Conversation

@JoshuaSBrown
Copy link
Collaborator

@JoshuaSBrown JoshuaSBrown commented Feb 3, 2026

Ticket

Description

How Has This Been Tested?

Artifacts (if appropriate):

Tasks

  • - A description of the PR has been provided, and a diagram included if it is a new feature.
  • - Formatter has been run
  • - CHANGELOG comment has been added
  • - Labels have been assigned to the pr
  • - A reviwer has been added
  • - A user has been assigned to work on the pr
  • - If new feature a unit test has been added

Summary by Sourcery

Update CI Docker image check and tagging logic to avoid unnecessary rebuilds and switch from build pipelines to retag pipelines based on watched-path changes.

New Features:

  • Add commit-aware image change detection in the CI image check job using Harbor metadata and git diffs against configurable watched paths.
  • Introduce dedicated retag pipelines for each service image to reuse existing images when appropriate instead of rebuilding them.

Enhancements:

  • Refine intermediate image handling so that missing intermediate layers trigger a forced build while existing ones allow retagging.
  • Normalize component naming between hyphenated repository names and underscore-based CI file names for image build/retag jobs.
  • Tidy CI configuration comments and whitespace in common GitLab CI templates.

CI:

  • Extend the .image_check job to query Harbor for the last built commit SHA and only force Docker image builds when watched files have changed or metadata is unavailable.
  • Add WATCHED_PATHS configuration per image-check job to control which paths trigger image rebuilds for ws, core, repo, gcs, gcs-base, and foxx images.
  • Replace per-component build_image GitLab CI configs with retag_image configs that rely on the shared .docker_retag_image template.

@JoshuaSBrown JoshuaSBrown self-assigned this Feb 3, 2026
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Feb 3, 2026

Reviewer's Guide

Updates the GitLab CI image check and build pipeline to use commit-SHA–aware retagging and watched-path diffs to decide when to rebuild Docker images, introduces retag pipelines per component, and removes obsolete build-only pipeline configs.

Sequence diagram for updated .image_check image rebuild decision

sequenceDiagram
    participant GitLabCI
    participant image_check_job
    participant HarborRegistry
    participant GitRepository

    GitLabCI->>image_check_job: Start job with COMPONENT, PROJECT, WATCHED_PATHS
    image_check_job->>HarborRegistry: docker login REGISTRY

    image_check_job->>HarborRegistry: docker pull IMAGE_PATH:latest
    HarborRegistry-->>image_check_job: Success or failure
    alt Image does not exist
        image_check_job->>image_check_job: Set FORCE_BUILD = TRUE
    else Image exists
        image_check_job->>HarborRegistry: GET /api/v2.0/projects/PROJECT/repositories/REPO_NAME/artifacts
        HarborRegistry-->>image_check_job: Harbor API response
        alt Harbor API error or empty
            image_check_job->>image_check_job: Set FORCE_BUILD = TRUE
        else Harbor API ok
            image_check_job->>image_check_job: Extract LATEST_IMAGE_SHA from tags
            alt No SHA tag found
                image_check_job->>image_check_job: Set FORCE_BUILD = TRUE
            else SHA tag found
                alt LATEST_IMAGE_SHA == CI_COMMIT_SHA
                    image_check_job->>image_check_job: No rebuild needed
                else Different commit
                    image_check_job->>GitRepository: git fetch history
                    GitRepository-->>image_check_job: Updated history
                    image_check_job->>GitRepository: git cat-file -e LATEST_IMAGE_SHA
                    GitRepository-->>image_check_job: Exists or missing
                    alt Commit not in history
                        image_check_job->>image_check_job: Set FORCE_BUILD = TRUE
                    else Commit exists
                        image_check_job->>GitRepository: git diff --name-only LATEST_IMAGE_SHA CI_COMMIT_SHA -- WATCHED_PATHS
                        GitRepository-->>image_check_job: DIFF_OUTPUT
                        alt DIFF_OUTPUT not empty
                            image_check_job->>image_check_job: Set FORCE_BUILD = TRUE
                        else No watched changes
                            image_check_job->>image_check_job: Keep FORCE_BUILD = FALSE
                        end
                    end
                end
            end
        end
    end

    alt BUILD_INTERMEDIATE == TRUE and FORCE_BUILD == FALSE
        image_check_job->>HarborRegistry: docker pull COMPONENT-INTERMEDIATE_LAYER_NAME-BRANCH:latest
        HarborRegistry-->>image_check_job: Success or failure
        alt Intermediate missing
            image_check_job->>image_check_job: Set FORCE_BUILD = TRUE
        end
    end

    image_check_job->>image_check_job: FILE_COMPONENT = COMPONENT with dashes to underscores
    alt FORCE_BUILD == TRUE
        image_check_job->>image_check_job: cp .gitlab/build/force_build_FILE_COMPONENT_image.yml FILE_COMPONENT_image.yml
    else FORCE_BUILD == FALSE
        image_check_job->>image_check_job: cp .gitlab/build/retag_FILE_COMPONENT_image.yml FILE_COMPONENT_image.yml
    end
    image_check_job->>GitLabCI: Export build.env and artifact FILE_COMPONENT_image.yml
Loading

Flow diagram for FORCE_BUILD decision and file selection in .image_check

flowchart TD
    A[Start .image_check script] --> B[Set BRANCH_LOWER<br>Set REPO_NAME<br>Set IMAGE_PATH]
    B --> C[docker pull IMAGE_PATH:latest]
    C --> D{Pull succeeded?}
    D -- No --> E[Set FORCE_BUILD = TRUE]
    D -- Yes --> F[Call Harbor API for latest artifacts]

    F --> G{API ok and response present?}
    G -- No --> E
    G -- Yes --> H[Extract LATEST_IMAGE_SHA tag]

    H --> I{LATEST_IMAGE_SHA present?}
    I -- No --> E
    I -- Yes --> J{LATEST_IMAGE_SHA == CI_COMMIT_SHA?}

    J -- Yes --> K[Keep FORCE_BUILD = FALSE<br>No rebuild needed]
    J -- No --> L[git fetch history]

    L --> M[git cat-file -e LATEST_IMAGE_SHA]
    M --> N{Commit exists in history?}
    N -- No --> E
    N -- Yes --> O{WATCHED_PATHS defined?}

    O -- No --> P[Exit with error]
    O -- Yes --> Q[git diff --name-only<br>LATEST_IMAGE_SHA CI_COMMIT_SHA -- WATCHED_PATHS]

    Q --> R{DIFF_OUTPUT non-empty?}
    R -- Yes --> E
    R -- No --> K

    E --> S[FORCE_BUILD may be TRUE]
    K --> S

    S --> T{BUILD_INTERMEDIATE == TRUE<br>and FORCE_BUILD == FALSE?}
    T -- Yes --> U[docker pull intermediate image]
    U --> V{Intermediate exists?}
    V -- No --> E
    V -- Yes --> W[Keep FORCE_BUILD as FALSE]

    T -- No --> W

    W --> X[FILE_COMPONENT = COMPONENT with dashes to underscores]
    X --> Y{FORCE_BUILD == TRUE?}

    Y -- Yes --> Z[cp .gitlab/build/force_build_FILE_COMPONENT_image.yml<br>FILE_COMPONENT_image.yml]
    Y -- No --> AA[cp .gitlab/build/retag_FILE_COMPONENT_image.yml<br>FILE_COMPONENT_image.yml]

    Z --> AB[Write build.env<br>export variables]
    AA --> AB
    AB --> AC[End .image_check script]
Loading

File-Level Changes

Change Details Files
Enhance .image_check job to decide rebuilds based on Harbor image metadata and git diffs, and to select new retag vs force-build pipelines using underscore-based component names.
  • Refactors image path construction using REPO_NAME and IMAGE_PATH variables.
  • Replaces simple docker pull existence checks with logic that queries Harbor’s API for the latest artifact, extracts a commit SHA tag, and compares it to CI_COMMIT_SHA.
  • Adds logic to fetch git history, verify the previous commit exists, and compute git diff restricted to WATCHED_PATHS to determine if a rebuild is necessary.
  • Adds handling for missing images, failed Harbor API calls, missing commit SHA tags, or missing intermediate images by forcing a rebuild.
  • Introduces FILE_COMPONENT (dash-to-underscore conversion) and uses it when copying either force_build_.yml or retag_.yml into the per-component pipeline file.
  • Keeps environment export behavior and slightly cleans up formatting in the helper push loop.
.gitlab/common.yml
Define watched paths per component for image change detection in stage_image_check jobs.
  • Adds WATCHED_PATHS variables to ws, core, repo, gcs_base, gcs, and foxx image-check jobs with component-specific directory and file lists.
  • Aligns gcs_base component naming to gcs-base to match new FILE_COMPONENT and repository naming conventions.
.gitlab/stage_image_check.yml
Introduce per-component retag pipelines and remove obsolete build pipelines.
  • Adds new retag_image.yml files (ws, core, repo, gcs, gcs-base, foxx) that extend .docker_retag_image and configure appropriate PROJECT, COMPONENT, BUILD_INTERMEDIATE, and tags.
  • Configures ws retag to use an intermediate build layer (ws-build) and appropriate intermediate variables.
  • Deletes legacy build_image.yml CI configs now superseded by retag pipelines and force_build logic in .image_check.
.gitlab/build/retag_ws_image.yml
.gitlab/build/retag_gcs_image.yml
.gitlab/build/retag_core_image.yml
.gitlab/build/retag_foxx_image.yml
.gitlab/build/retag_gcs_base_image.yml
.gitlab/build/retag_repo_image.yml
.gitlab/build/build_core_image.yml
.gitlab/build/build_foxx_image.yml
.gitlab/build/build_gcs_base_image.yml
.gitlab/build/build_gcs_image.yml
.gitlab/build/build_repo_image.yml
.gitlab/build/build_ws_image.yml

Possibly linked issues

  • #N/A: PR’s WATCHED_PATHS for foxx now include CMakeLists.txt, ensuring foxx images rebuild correctly and tags match commits.
  • #[Bug] - CI image retag triggered where a build is needed: PR replaces last-commit change rules with diff-from-last-image SHA using Harbor and WATCHED_PATHS, fixing erroneous retags.
  • #(not provided): PR introduces SHA and watched-path checks so CI rebuilds images instead of incorrectly relabeling old ones.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • The new .image_check script introduces several external dependencies (curl, jq, git) but does not validate their availability or handle failures of jq/JSON parsing specifically; consider adding explicit checks and clearer failure messages around those calls so failures don’t silently fall back to FORCE_BUILD without context.
  • The WATCHED_PATHS handling is spread between the job definitions and inline checks in the script; to avoid misconfiguration and hard‑to‑debug failures, consider centralizing default paths or adding a stricter validation step (e.g., fail fast when it’s unset for components that require it) instead of only checking for empty in the Harbor‑SHA flow.
  • The mapping from COMPONENT to FILE_COMPONENT (hyphen to underscore) and the new retag_* YAML files replaces the old build_* files, but the retag YAMLs are currently empty; ensure they contain the equivalent job definitions/logic that the deleted build_* files had so that the cp .gitlab/build/retag_${FILE_COMPONENT}_image.yml calls result in a usable pipeline fragment.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new `.image_check` script introduces several external dependencies (`curl`, `jq`, `git`) but does not validate their availability or handle failures of `jq`/JSON parsing specifically; consider adding explicit checks and clearer failure messages around those calls so failures don’t silently fall back to `FORCE_BUILD` without context.
- The `WATCHED_PATHS` handling is spread between the job definitions and inline checks in the script; to avoid misconfiguration and hard‑to‑debug failures, consider centralizing default paths or adding a stricter validation step (e.g., fail fast when it’s unset for components that require it) instead of only checking for empty in the Harbor‑SHA flow.
- The mapping from `COMPONENT` to `FILE_COMPONENT` (hyphen to underscore) and the new `retag_*` YAML files replaces the old `build_*` files, but the retag YAMLs are currently empty; ensure they contain the equivalent job definitions/logic that the deleted `build_*` files had so that the `cp .gitlab/build/retag_${FILE_COMPONENT}_image.yml` calls result in a usable pipeline fragment.

## Individual Comments

### Comment 1
<location> `.gitlab/common.yml:82-85` </location>
<code_context>
+                echo "Image exists, checking for changes in watched files"
+
+                # Get commit SHA from latest image via Harbor API
+                HARBOR_API_RESPONSE=$(curl -sf -u "${HARBOR_USER}:${HARBOR_DATAFED_GITLAB_CI_REGISTRY_TOKEN}" \
+                    "https://${REGISTRY}/api/v2.0/projects/${PROJECT}/repositories/${REPO_NAME}/artifacts?page_size=1&sort=-push_time")
+
+                if [ $? -ne 0 ] || [ -z "$HARBOR_API_RESPONSE" ]; then
+                    echo "WARNING: Harbor API request failed, forcing build"
+                    FORCE_BUILD="TRUE"
</code_context>

<issue_to_address>
**issue (bug_risk):** The `curl` failure handling is ineffective under `set -e` and will cause the script to abort instead of falling back to `FORCE_BUILD="TRUE"`.

With `set -e` enabled, a non‑zero exit from `curl -sf` will exit the script before the `[ $? -ne 0 ]` check runs, so transient Harbor/API errors will fail the job instead of setting `FORCE_BUILD="TRUE"`.

To preserve the intended fallback, either temporarily disable `set -e` around `curl` (like the `docker pull` logic) or capture the status via `||`:

```bash
set +e
HARBOR_API_RESPONSE=$(curl -sf -u "${HARBOR_USER}:${HARBOR_DATAFED_GITLAB_CI_REGISTRY_TOKEN}" \
    "https://${REGISTRY}/api/v2.0/projects/${PROJECT}/repositories/${REPO_NAME}/artifacts?page_size=1&sort=-push_time")
CURL_STATUS=$?
set -e

if [ $CURL_STATUS -ne 0 ] || [ -z "$HARBOR_API_RESPONSE" ]; then
    echo "WARNING: Harbor API request failed, forcing build"
    FORCE_BUILD="TRUE"
else
    ...
fi
```

This ensures Harbor API issues trigger a forced build rather than a hard pipeline failure.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +82 to +85
HARBOR_API_RESPONSE=$(curl -sf -u "${HARBOR_USER}:${HARBOR_DATAFED_GITLAB_CI_REGISTRY_TOKEN}" \
"https://${REGISTRY}/api/v2.0/projects/${PROJECT}/repositories/${REPO_NAME}/artifacts?page_size=1&sort=-push_time")

if [ $? -ne 0 ] || [ -z "$HARBOR_API_RESPONSE" ]; then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): The curl failure handling is ineffective under set -e and will cause the script to abort instead of falling back to FORCE_BUILD="TRUE".

With set -e enabled, a non‑zero exit from curl -sf will exit the script before the [ $? -ne 0 ] check runs, so transient Harbor/API errors will fail the job instead of setting FORCE_BUILD="TRUE".

To preserve the intended fallback, either temporarily disable set -e around curl (like the docker pull logic) or capture the status via ||:

set +e
HARBOR_API_RESPONSE=$(curl -sf -u "${HARBOR_USER}:${HARBOR_DATAFED_GITLAB_CI_REGISTRY_TOKEN}" \
    "https://${REGISTRY}/api/v2.0/projects/${PROJECT}/repositories/${REPO_NAME}/artifacts?page_size=1&sort=-push_time")
CURL_STATUS=$?
set -e

if [ $CURL_STATUS -ne 0 ] || [ -z "$HARBOR_API_RESPONSE" ]; then
    echo "WARNING: Harbor API request failed, forcing build"
    FORCE_BUILD="TRUE"
else
    ...
fi

This ensures Harbor API issues trigger a forced build rather than a hard pipeline failure.

@JoshuaSBrown JoshuaSBrown merged commit 51df50e into devel Feb 4, 2026
14 checks passed
@JoshuaSBrown JoshuaSBrown deleted the 1839-DAPS-fix-ci-image-retag branch February 4, 2026 14:01
@JoshuaSBrown JoshuaSBrown linked an issue Feb 4, 2026 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] - CI image retag triggered where a build is needed

1 participant