Skip to content

fix NPE for build waiter#640

Merged
mnovak merged 1 commit intoxtf-cz:mainfrom
laDok8:fix_build_waiter
Mar 11, 2026
Merged

fix NPE for build waiter#640
mnovak merged 1 commit intoxtf-cz:mainfrom
laDok8:fix_build_waiter

Conversation

@laDok8
Copy link
Copy Markdown
Contributor

@laDok8 laDok8 commented Mar 6, 2026

Return null instead of crashing so OpenshiftWaiters.hasBuildCompleted can retry gracefully. Reproduces on slower environments where Helm chart reconciliation lags behind the waiter start.

Closes #641

Summary by Sourcery

Bug Fixes:

  • Avoid a null pointer exception in getLatestBuild by returning null when the target BuildConfig does not exist.

@laDok8 laDok8 requested review from Copilot and mnovak March 6, 2026 10:56
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai bot commented Mar 6, 2026

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Adjusts OpenShift build retrieval to safely handle missing BuildConfigs by returning null instead of throwing a NullPointerException, allowing build waiters to retry gracefully.

Sequence diagram for OpenShift build waiter handling missing BuildConfig

sequenceDiagram
    actor Tester
    participant OpenshiftWaiters
    participant OpenShift
    participant OpenShiftClient

    Tester->>OpenshiftWaiters: hasBuildCompleted(buildConfigName)
    OpenshiftWaiters->>OpenShift: getLatestBuild(buildConfigName)
    OpenShift->>OpenShiftClient: buildConfigs().withName(buildConfigName).get()
    OpenShiftClient-->>OpenShift: BuildConfig or null
    alt BuildConfig is null
        OpenShift-->>OpenshiftWaiters: null
        OpenshiftWaiters->>OpenshiftWaiters: wait and retry
    else BuildConfig exists
        OpenShift->>OpenShift: lastVersion = bc.getStatus().getLastVersion()
        OpenShift->>OpenShift: buildName = buildConfigName + '-' + lastVersion
        OpenShift->>OpenShiftClient: getBuild(buildName)
        OpenShiftClient-->>OpenShift: Build
        OpenShift-->>OpenshiftWaiters: Build
        OpenshiftWaiters->>OpenshiftWaiters: evaluate completion
    end
Loading

Updated class diagram for OpenShift getLatestBuild behavior

classDiagram
    class OpenShift {
        +Build getBuild(String name)
        +Build getLatestBuild(String buildConfigName)
    }

    class BuildConfig {
        +BuildConfigStatus getStatus()
    }

    class BuildConfigStatus {
        +long getLastVersion()
    }

    class Build {
    }

    OpenShift --> BuildConfig : queries
    BuildConfig --> BuildConfigStatus : has
    OpenShift --> Build : returns

    note for OpenShift "getLatestBuild:
1. BuildConfig bc = buildConfigs().withName(buildConfigName).get()
2. if bc == null return null
3. long lastVersion = bc.getStatus().getLastVersion()
4. return getBuild(buildConfigName + '-' + lastVersion)"
Loading

File-Level Changes

Change Details Files
Handle missing BuildConfig when resolving latest build to avoid NullPointerException and allow callers to retry.
  • Store the result of buildConfigs().withName(buildConfigName).get() in a local BuildConfig variable instead of chaining calls
  • Add a null check for the retrieved BuildConfig and return null if it does not exist
  • Use the non-null BuildConfig instance to obtain status and lastVersion before constructing the build name
core/src/main/java/cz/xtf/core/openshift/OpenShift.java

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
Copy Markdown

@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 NPE fix only guards against a null BuildConfig; if bc.getStatus() can also be null in the slow-reconciliation scenario, you may want to null-check bc.getStatus() before dereferencing getLastVersion() to fully address the issue.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The NPE fix only guards against a null BuildConfig; if `bc.getStatus()` can also be null in the slow-reconciliation scenario, you may want to null-check `bc.getStatus()` before dereferencing `getLastVersion()` to fully address the issue.

## Individual Comments

### Comment 1
<location path="core/src/main/java/cz/xtf/core/openshift/OpenShift.java" line_range="835-839" />
<code_context>

     public Build getLatestBuild(String buildConfigName) {
-        long lastVersion = buildConfigs().withName(buildConfigName).get().getStatus().getLastVersion();
+        BuildConfig bc = buildConfigs().withName(buildConfigName).get();
+        if (bc == null) {
+            return null;
+        }
+        long lastVersion = bc.getStatus().getLastVersion();
         return getBuild(buildConfigName + "-" + lastVersion);
     }
</code_context>
<issue_to_address>
**issue (bug_risk):** Guard against a null BuildConfig status before calling getLastVersion()

The null check on `bc` prevents one NPE, but `bc.getStatus()` itself can still be null (e.g., for a newly created/partially initialized BuildConfig), causing an NPE on `getStatus().getLastVersion()`. Please also guard against a null status (and optionally handle a 0/unset `getLastVersion()`) before building the name, or fail in a controlled way.
</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 +835 to +839
BuildConfig bc = buildConfigs().withName(buildConfigName).get();
if (bc == null) {
return null;
}
long lastVersion = bc.getStatus().getLastVersion();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): Guard against a null BuildConfig status before calling getLastVersion()

The null check on bc prevents one NPE, but bc.getStatus() itself can still be null (e.g., for a newly created/partially initialized BuildConfig), causing an NPE on getStatus().getLastVersion(). Please also guard against a null status (and optionally handle a 0/unset getLastVersion()) before building the name, or fail in a controlled way.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adjusts OpenShift build lookup to avoid crashing when the BuildConfig isn’t available yet, allowing OpenShiftWaiters.hasBuildCompleted to keep retrying in slow/reconciling environments.

Changes:

  • Update OpenShift.getLatestBuild to return null when the BuildConfig cannot be fetched.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

if (bc == null) {
return null;
}
long lastVersion = bc.getStatus().getLastVersion();
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

getLatestBuild still has a possible NPE: bc.getStatus() can be null (and in this codebase getLastVersion() is treated as nullable elsewhere), so bc.getStatus().getLastVersion() may crash even when bc is non-null. Consider returning null when bc.getStatus() is null and when getLastVersion() is null/0 (use Long instead of long) so waiters can retry gracefully.

Suggested change
long lastVersion = bc.getStatus().getLastVersion();
if (bc.getStatus() == null) {
return null;
}
Long lastVersion = bc.getStatus().getLastVersion();
if (lastVersion == null || lastVersion == 0L) {
return null;
}

Copilot uses AI. Check for mistakes.
@mnovak
Copy link
Copy Markdown
Contributor

mnovak commented Mar 11, 2026

LGTM, merging. Thanks

@mnovak mnovak merged commit 4bc6d85 into xtf-cz:main Mar 11, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OpenShift.getLatestBuild() throws NPE when BuildConfig does not exist

3 participants