Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

fix: ensure samples fail if there is any error - #490

#490
Merged
berezovskyi merged 5 commits into
mainOSLC/oslc4net:mainfrom
b-strict-smokeOSLC/oslc4net:b-strict-smokeCopy head branch name to clipboard
Dec 7, 2025
Merged

fix: ensure samples fail if there is any error#490
berezovskyi merged 5 commits into
mainOSLC/oslc4net:mainfrom
b-strict-smokeOSLC/oslc4net:b-strict-smokeCopy head branch name to clipboard

Conversation

@berezovskyi

@berezovskyi berezovskyi commented Dec 7, 2025

Copy link
Copy Markdown
Member

Replaces silent failures with explicit exceptions, ensuring exceptions are rethrown after logging, and cleaning up and organizing using statements for better readability.

Summary by CodeRabbit

  • New Features

    • Generic allowed-values support for resources.
    • New CLI-driven sample launcher and per-sample Run entry points with improved logging and console options.
    • Expanded authentication client with form-login flow and redirect handling.
    • New abstract sample base to standardize paging/raw-response handling.
  • Bug Fixes

    • Improved error handling and exception propagation across samples.
    • More robust property-resolution and paging processing; clearer error messages for missing samples.
    • Fixed stray BOM/encoding issues.
  • Tests

    • Added deserialization tests for allowed-values resources.

✏️ Tip: You can customize this high-level summary in your review settings.

Copilot AI review requested due to automatic review settings December 7, 2025 10:03
@coderabbitai

coderabbitai Bot commented Dec 7, 2025

Copy link
Copy Markdown
Contributor

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Samples were refactored into sealed classes with public static Run entry points, CLI parsing, and ILogger wiring; authentication flows were tightened to throw on failure; AllowedValues became generic AllowedValuesResource; RDF member filtering for query results was narrowed; tests and solution/project references were updated.

Changes

Cohort / File(s) Summary
Samples — CLI & logging refactor
OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ERMSample.cs, OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs, OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs, OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/Program.cs
Introduced public static async Task Run(string[] args) entry points, added ILoggerFactory/ILogger usage, switched to System.CommandLine parsing, centralized sample selection/launcher in Program, and changed auth failure handling to throw/propagate exceptions.
Samples — shared base & paging helpers
OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/SampleBase.cs, OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/Properties/AssemblyInfo.cs
Added public abstract class SampleBase<TResource> with paging/query processing, raw-response streaming and logging helpers; removed stray BOM and cleaned AssemblyInfo usings.
EWMSample — filedAgainst resolution & scenarios
OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs
Added ResolveFiledAgainstAsync discovery flow (CreationFactory → ServiceProvider → ResourceShapes → filedAgainst → AllowedValues), three scenarios (paged query, raw XML retrieval, create/update), and enhanced logging/error handling.
ERM & ETM samples — full workflows
OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ERMSample.cs, OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs
Reworked sample flows to Run/RunAsync patterns performing multi-step OSLC/Jazz workflows (auth, root services discovery, service provider lookup, resource creation/query, shapes handling) and improved error propagation.
AllowedValues → generic AllowedValuesResource
OSLC4Net_SDK/OSLC4Net.Core/Model/AllowedValuesResource.cs (was AllowedValues.cs)
Replaced string-only AllowedValues with public sealed AllowedValuesResource<T> exposing ICollection<T> AllowedValues, generic AddAllowedValue(T), and [OslcName("AllowedValues")] annotation.
Type/generic helpers
OSLC4Net_SDK/OSLC4Net.Core/Model/InheritedGenericInterfacesHelper.cs, OSLC4Net_SDK/OSLC4Net.Core/Model/TypeFactory.cs
ImplementsGenericInterface now detects direct generic-type matches; TypeFactory.GetName strips generic arity suffix (backtick+digits) when OslcName is absent.
Query result filtering
OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/OslcQueryResult.cs
GetMembers<T>() now filters triples to only rdfs:member predicates whose object is a URI node before wrapping, aligning with member-URL enumeration behavior.
Solution & tests
OSLC4Net_SDK/OSLC4Net.Core.slnx, OSLC4Net_SDK/Tests/OSLC4Net.Core.DotNetRdfProviderTests/AllowedValuesDeserializationTests.cs, .../AllowedValuesSerializationTests.cs
Added example projects to the solution; added deserialization test for AllowedValuesResource<Uri>; updated serialization test to use AllowedValuesResource<string> and assert AllowedValues property.
Jazz client & constants cleanup
OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzFormAuthClient.cs, .../JazzConstants.cs, .../JazzRootServicesConstants.cs, .../Properties/AssemblyInfo.cs
Expanded JazzFormAuthClient API (constructors, getters/setters, FormLoginAsync, redirect handling), flattened constants classes (removed nested wrappers), and removed stray BOM/unused usings.

Sequence Diagram(s)

mermaid
sequenceDiagram
autonumber
participant Sample as EWMSample
participant Oslc as OslcClient
participant Root as RootServices/Catalog
participant SP as ServiceProvider
participant Shapes as ResourceShapes
participant Allowed as AllowedValuesEndpoint

Note over Sample,Oslc: ResolveFiledAgainstAsync (discovery + allowed-values)
Sample->>Oslc: Request CreationFactory URL
Oslc->>Root: GET root services / catalog
Root-->>Oslc: Catalog with CreationFactory refs
Oslc->>SP: GET service provider (providerRef)
SP-->>Oslc: Service provider with CreationFactory(s)
Oslc->>Shapes: GET resource shapes for CreationFactory
Shapes-->>Oslc: Resource shapes graph
Oslc->>Shapes: Locate filedAgainst property → allowedValues ref
Oslc->>Allowed: GET allowed-values resource (allowedValues URL)
Allowed-->>Oslc: RDF/XML AllowedValues payload
Oslc-->>Sample: Deserialize AllowedValuesResource<T> and return chosen value

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Pay attention to: EWMSample.ResolveFiledAgainstAsync (RDF traversal, HTTP calls, allowed-values selection).
  • Verify AllowedValuesResource serialization/deserialization and updated tests (URI vs string element types).
  • Review GetMembers() filter change for downstream consumers expecting non-URI members.
  • Inspect JazzFormAuthClient new public surface and error/redirect handling for backward compatibility.

Possibly related PRs

Poem

🐇 I nibbled through shapes and chased a CVR,

Hopped past redirects, found AllowedValues for me.
Auth now voices errors instead of sighs,
Samples march out with CLI and logs that wise.
A tiny rabbit cheers — new workflows on the lea.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.45% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly and concisely summarizes the main objective: ensuring that sample code fails explicitly when errors occur rather than silently continuing, which aligns with the core changes throughout the PR.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch b-strict-smoke

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov

codecov Bot commented Dec 7, 2025

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 50.69%. Comparing base (fd33042) to head (549992f).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #490      +/-   ##
==========================================
- Coverage   50.72%   50.69%   -0.03%     
==========================================
  Files         169      169              
  Lines       10201    10205       +4     
  Branches     1015     1017       +2     
==========================================
- Hits         5174     5173       -1     
  Misses       4770     4770              
- Partials      257      262       +5     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs (1)

102-110: Parse errors logged but method returns silently.

Same issue as in ETMSample.cs - when there are parsing errors, the method returns without throwing, which means no non-zero exit code is set. Consider throwing an exception for consistency with the PR objective.

             if (parseResult.Errors.Count > 0)
             {
                 foreach (var error in parseResult.Errors)
                 {
                     Console.Error.WriteLine(error.Message);
                 }
 
-                return;
+                throw new ArgumentException("Invalid command-line arguments");
             }
🧹 Nitpick comments (4)
OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/SampleBase.cs (1)

55-70: Rethrowing after logging correctly propagates failures

Adding throw; after logging ensures that any processing error for a given resultsUrl is no longer silently absorbed and instead bubbles up with its original stack trace preserved, which aligns with the PR goal of making samples fail on any error and follows .NET guidance for rethrowing exceptions.

If you want to tighten things further per .NET design and maintainability guidelines, you might consider narrowing catch (Exception e) to the specific exception types you expect from GetResourceRawAsync / ProcessRawResponseAsync (e.g., HttpRequestException, TaskCanceledException), so truly unexpected failures are not handled at this low level. This is optional and can be deferred.

OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ERMSample.cs (1)

18-19: Using directives added for consistency across samples.

The System.CommandLine and System.CommandLine.Invocation namespaces are imported but not directly used in this file's changed code. These appear to be added for consistency with other samples. Consider removing unused imports if dotnet format or analyzers flag them.

Also applies to: 26-26, 29-29

OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs (2)

360-368: Property matching uses loose string comparison.

The check defString.Contains("filedAgainst", StringComparison.OrdinalIgnoreCase) could match unrelated properties that happen to contain "filedAgainst" as a substring. The EndsWith check is more precise, but the Contains fallback is overly permissive.

Consider using only the EndsWith check or matching against a known URI pattern:

-                        if (defString.EndsWith("filedAgainst", StringComparison.OrdinalIgnoreCase) || defString.Contains("filedAgainst", StringComparison.OrdinalIgnoreCase))
+                        if (defString.EndsWith("filedAgainst", StringComparison.OrdinalIgnoreCase))

411-416: Fallback logic has redundant condition.

The if (values.Length > 0) check on line 412 is always true at this point because the enclosing if on line 397 already verified values.Length > 0. This is dead code.

                             // Fallback to first if all seem unassigned or check failed
-                            if (values.Length > 0)
-                            {
-                                Logger.LogInformation("Using fallback Filed Against category: {Category}", values[0]);
-                                return new Uri(values[0]);
-                            }
+                            Logger.LogInformation("Using fallback Filed Against category: {Category}", values[0]);
+                            return new Uri(values[0]);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7e4de88 and bc4e544.

📒 Files selected for processing (6)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ERMSample.cs (3 hunks)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs (3 hunks)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs (4 hunks)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/Program.cs (3 hunks)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/Properties/AssemblyInfo.cs (1 hunks)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/SampleBase.cs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.cs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.cs: Follow Microsoft .NET design guidelines (https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/) for code style
Run dotnet format before commit to maintain code formatting consistency
Use C# 14 with nullable reference types enabled
Follow .NET code analysis and Meziantou.Analyzer rules

Files:

  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/Properties/AssemblyInfo.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/SampleBase.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/Program.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ERMSample.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs

⚙️ CodeRabbit configuration file

**/*.cs: Review the C# code against the Microsoft Framework design guidelines as well as 10 guidelines
from "Building Maintainable Software" by Joost Visser. Point out deviations and improvements.

Files:

  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/Properties/AssemblyInfo.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/SampleBase.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/Program.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ERMSample.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs
🧬 Code graph analysis (2)
OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs (4)
OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzFormAuthClient.cs (5)
  • JazzFormAuthClient (30-230)
  • JazzFormAuthClient (43-47)
  • JazzFormAuthClient (56-63)
  • JazzFormAuthClient (75-79)
  • HttpResponseMessage (207-229)
OSLC4Net_SDK/OSLC4Net.Client/Oslc/OSLCConstants.cs (1)
  • OSLCConstants (21-148)
OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/OslcQuery.cs (7)
  • OslcQuery (24-219)
  • OslcQuery (48-53)
  • OslcQuery (61-65)
  • OslcQuery (73-76)
  • OslcQuery (85-110)
  • OslcQuery (112-115)
  • OslcQuery (117-122)
OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/OslcQueryResult.cs (4)
  • OslcQueryResult (33-417)
  • OslcQueryResult (62-70)
  • OslcQueryResult (72-80)
  • HttpResponseMessage (281-284)
OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ERMSample.cs (2)
OSLC4Net_SDK/OSLC4Net.Core.DotNetRdfProvider/Extensions.cs (1)
  • Extensions (7-67)
OSLC4Net_NETFramework/OSLC4Net.StockQuoteSample/Areas/HelpPage/SampleGeneration/HelpPageSampleGenerator.cs (1)
  • Exception (357-365)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: smoke-test
  • GitHub Check: CodeQL analysis (csharp)
  • GitHub Check: Agent
  • GitHub Check: test (ubuntu-24.04, 10.x, net10.0)
  • GitHub Check: test (windows-latest, 10.x, net10.0)
  • GitHub Check: Analyze (csharp)
🔇 Additional comments (8)
OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/Properties/AssemblyInfo.cs (1)

1-1: LGTM: BOM character removal.

Removing the stray Byte Order Mark (BOM) character is a good cleanup that prevents potential encoding issues and aligns with .NET formatting best practices.

OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/Program.cs (2)

36-41: Improved error messaging for missing sample types.

Good improvement to provide clearer feedback when a sample type is not found. The error message now includes the specific sample name that failed to resolve and displays usage instructions.


53-65: Exception handling correctly propagates errors to exit code.

The try-catch properly unwraps TargetInvocationException via ex.InnerException and exits with a non-zero code, aligning with the PR objective to fail on errors.

OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ERMSample.cs (1)

338-347: Authentication failure now throws instead of silently continuing.

Good change. The InvalidOperationException with a descriptive message ensures the sample fails fast on authentication failure, and the rethrow in the catch block ensures the exception propagates to the caller. This aligns with the PR objective.

OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs (1)

195-209: Authentication failure and exception handling correctly implemented.

The pattern of throwing InvalidOperationException on auth failure and rethrowing exceptions after logging is consistent across samples. The specific catch for RootServicesException provides targeted error messaging. This correctly implements fail-fast behavior per the PR objective.

OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs (3)

217-221: Creation failure now throws instead of returning.

Good improvement. The change from early return to throwing InvalidOperationException with the HTTP status code and error details ensures the sample fails visibly on creation errors.


246-260: Authentication failure and exception propagation correctly implemented.

The pattern matches the other samples: throw on auth failure, log then rethrow in catch blocks. This ensures errors propagate to Program.cs for proper exit code handling.


280-291: ResolveFiledAgainstAsync catches errors and returns null.

This method returns null on errors rather than propagating exceptions. While this is intentional (the caller logs a warning and continues), it's inconsistent with the PR's goal of ensuring failures are explicit. Consider whether resolution failures should be propagated as exceptions when the PR objective is to "ensure samples fail if there is any error."

The current behavior allows the sample to continue and potentially fail with a 403 error during creation. If strict error handling is desired, consider making this a throwing method or having the caller throw when resolution fails.

Comment thread OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs
Comment on lines +76 to +85
var parseResult = rootCommand.Parse(args);
if (parseResult.Errors.Count > 0)
{
foreach (var error in parseResult.Errors)
{
Console.Error.WriteLine(error.Message);
}

return;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Parse errors are logged but method returns silently.

When parseResult.Errors.Count > 0, errors are written to stderr and the method returns. However, this doesn't set a non-zero exit code. Since Program.cs catches exceptions and calls Environment.Exit(1), consider throwing an exception here instead of returning silently to ensure proper exit code propagation.

             if (parseResult.Errors.Count > 0)
             {
                 foreach (var error in parseResult.Errors)
                 {
                     Console.Error.WriteLine(error.Message);
                 }
 
-                return;
+                throw new ArgumentException("Invalid command-line arguments");
             }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var parseResult = rootCommand.Parse(args);
if (parseResult.Errors.Count > 0)
{
foreach (var error in parseResult.Errors)
{
Console.Error.WriteLine(error.Message);
}
return;
}
var parseResult = rootCommand.Parse(args);
if (parseResult.Errors.Count > 0)
{
foreach (var error in parseResult.Errors)
{
Console.Error.WriteLine(error.Message);
}
throw new ArgumentException("Invalid command-line arguments");
}
🤖 Prompt for AI Agents
In OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs around lines 76 to
85, the parser writes errors to stderr then returns silently which prevents
Program.cs from exiting with a non-zero code; instead, aggregate the parse error
messages into a single descriptive message and throw an exception (e.g.,
ArgumentException or InvalidOperationException) with that message so the caller
can catch it and Environment.Exit(1) will be triggered.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR improves error handling in OSLC sample code by ensuring that exceptions are not silently swallowed. It replaces silent failures with explicit exception re-throwing after logging, adds authentication failure exceptions, and reorganizes using statements for better readability and consistency.

Key Changes

  • Added throw; statements after error logging to propagate exceptions instead of silently failing
  • Introduced explicit InvalidOperationException when authentication fails
  • Added status code validation for change request creation in EWMSample with descriptive error message
  • Reorganized using statements alphabetically by namespace within groups (System, Microsoft, OSLC4Net, third-party)

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
SampleBase.cs Added exception re-throw after logging errors during artifact processing
AssemblyInfo.cs Removed leading whitespace from first using statement
Program.cs Cleaned up trailing whitespace on multiple lines for consistency
EWMSample.cs Reorganized using statements, added exception re-throws, added explicit authentication failure exception, and added HTTP status validation for change request creation
ETMSample.cs Reorganized using statements, replaced tabs with spaces for consistent indentation, added exception re-throws, and added explicit authentication failure exception
ERMSample.cs Reorganized using statements, added exception re-throw after error logging, and added explicit authentication failure exception

HttpResponseMessage creationResponse = await client.CreateResourceRawAsync(
testcaseCreation, testcase,
OslcMediaType.APPLICATION_RDF_XML);
creationResponse.ConsumeContent();

Copilot AI Dec 7, 2025

Copy link

Choose a reason for hiding this comment

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

The test case creation response status is not being checked before accessing the Location header. Unlike the change made in EWMSample.cs (line 217-221), this code should validate that creationResponse.StatusCode == HttpStatusCode.Created before accessing creationResponse.Headers.Location.

Consider adding a status check similar to EWMSample.cs:

if (creationResponse.StatusCode != HttpStatusCode.Created)
{
    String errorString = await creationResponse.Content.ReadAsStringAsync();
    throw new InvalidOperationException($"Failed to create test case (HTTP {creationResponse.StatusCode}): {errorString}");
}
Suggested change
creationResponse.ConsumeContent();
creationResponse.ConsumeContent();
if (creationResponse.StatusCode != HttpStatusCode.Created)
{
String errorString = await creationResponse.Content.ReadAsStringAsync();
throw new InvalidOperationException($"Failed to create test case (HTTP {creationResponse.StatusCode}): {errorString}");
}

Copilot uses AI. Check for mistakes.
}
catch (RootServicesException re)
{
Logger.LogError(re, "Unable to access the Jazz rootservices document at: " + webContextUrl + "/rootservices");

Copilot AI Dec 7, 2025

Copy link

Choose a reason for hiding this comment

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

String concatenation is used here instead of structured logging placeholders. For consistency with structured logging best practices and the pattern used in ETMSample.cs (line 202), this should use a placeholder:

Logger.LogError(re, "Unable to access the Jazz rootservices document at: {Url}", webContextUrl + "/rootservices");
Suggested change
Logger.LogError(re, "Unable to access the Jazz rootservices document at: " + webContextUrl + "/rootservices");
Logger.LogError(re, "Unable to access the Jazz rootservices document at: {Url}", webContextUrl + "/rootservices");

Copilot uses AI. Check for mistakes.
Comment on lines 402 to 409
foreach (var val in values)
{
if (!val.Contains("Unassigned", StringComparison.OrdinalIgnoreCase))
{
Logger.LogInformation("Using fallback Filed Against category: {Category}", values[0]);
return new Uri(values[0]);
Logger.LogInformation("Resolved Filed Against category: {Category}", val);
return new Uri(val);
}
}

Copilot AI Dec 7, 2025

Copy link

Choose a reason for hiding this comment

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

This foreach loop implicitly filters its target sequence - consider filtering the sequence explicitly using '.Where(...)'.

Copilot uses AI. Check for mistakes.
//Get the Creation Factory URL for test cases so that we can create a test case
String testcaseCreation = await client.LookupCreationFactoryAsync(
serviceProviderUrl, OSLCConstants.OSLC_QM_V2,
testcase.GetRdfTypes()[0].ToString());

Copilot AI Dec 7, 2025

Copy link

Choose a reason for hiding this comment

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

Call to obsolete method GetRdfTypes.

Suggested change
testcase.GetRdfTypes()[0].ToString());
testcase.RdfTypes.First().ToString());

Copilot uses AI. Check for mistakes.
//Get the Creation Factory URL for change requests so that we can create one
String changeRequestCreation = await client.LookupCreationFactoryAsync(
serviceProviderUrl, OSLCConstants.OSLC_CM_V2,
changeRequest.GetRdfTypes()[0].ToString());

Copilot AI Dec 7, 2025

Copy link

Choose a reason for hiding this comment

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

Call to obsolete method GetRdfTypes.

Suggested change
changeRequest.GetRdfTypes()[0].ToString());
changeRequest.RdfTypes[0].ToString());

Copilot uses AI. Check for mistakes.
string creationFactoryUrl = await client.LookupCreationFactoryAsync(
serviceProviderUrl,
OSLCConstants.OSLC_CM_V2,
changeRequest.GetRdfTypes()[0].ToString());

Copilot AI Dec 7, 2025

Copy link

Choose a reason for hiding this comment

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

Call to obsolete method GetRdfTypes.

Suggested change
changeRequest.GetRdfTypes()[0].ToString());
changeRequest.RdfTypes[0].ToString());

Copilot uses AI. Check for mistakes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (1)
OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs (1)

253-253: Use structured logging placeholders instead of string concatenation.

This was flagged in a previous review. Use placeholders for consistency with structured logging best practices.

-                Logger.LogError(re, "Unable to access the Jazz rootservices document at: " + webContextUrl + "/rootservices");
+                Logger.LogError(re, "Unable to access the Jazz rootservices document at: {Url}", webContextUrl + "/rootservices");
🧹 Nitpick comments (1)
OSLC4Net_SDK/OSLC4Net.Core/Model/AllowedValuesResource.cs (1)

13-13: Consider nullable handling for About property.

Using null! suppresses compiler warnings but doesn't prevent runtime NullReferenceException if About is accessed before SetAbout is called. Consider either:

  1. Making the property nullable: Uri? About { get; set; }
  2. Requiring initialization via constructor
-    public Uri About { get; set; } = null!;
+    public Uri? About { get; set; }

If nullable, update GetAbout() accordingly:

-    public Uri GetAbout() => About;
+    public Uri? GetAbout() => About;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bc4e544 and eb6c59d.

📒 Files selected for processing (8)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs (4 hunks)
  • OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/OslcQueryResult.cs (1 hunks)
  • OSLC4Net_SDK/OSLC4Net.Core.slnx (1 hunks)
  • OSLC4Net_SDK/OSLC4Net.Core/Model/AllowedValuesResource.cs (1 hunks)
  • OSLC4Net_SDK/OSLC4Net.Core/Model/InheritedGenericInterfacesHelper.cs (1 hunks)
  • OSLC4Net_SDK/OSLC4Net.Core/Model/TypeFactory.cs (1 hunks)
  • OSLC4Net_SDK/Tests/OSLC4Net.Core.DotNetRdfProviderTests/AllowedValuesDeserializationTests.cs (1 hunks)
  • OSLC4Net_SDK/Tests/OSLC4Net.Core.DotNetRdfProviderTests/AllowedValuesSerializationTests.cs (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.cs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.cs: Follow Microsoft .NET design guidelines (https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/) for code style
Run dotnet format before commit to maintain code formatting consistency
Use C# 14 with nullable reference types enabled
Follow .NET code analysis and Meziantou.Analyzer rules

Files:

  • OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/OslcQueryResult.cs
  • OSLC4Net_SDK/Tests/OSLC4Net.Core.DotNetRdfProviderTests/AllowedValuesDeserializationTests.cs
  • OSLC4Net_SDK/Tests/OSLC4Net.Core.DotNetRdfProviderTests/AllowedValuesSerializationTests.cs
  • OSLC4Net_SDK/OSLC4Net.Core/Model/TypeFactory.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs
  • OSLC4Net_SDK/OSLC4Net.Core/Model/AllowedValuesResource.cs
  • OSLC4Net_SDK/OSLC4Net.Core/Model/InheritedGenericInterfacesHelper.cs

⚙️ CodeRabbit configuration file

**/*.cs: Review the C# code against the Microsoft Framework design guidelines as well as 10 guidelines
from "Building Maintainable Software" by Joost Visser. Point out deviations and improvements.

Files:

  • OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/OslcQueryResult.cs
  • OSLC4Net_SDK/Tests/OSLC4Net.Core.DotNetRdfProviderTests/AllowedValuesDeserializationTests.cs
  • OSLC4Net_SDK/Tests/OSLC4Net.Core.DotNetRdfProviderTests/AllowedValuesSerializationTests.cs
  • OSLC4Net_SDK/OSLC4Net.Core/Model/TypeFactory.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs
  • OSLC4Net_SDK/OSLC4Net.Core/Model/AllowedValuesResource.cs
  • OSLC4Net_SDK/OSLC4Net.Core/Model/InheritedGenericInterfacesHelper.cs
**/Tests/**/*.cs

📄 CodeRabbit inference engine (AGENTS.md)

**/Tests/**/*.cs: Use TUnit for unit tests
Prefer Verify and round-tripping checks when dealing with RDF data in tests
When creating multiline dummy data in tests, prefer triple-quoted strings (""")
Follow Microsoft .NET unit testing best practices (https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices)

Files:

  • OSLC4Net_SDK/Tests/OSLC4Net.Core.DotNetRdfProviderTests/AllowedValuesDeserializationTests.cs
  • OSLC4Net_SDK/Tests/OSLC4Net.Core.DotNetRdfProviderTests/AllowedValuesSerializationTests.cs
🧠 Learnings (1)
📚 Learning: 2025-11-29T19:12:48.610Z
Learnt from: CR
Repo: OSLC/oslc4net PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-29T19:12:48.610Z
Learning: Applies to **/Tests/**/*.cs : Prefer Verify and round-tripping checks when dealing with RDF data in tests

Applied to files:

  • OSLC4Net_SDK/Tests/OSLC4Net.Core.DotNetRdfProviderTests/AllowedValuesDeserializationTests.cs
  • OSLC4Net_SDK/Tests/OSLC4Net.Core.DotNetRdfProviderTests/AllowedValuesSerializationTests.cs
🧬 Code graph analysis (2)
OSLC4Net_SDK/Tests/OSLC4Net.Core.DotNetRdfProviderTests/AllowedValuesDeserializationTests.cs (3)
OSLC4Net_SDK/OSLC4Net.Core/Model/OslcMediaType.cs (1)
  • OslcMediaType (24-63)
OSLC4Net_SDK/Tests/OSLC4Net.Core.DotNetRdfProviderTests/RdfHelpers.cs (1)
  • RdfHelpers (4-83)
OSLC4Net_SDK/OSLC4Net.Core/Model/AllowedValuesResource.cs (1)
  • Uri (20-20)
OSLC4Net_SDK/OSLC4Net.Core/Model/AllowedValuesResource.cs (4)
OSLC4Net_SDK/OSLC4Net.Core/Attribute/OslcOccurs.cs (1)
  • OslcOccurs (33-36)
OSLC4Net_SDK/OSLC4Net.Core/Attribute/OslcPropertyDefinition.cs (1)
  • OslcPropertyDefinition (31-34)
OSLC4Net_SDK/OSLC4Net.Core/Attribute/OslcTitle.cs (1)
  • OslcTitle (32-35)
OSLC4Net_SDK/OSLC4Net.Core/Model/ResponseInfoCollection.cs (1)
  • ICollection (60-63)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: test (ubuntu-24.04, 10.x, net10.0)
  • GitHub Check: Analyze (csharp)
🔇 Additional comments (6)
OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/OslcQueryResult.cs (1)

342-348: Excellent consistency fix aligning member filtering logic.

The filtering in GetMembers<T>() now matches GetMembersUrls() exactly: both filter triples to include only those with rdfs:member predicates and IUriNode objects. This makes the implicit behavior explicit and prevents potential casting errors when processing members downstream.

The filter logic at lines 343-346 correctly mirrors GetMembersUrls() (lines 303-307), ensuring consistent member retrieval across both methods. This is a correctness improvement, not a refactor—the filtering ensures only valid URI objects are enumerated, preventing downstream exceptions from non-URI triple objects.

No breaking changes expected: non-URI members would have failed during enumeration anyway; this change simply makes the constraint explicit.

OSLC4Net_SDK/OSLC4Net.Core.slnx (1)

8-9: LGTM!

The addition of the two new example projects to the solution is consistent with the existing structure and ordering.

OSLC4Net_SDK/OSLC4Net.Core/Model/InheritedGenericInterfacesHelper.cs (1)

27-31: LGTM!

The early return for direct generic type matching correctly handles the case where typeToTest is itself the generic type definition (e.g., ICollection<string> matching ICollection<>). This supplements the interface iteration logic appropriately.

OSLC4Net_SDK/OSLC4Net.Core/Model/AllowedValuesResource.cs (1)

22-28: LGTM!

The AllowedValues property is well-defined with appropriate OSLC attributes. The collection initialization with [] follows modern C# conventions.

OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs (1)

246-260: LGTM - Improved error handling with explicit exceptions.

The changes correctly implement the PR objective: authentication failures now throw InvalidOperationException instead of silently failing, and exceptions are properly rethrown after logging.

OSLC4Net_SDK/OSLC4Net.Core/Model/TypeFactory.cs (1)

46-54: LGTM!

The refactored GetName method correctly handles generic type names by stripping the arity suffix (e.g., `1). The fallback logic using IndexOf and range operator is clean and idiomatic C#.

Comment on lines +426 to +429
catch (Exception ex)
{
Logger.LogError(ex, "Failed to deserialize AllowedValues");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Exception swallowed silently contradicts PR objective.

This catch block logs but doesn't rethrow the exception, which contradicts the PR objective to "ensure samples fail if there is any error." The deserialization failure is silently swallowed.

Consider rethrowing to align with the PR's error handling approach:

                    catch (Exception ex)
                    {
                        Logger.LogError(ex, "Failed to deserialize AllowedValues");
+                       throw;
                    }

Alternatively, if this is intentionally lenient to allow the loop to continue trying other shapes, document this decision explicitly.

🤖 Prompt for AI Agents
In OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs around lines
426-429, the catch block logs deserialization errors for AllowedValues but
swallows the exception; change behavior to rethrow the exception (or throw a new
exception with context) after logging so the sample fails on error per the PR
objective, or if swallowing was intentional, add a clear comment explaining why
and keep the exception suppressed; ensure the chosen approach is implemented
consistently and preserves the original exception stack (use throw; or include
the caught exception when throwing a new one).

Comment thread OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs Outdated
Comment on lines +32 to +40
var allowedValues = await RdfHelpers.DeserializeAsync<AllowedValuesResource<Uri>>(formatter, SamplePayload, mediaType);

// Assert
await Assert.That(allowedValues).IsNotNull();
await Assert.That(allowedValues!.AllowedValues).HasCount().EqualTo(4);

await Assert.That(allowedValues.AllowedValues)
.Contains(new Uri("https://jazz.net/sandbox01-ccm/resource/itemOid/com.ibm.team.workitem.Category/_Kt2WgH3QEfC-rJM7pd93jg"));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Promote allowedValues to a non-null local after assertion and reuse it

RdfHelpers.DeserializeAsync<AllowedValuesResource<Uri>> returns a nullable type, and while line 36 uses allowedValues!, line 38 dereferences allowedValues without the null-forgiving operator, which will trip nullable analysis.

You can both simplify the code and satisfy nullable checks by introducing a non-null local after the not-null assertion and using it for subsequent assertions:

-        await Assert.That(allowedValues).IsNotNull();
-        await Assert.That(allowedValues!.AllowedValues).HasCount().EqualTo(4);
-
-        await Assert.That(allowedValues.AllowedValues)
+        await Assert.That(allowedValues).IsNotNull();
+        var nonNullAllowedValues = allowedValues!;
+        await Assert.That(nonNullAllowedValues.AllowedValues).HasCount().EqualTo(4);
+
+        await Assert.That(nonNullAllowedValues.AllowedValues)
             .Contains(new Uri("https://jazz.net/sandbox01-ccm/resource/itemOid/com.ibm.team.workitem.Category/_Kt2WgH3QEfC-rJM7pd93jg"));

This keeps runtime semantics unchanged while aligning with nullable reference type expectations.

As an optional enhancement, you might also consider adding a Verify(...) or a serialize–deserialize round-trip assertion for allowedValues to further exercise the RDF pipeline, in line with the RDF testing preference in this repo. Based on learnings, tests dealing with RDF often benefit from such round-tripping checks.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var allowedValues = await RdfHelpers.DeserializeAsync<AllowedValuesResource<Uri>>(formatter, SamplePayload, mediaType);
// Assert
await Assert.That(allowedValues).IsNotNull();
await Assert.That(allowedValues!.AllowedValues).HasCount().EqualTo(4);
await Assert.That(allowedValues.AllowedValues)
.Contains(new Uri("https://jazz.net/sandbox01-ccm/resource/itemOid/com.ibm.team.workitem.Category/_Kt2WgH3QEfC-rJM7pd93jg"));
}
var allowedValues = await RdfHelpers.DeserializeAsync<AllowedValuesResource<Uri>>(formatter, SamplePayload, mediaType);
// Assert
await Assert.That(allowedValues).IsNotNull();
var nonNullAllowedValues = allowedValues!;
await Assert.That(nonNullAllowedValues.AllowedValues).HasCount().EqualTo(4);
await Assert.That(nonNullAllowedValues.AllowedValues)
.Contains(new Uri("https://jazz.net/sandbox01-ccm/resource/itemOid/com.ibm.team.workitem.Category/_Kt2WgH3QEfC-rJM7pd93jg"));
}
🤖 Prompt for AI Agents
In
OSLC4Net_SDK/Tests/OSLC4Net.Core.DotNetRdfProviderTests/AllowedValuesDeserializationTests.cs
around lines 32 to 40, after asserting allowedValues is not null, promote it to
a non-null local and use that local for subsequent assertions to satisfy
nullable analysis; specifically, immediately after await
Assert.That(allowedValues).IsNotNull(); assign a new non-null local (e.g., var
av = allowedValues!;) and replace later uses of allowedValues with av so you no
longer need the null-forgiving operator elsewhere.

Comment on lines +24 to 33
var deserialized = await RdfHelpers.DeserializeAsync<AllowedValuesResource<string>>(formatter, rdfXml, mediaType);

// Assert
await Assert.That(deserialized).IsNotNull();
await Assert.That(deserialized.GetAllowedValues()).HasCount().EqualTo(allowedValues.GetAllowedValues().Length);
await Assert.That(deserialized.AllowedValues).HasCount().EqualTo(allowedValues.AllowedValues.Count);

foreach (var val in allowedValues.GetAllowedValues())
foreach (var val in allowedValues.AllowedValues)
{
await Assert.That(deserialized.GetAllowedValues()).Contains(val);
await Assert.That(deserialized.AllowedValues).Contains(val);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Use null-forgiving on deserialized to satisfy nullable analysis

RdfHelpers.DeserializeAsync<AllowedValuesResource<string>> returns a nullable reference (AllowedValuesResource<string>?), so subsequent dereferences of deserialized will trigger nullable warnings even after the IsNotNull assertion.

You can keep the runtime behavior as-is and make the intent explicit to analyzers by using the null-forgiving operator on dereferences:

-        await Assert.That(deserialized.AllowedValues).HasCount().EqualTo(allowedValues.AllowedValues.Count);
+        await Assert.That(deserialized!.AllowedValues).HasCount().EqualTo(allowedValues.AllowedValues.Count);
@@
-        foreach (var val in allowedValues.AllowedValues)
+        foreach (var val in allowedValues.AllowedValues)
         {
-            await Assert.That(deserialized.AllowedValues).Contains(val);
+            await Assert.That(deserialized!.AllowedValues).Contains(val);
         }

This keeps the test behavior unchanged while aligning with nullable reference type expectations.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var deserialized = await RdfHelpers.DeserializeAsync<AllowedValuesResource<string>>(formatter, rdfXml, mediaType);
// Assert
await Assert.That(deserialized).IsNotNull();
await Assert.That(deserialized.GetAllowedValues()).HasCount().EqualTo(allowedValues.GetAllowedValues().Length);
await Assert.That(deserialized.AllowedValues).HasCount().EqualTo(allowedValues.AllowedValues.Count);
foreach (var val in allowedValues.GetAllowedValues())
foreach (var val in allowedValues.AllowedValues)
{
await Assert.That(deserialized.GetAllowedValues()).Contains(val);
await Assert.That(deserialized.AllowedValues).Contains(val);
}
var deserialized = await RdfHelpers.DeserializeAsync<AllowedValuesResource<string>>(formatter, rdfXml, mediaType);
// Assert
await Assert.That(deserialized).IsNotNull();
await Assert.That(deserialized!.AllowedValues).HasCount().EqualTo(allowedValues.AllowedValues.Count);
foreach (var val in allowedValues.AllowedValues)
{
await Assert.That(deserialized!.AllowedValues).Contains(val);
}
🤖 Prompt for AI Agents
In
OSLC4Net_SDK/Tests/OSLC4Net.Core.DotNetRdfProviderTests/AllowedValuesSerializationTests.cs
around lines 24 to 33, the variable returned by RdfHelpers.DeserializeAsync is
nullable so subsequent dereferences trigger nullable analysis warnings; update
the assertions and foreach to use the null-forgiving operator on deserialized
(e.g. use deserialized!.AllowedValues and Assert.That(deserialized!).IsNotNull()
where appropriate) so the analyzer knows the value is non-null after the
IsNotNull assertion while keeping runtime behavior unchanged.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (7)
OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzFormAuthClient.cs (7)

25-25: Remove unnecessary using directive.

The Microsoft.Extensions.Logging.Abstractions namespace is not used in this file.

-using Microsoft.Extensions.Logging.Abstractions;

28-28: Convert to file-scoped namespace.

File-scoped namespaces reduce indentation and are a modern C# best practice.

-namespace OSLC4Net.Client.Oslc.Jazz
-{
+namespace OSLC4Net.Client.Oslc.Jazz;
+

38-39: Use lowercase string keyword for constants.

Consistent with .NET design guidelines, use the lowercase string keyword instead of String.

-        private const String JAZZ_AUTH_MESSAGE_HEADER = "X-com-ibm-team-repository-web-auth-msg";
-        private const String JAZZ_AUTH_FAILED = "authfailed";
+        private const string JAZZ_AUTH_MESSAGE_HEADER = "X-com-ibm-team-repository-web-auth-msg";
+        private const string JAZZ_AUTH_FAILED = "authfailed";

191-198: Remove redundant catch-and-rethrow blocks.

Catching specific exceptions only to immediately rethrow them serves no purpose. These blocks can be safely removed, allowing the exceptions to propagate naturally.

-            catch (JazzAuthFailedException jfe)
-            {
-                throw jfe;
-            }
-            catch (JazzAuthErrorException jee)
-            {
-                throw jee;
-            }
             catch (Exception e)
             {
                 _logger.LogError(e, "Error during login");
+                throw;
             }

132-132: Remove unnecessary variable initialization.

The location variable is assigned null but is unconditionally assigned before use at line 143 or 185.

-            String location = null;
+            String location;

215-215: Simplify null check with null-coalescing operator.

The ternary operator can be simplified using the null-coalescing operator.

-                    location = (newResp.Headers.Location != null) ? newResp.Headers.Location.AbsoluteUri : null;
+                    location = newResp.Headers.Location?.AbsoluteUri;

227-252: Remove unused private method.

Static analysis indicates this method is never called. Consider removing it to reduce code maintenance burden.

If this method is intended for future use, it should be made async and its exception handling should be fixed to rethrow exceptions after logging (see separate comment).

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eb6c59d and 280b832.

📒 Files selected for processing (5)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzConstants.cs (1 hunks)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzFormAuthClient.cs (4 hunks)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzRootServicesConstants.cs (1 hunks)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Properties/AssemblyInfo.cs (1 hunks)
  • OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/OslcQueryResult.cs (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzRootServicesConstants.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzConstants.cs
🚧 Files skipped from review as they are similar to previous changes (1)
  • OSLC4Net_SDK/OSLC4Net.Client/Oslc/Resources/OslcQueryResult.cs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.cs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.cs: Follow Microsoft .NET design guidelines (https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/) for code style
Run dotnet format before commit to maintain code formatting consistency
Use C# 14 with nullable reference types enabled
Follow .NET code analysis and Meziantou.Analyzer rules

Files:

  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Properties/AssemblyInfo.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzFormAuthClient.cs

⚙️ CodeRabbit configuration file

**/*.cs: Review the C# code against the Microsoft Framework design guidelines as well as 10 guidelines
from "Building Maintainable Software" by Joost Visser. Point out deviations and improvements.

Files:

  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Properties/AssemblyInfo.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzFormAuthClient.cs
🧬 Code graph analysis (1)
OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzFormAuthClient.cs (3)
OSLC4Net_SDK/OSLC4Net.Client/Oslc/OslcClient.cs (1)
  • ConsumeContent (900-903)
OSLC4Net_SDK/OSLC4Net.Client/Exceptions/JazzAuthFailedException.cs (1)
  • JazzAuthFailedException (19-32)
OSLC4Net_SDK/OSLC4Net.Client/Exceptions/JazzAuthErrorException.cs (1)
  • JazzAuthErrorException (21-34)
🪛 GitHub Check: Format (dotnet format)
OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzFormAuthClient.cs

[warning] 25-25:
Using directive is unnecessary.


[warning] 22-22:
Using directive is unnecessary.


[warning] 20-20:
Using directive is unnecessary.


[warning] 28-28:
Convert to file-scoped namespace


[warning] 132-132:
Unnecessary assignment of a value to 'location'


[warning] 215-215:
Null check can be simplified


[warning] 227-227:
Private member 'JazzFormAuthClient.GetArtifactFeed' is unused

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (csharp)
  • GitHub Check: test (ubuntu-24.04, 10.x, net10.0)
🔇 Additional comments (1)
OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Properties/AssemblyInfo.cs (1)

1-1: BOM removal and using directive look good

The invisible BOM cleanup on Line 1 is harmless and improves consistency; no issues with the using directives or assembly attributes as written.

Comment on lines +32 to +37
private String url;
private String authUrl;
private String project;
private String user;
private String password;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Use lowercase string keyword and add nullable annotations.

According to .NET design guidelines, use the lowercase string keyword instead of String. Additionally, with nullable reference types enabled (per coding guidelines), these fields should be properly annotated or initialized to avoid potential null reference warnings.

As per coding guidelines, C# 14 with nullable reference types is enabled.

-        private String url;
-        private String authUrl;
-        private String project;
-        private String user;
-        private String password;
+        private string? url;
+        private string? authUrl;
+        private string? project;
+        private string? user;
+        private string? password;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private String url;
private String authUrl;
private String project;
private String user;
private String password;
private string? url;
private string? authUrl;
private string? project;
private string? user;
private string? password;
🤖 Prompt for AI Agents
In OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzFormAuthClient.cs
around lines 32 to 37, the fields are declared using the System.String type
without nullable annotations; change them to use the lowercase string keyword
and either initialize them or add nullable annotations (string? for fields that
may be null) to satisfy nullable reference type rules. Update declarations for
url, authUrl, project, user, and password to use string or string? as
appropriate and ensure any code that assumes non-null values either initializes
these fields or checks for null before use.

Comment on lines +81 to +123
public String GetUrl()
{
return url;
}
public void SetUrl(String url)
{
this.url = url;
}

public String GetAuthUrl()
{
return authUrl;
}

public void SetAuthUrl(String authUrl)
{
this.authUrl = authUrl;
}

public String GetProject()
{
return project;
}
public void SetProject(String project)
{
this.project = project;
}
public String GetUser()
{
return user;
}
public void SetUser(String user)
{
this.user = user;
}
public String GetPassword()
{
return password;
}
public void SetPassword(String password)
{
this.password = password;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Replace Java-style getters/setters with C# properties.

This code violates Microsoft .NET design guidelines by using Java-style getter/setter methods instead of C# properties. Properties are the idiomatic C# approach and provide better syntax, IntelliSense support, and integration with data binding and serialization frameworks.

As per coding guidelines, follow Microsoft .NET design guidelines.

-        public String GetUrl()
-        {
-            return url;
-        }
-        public void SetUrl(String url)
-        {
-            this.url = url;
-        }
-
-        public String GetAuthUrl()
-        {
-            return authUrl;
-        }
-
-        public void SetAuthUrl(String authUrl)
-        {
-            this.authUrl = authUrl;
-        }
-
-        public String GetProject()
-        {
-            return project;
-        }
-        public void SetProject(String project)
-        {
-            this.project = project;
-        }
-        public String GetUser()
-        {
-            return user;
-        }
-        public void SetUser(String user)
-        {
-            this.user = user;
-        }
-        public String GetPassword()
-        {
-            return password;
-        }
-        public void SetPassword(String password)
-        {
-            this.password = password;
-        }
+        public string? Url 
+        { 
+            get => url; 
+            set => url = value; 
+        }
+
+        public string? AuthUrl 
+        { 
+            get => authUrl; 
+            set => authUrl = value; 
+        }
+
+        public string? Project 
+        { 
+            get => project; 
+            set => project = value; 
+        }
+
+        public string? User 
+        { 
+            get => user; 
+            set => user = value; 
+        }
+
+        public string? Password 
+        { 
+            get => password; 
+            set => password = value; 
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public String GetUrl()
{
return url;
}
public void SetUrl(String url)
{
this.url = url;
}
public String GetAuthUrl()
{
return authUrl;
}
public void SetAuthUrl(String authUrl)
{
this.authUrl = authUrl;
}
public String GetProject()
{
return project;
}
public void SetProject(String project)
{
this.project = project;
}
public String GetUser()
{
return user;
}
public void SetUser(String user)
{
this.user = user;
}
public String GetPassword()
{
return password;
}
public void SetPassword(String password)
{
this.password = password;
}
public string? Url
{
get => url;
set => url = value;
}
public string? AuthUrl
{
get => authUrl;
set => authUrl = value;
}
public string? Project
{
get => project;
set => project = value;
}
public string? User
{
get => user;
set => user = value;
}
public string? Password
{
get => password;
set => password = value;
}
🤖 Prompt for AI Agents
In OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzFormAuthClient.cs
around lines 81 to 123, replace the Java-style Get*/Set* methods with idiomatic
C# properties: remove the explicit GetX/SetX methods and expose public
properties with PascalCase (e.g., public string Url { get; set; }) backed by the
existing private fields or convert fields to auto-properties if no extra logic
is needed; ensure naming follows .NET conventions (Url, AuthUrl, Project, User,
Password) and preserve existing accessibility and behavior so callers can use
obj.Url instead of obj.GetUrl().

Comment on lines 191 to 202
catch (JazzAuthFailedException jfe)
{
throw jfe;
}
catch (JazzAuthErrorException jee)
{
throw jee;
}
catch (Exception e)
{
_logger.LogError(e, "Error during login");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Exception not rethrown after logging.

The catch block at lines 199-202 logs the exception but does not rethrow it, which swallows the exception and violates the PR objective: "ensures exceptions are rethrown after logging." This means authentication failures will silently return the default HttpStatusCode.Unused instead of propagating the error.

             catch (JazzAuthErrorException jee)
             {
                 throw jee;
             }
             catch (Exception e)
             {
                 _logger.LogError(e, "Error during login");
+                throw;
             }
             return statusCode;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
catch (JazzAuthFailedException jfe)
{
throw jfe;
}
catch (JazzAuthErrorException jee)
{
throw jee;
}
catch (Exception e)
{
_logger.LogError(e, "Error during login");
}
catch (JazzAuthFailedException jfe)
{
throw jfe;
}
catch (JazzAuthErrorException jee)
{
throw jee;
}
catch (Exception e)
{
_logger.LogError(e, "Error during login");
throw;
}
🤖 Prompt for AI Agents
In OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzFormAuthClient.cs
around lines 191 to 202, the generic catch logs the exception but does not
rethrow it; update the handler so the exception is rethrown after logging to
avoid swallowing errors—after calling _logger.LogError(...), rethrow the
original exception using a plain throw (to preserve stack trace) so
authentication failures propagate as intended.

Comment on lines +211 to +221
try
{
HttpResponseMessage newResp = await GetHttpClient().GetAsync(location);
statusCode = newResp.StatusCode;
location = (newResp.Headers.Location != null) ? newResp.Headers.Location.AbsoluteUri : null;
statusCode = newResp.StatusCode;
location = (newResp.Headers.Location != null) ? newResp.Headers.Location.AbsoluteUri : null;
newResp.ConsumeContent();
} catch (Exception e) {
_logger.LogError(e, "Error following redirect");
}
}
catch (Exception e)
{
_logger.LogError(e, "Error following redirect");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Exception not rethrown after logging.

The catch block logs the exception but does not rethrow it, causing redirect errors to be silently ignored. This violates the PR objective: "ensures exceptions are rethrown after logging."

                 catch (Exception e)
                 {
                     _logger.LogError(e, "Error following redirect");
+                    throw;
                 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try
{
HttpResponseMessage newResp = await GetHttpClient().GetAsync(location);
statusCode = newResp.StatusCode;
location = (newResp.Headers.Location != null) ? newResp.Headers.Location.AbsoluteUri : null;
statusCode = newResp.StatusCode;
location = (newResp.Headers.Location != null) ? newResp.Headers.Location.AbsoluteUri : null;
newResp.ConsumeContent();
} catch (Exception e) {
_logger.LogError(e, "Error following redirect");
}
}
catch (Exception e)
{
_logger.LogError(e, "Error following redirect");
}
try
{
HttpResponseMessage newResp = await GetHttpClient().GetAsync(location);
statusCode = newResp.StatusCode;
location = (newResp.Headers.Location != null) ? newResp.Headers.Location.AbsoluteUri : null;
newResp.ConsumeContent();
}
catch (Exception e)
{
_logger.LogError(e, "Error following redirect");
throw;
}
🧰 Tools
🪛 GitHub Check: Format (dotnet format)

[warning] 215-215:
Null check can be simplified

🤖 Prompt for AI Agents
In OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzFormAuthClient.cs
around lines 211 to 221, the catch block logs the exception but does not rethrow
it causing redirect failures to be swallowed; change the catch to rethrow after
logging (use throw; to preserve the original stack trace) so that calling code
observes the error, i.e., log the exception as currently done and then
immediately rethrow the exception.

Comment on lines +231 to 249
try
{
GetHttpClient().DefaultRequestHeaders.Clear();
GetHttpClient().DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(OSLCConstants.ATOM));

resp = GetHttpClient().GetAsync(feedUrl).Result;
resp = GetHttpClient().GetAsync(feedUrl).Result;

HttpStatusCode statusCode = resp.StatusCode;
HttpStatusCode statusCode = resp.StatusCode;

if (statusCode != HttpStatusCode.OK)
{
_logger.LogWarning("Status code from feed retrieval: {StatusCode}", statusCode);
}

} catch (Exception e) {

}
catch (Exception e)
{
_logger.LogError(e, "Error getting artifact feed");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Exception not rethrown after logging (if method is retained).

If this method is kept, the catch block must rethrow the exception after logging to align with the PR objective. Additionally, the method should be made async and use await instead of .Result to avoid blocking.

-        private HttpResponseMessage GetArtifactFeed(String feedUrl)
+        private async Task<HttpResponseMessage> GetArtifactFeed(String feedUrl)
         {
             HttpResponseMessage resp = null;
 
             try
             {
                 GetHttpClient().DefaultRequestHeaders.Clear();
                 GetHttpClient().DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(OSLCConstants.ATOM));
 
-                resp = GetHttpClient().GetAsync(feedUrl).Result;
+                resp = await GetHttpClient().GetAsync(feedUrl);
 
                 HttpStatusCode statusCode = resp.StatusCode;
 
                 if (statusCode != HttpStatusCode.OK)
                 {
                     _logger.LogWarning("Status code from feed retrieval: {StatusCode}", statusCode);
                 }
 
             }
             catch (Exception e)
             {
                 _logger.LogError(e, "Error getting artifact feed");
+                throw;
             }
 
             return resp;
         }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzFormAuthClient.cs
around lines 231-249, the catch block logs exceptions but swallows them and the
method blocks on GetAsync().Result; change the method to be async, use await
GetHttpClient().GetAsync(feedUrl) instead of .Result, and after logging rethrow
the original exception with "throw;" (not throw e) so callers observe failures
and the stack is preserved; also update the method return type to the
appropriate Task/Task<T> and adjust call sites accordingly.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

♻️ Duplicate comments (6)
OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs (3)

160-162: Uses obsolete GetRdfTypes() method.

Consider using the RdfTypes property instead to avoid deprecation warnings.

                 String testcaseCreation = await client.LookupCreationFactoryAsync(
                         serviceProviderUrl, OSLCConstants.OSLC_QM_V2,
-                        testcase.GetRdfTypes()[0].ToString()).ConfigureAwait(false);
+                        testcase.RdfTypes[0].ToString()).ConfigureAwait(false);

69-77: Parse errors return silently without failing the sample.

This contradicts the PR objective. When command-line arguments are invalid, the method returns without setting a non-zero exit code, causing the sample to appear successful.

         if (parseResult.Errors.Count > 0)
         {
             foreach (var error in parseResult.Errors)
             {
                 Console.Error.WriteLine(error.Message);
             }
 
-            return;
+            throw new ArgumentException("Invalid command-line arguments");
         }

165-170: Missing status check before accessing Location header.

Unlike EWMSample.cs (lines 206-210), this code doesn't validate that the creation succeeded before accessing the Location header. If creation fails, this could throw a NullReferenceException or produce misleading output.

                 HttpResponseMessage creationResponse = await client.CreateResourceRawAsync(
                         testcaseCreation, testcase,
                         OslcMediaType.APPLICATION_RDF_XML).ConfigureAwait(false);
-                creationResponse.ConsumeContent();
+
+                if (creationResponse.StatusCode != HttpStatusCode.Created)
+                {
+                    string errorString = await creationResponse.Content.ReadAsStringAsync().ConfigureAwait(false);
+                    throw new InvalidOperationException($"Failed to create test case (HTTP {creationResponse.StatusCode}): {errorString}");
+                }
+
                 String testcaseLocation = creationResponse.Headers.Location.ToString();
+                creationResponse.ConsumeContent();
OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs (3)

239-243: Use structured logging placeholder instead of string concatenation.

For consistency with the rest of the codebase and structured logging best practices:

-            Logger.LogError(re, "Unable to access the Jazz rootservices document at: " + webContextUrl + "/rootservices");
+            Logger.LogError(re, "Unable to access the Jazz rootservices document at: {Url}", webContextUrl + "/rootservices");

195-198: Uses obsolete GetRdfTypes() method.

Consider using the RdfTypes property instead.

                 String changeRequestCreation = await client.LookupCreationFactoryAsync(
                                 serviceProviderUrl, OSLCConstants.OSLC_CM_V2,
-                                changeRequest.GetRdfTypes()[0].ToString()).ConfigureAwait(false);
+                                changeRequest.RdfTypes[0].ToString()).ConfigureAwait(false);

414-427: Exceptions swallowed in ResolveFiledAgainstAsync contradict PR objective.

Both the inner catch (line 414-417) and outer catch (line 423-427) log errors but don't rethrow, allowing the sample to proceed with potentially corrupted state. This contradicts the PR's goal to "ensure samples fail if there is any error."

If graceful degradation is intentional here (continuing without filedAgainst), document this explicitly. Otherwise, rethrow to fail fast:

                 catch (Exception ex)
                 {
                     Logger.LogError(ex, "Failed to deserialize AllowedValues");
+                    throw;
                 }
         catch (Exception ex)
         {
             Logger.LogError(ex, "Error resolving Filed Against allowed values");
-            return null;
+            throw;
         }
🧹 Nitpick comments (4)
OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzConstants.cs (1)

16-24: LGTM! Clean refactoring to modern C# structure.

The file-scoped namespace and flattened class structure improve readability and follow current C# conventions. The constants are appropriately defined as public const string.

Optional: Consider adding XML documentation comments.

For better API discoverability, consider adding XML documentation comments to describe the purpose of each constant:

+/// <summary>
+/// Jazz namespace URIs used in OSLC integration.
+/// </summary>
 public static class JazzConstants
 {
+    /// <summary>
+    /// Jazz RTC Change Management namespace URI.
+    /// </summary>
     public const string RTC_CM = "http://jazz.net/xmlns/prod/jazz/rtc/cm/1.0/";
+    /// <summary>
+    /// Jazz Foundation Services namespace URI.
+    /// </summary>
     public const string JFS = "http://jazz.net/xmlns/prod/jazz/jfs/1.0/";
+    /// <summary>
+    /// Jazz Discovery namespace URI.
+    /// </summary>
     public const string JD = "http://jazz.net/xmlns/prod/jazz/discovery/1.0/";
+    /// <summary>
+    /// Jazz Process 0.6 namespace URI.
+    /// </summary>
     public const string JP06 = "http://jazz.net/xmlns/prod/jazz/process/0.6/";
 }
OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/Program.cs (1)

20-26: Unrecognized sample selector silently falls back to ETMSample.

When an unrecognized selector is provided (e.g., dotnet run foo), the code silently defaults to ETMSample without warning. Given the PR objective to avoid silent failures, consider logging a warning or failing explicitly for unknown selectors.

             sampleName = args[0].ToLower() switch
             {
                 "ewm" => "EWMSample",
                 "erm" => "ERMSample",
                 "etm" => "ETMSample",
-                _ => "ETMSample"
+                _ => throw new ArgumentException($"Unknown sample selector: '{args[0]}'. Valid options: ewm, erm, etm")
             };
OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/SampleBase.cs (1)

81-85: Use nullable annotation for line variable.

With nullable reference types enabled, string line = null should be string? line = null to avoid compiler warnings.

-        string line = null;
+        string? line = null;
OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ERMSample.cs (1)

174-178: Nullable reference type annotations missing.

With NRT enabled, these declarations will produce warnings. Use string? for nullable strings:

-                String req01URL = null;
-                String req02URL = null;
-                String req03URL = null;
-                String req04URL = null;
-                String reqcoll01URL = null;
+                string? req01URL = null;
+                string? req02URL = null;
+                string? req03URL = null;
+                string? req04URL = null;
+                string? reqcoll01URL = null;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 280b832 and a2aa0b7.

📒 Files selected for processing (10)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzConstants.cs (2 hunks)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzFormAuthClient.cs (2 hunks)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzRootServicesConstants.cs (2 hunks)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Properties/AssemblyInfo.cs (1 hunks)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ERMSample.cs (1 hunks)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs (1 hunks)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs (1 hunks)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/Program.cs (1 hunks)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/Properties/AssemblyInfo.cs (1 hunks)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/SampleBase.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzRootServicesConstants.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzFormAuthClient.cs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.cs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.cs: Follow Microsoft .NET design guidelines (https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/) for code style
Run dotnet format before commit to maintain code formatting consistency
Use C# 14 with nullable reference types enabled
Follow .NET code analysis and Meziantou.Analyzer rules

Files:

  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Properties/AssemblyInfo.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzConstants.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/Properties/AssemblyInfo.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/SampleBase.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/Program.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ERMSample.cs

⚙️ CodeRabbit configuration file

**/*.cs: Review the C# code against the Microsoft Framework design guidelines as well as 10 guidelines
from "Building Maintainable Software" by Joost Visser. Point out deviations and improvements.

Files:

  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Properties/AssemblyInfo.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzConstants.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/Properties/AssemblyInfo.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/SampleBase.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/Program.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ERMSample.cs
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: OSLC/oslc4net PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-29T19:12:48.610Z
Learning: Applies to **/Tests/**/*.cs : Prefer Verify and round-tripping checks when dealing with RDF data in tests
📚 Learning: 2025-11-29T19:12:48.610Z
Learnt from: CR
Repo: OSLC/oslc4net PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-29T19:12:48.610Z
Learning: Applies to **/Tests/**/*.cs : Prefer Verify and round-tripping checks when dealing with RDF data in tests

Applied to files:

  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs
🧬 Code graph analysis (1)
OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs (1)
OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/SampleBase.cs (6)
  • SampleBase (8-90)
  • SampleBase (12-15)
  • Task (17-34)
  • Task (36-68)
  • Task (70-87)
  • PrintResourceInfo (89-89)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Analyze (csharp)
  • GitHub Check: test (ubuntu-24.04, 10.x, net10.0)
  • GitHub Check: smoke-test
🔇 Additional comments (7)
OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/Properties/AssemblyInfo.cs (1)

1-1: Using directive cleanup looks good

Removing the BOM and unused usings while keeping only the required ones for the assembly attributes improves clarity without changing behavior.

OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Properties/AssemblyInfo.cs (1)

1-2: LGTM! Clean using directive organization.

The alphabetical ordering and removal of unused usings align with .NET formatting standards and improve code maintainability.

OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/Program.cs (1)

51-63: LGTM!

The exception handling correctly unwraps InnerException from reflection invocation and ensures a non-zero exit code on failure, aligning with the PR objective.

OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/SampleBase.cs (2)

62-66: LGTM!

The catch block logs the error with context (resultsUrl) and rethrows, correctly aligning with the PR objective to ensure failures propagate.


56-60: Remove the redundant null check for response.

GetResourceRawAsync returns Task<HttpResponseMessage> (non-nullable) and never returns null; it either returns a response or throws an exception. The check at line 56 is unnecessary and can be removed. If an error occurs, the method will throw and be caught by the existing exception handler.

HttpResponseMessage response = await client.GetResourceRawAsync(resultsUrl, OSLCConstants.CT_RDF).ConfigureAwait(false);
//Just print the raw RDF/XML (or process the XML as desired)
await ProcessRawResponseAsync(response).ConfigureAwait(false);

Additionally, update line 81 to use proper nullable reference type syntax: change string line = null; to string? line = null; to comply with C# 14 with nullable reference types enabled.

Likely an incorrect or invalid review comment.

OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs (1)

191-200: LGTM!

Exception handling correctly logs errors and rethrows, ensuring failures propagate as intended by the PR.

OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ERMSample.cs (1)

336-340: LGTM!

The outer exception handling correctly logs and rethrows unexpected errors.

Comment on lines +69 to 77
if (parseResult.Errors.Count > 0)
{
using ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
foreach (var error in parseResult.Errors)
{
builder.AddConsole();
builder.SetMinimumLevel(LogLevel.Information);
});

var urlOption = new System.CommandLine.Option<string>("--url") { Arity = ArgumentArity.ExactlyOne };
var userOption = new System.CommandLine.Option<string>("--user") { Arity = ArgumentArity.ExactlyOne };
var passwordOption = new System.CommandLine.Option<string>("--password") { Arity = ArgumentArity.ExactlyOne };
var projectAreaOption = new System.CommandLine.Option<string>("--project") { Arity = ArgumentArity.ExactlyOne };

var rootCommand = new System.CommandLine.RootCommand("ERM Sample");
rootCommand.Add(urlOption);
rootCommand.Add(userOption);
rootCommand.Add(passwordOption);
rootCommand.Add(projectAreaOption);

var parseResult = rootCommand.Parse(args);
if (parseResult.Errors.Count > 0)
{
foreach (var error in parseResult.Errors)
{
Console.Error.WriteLine(error.Message);
}

return;
Console.Error.WriteLine(error.Message);
}

var url = parseResult.GetValue(urlOption)!;
var user = parseResult.GetValue(userOption)!;
var password = parseResult.GetValue(passwordOption)!;
var projectArea = parseResult.GetValue(projectAreaOption)!;

var sample = new ERMSample(loggerFactory);
await sample.RunAsync(url, user, password, projectArea);
return;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Parse errors return silently without failing the sample.

Same issue as other samples. Invalid arguments should cause the sample to fail.

         if (parseResult.Errors.Count > 0)
         {
             foreach (var error in parseResult.Errors)
             {
                 Console.Error.WriteLine(error.Message);
             }
 
-            return;
+            throw new ArgumentException("Invalid command-line arguments");
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (parseResult.Errors.Count > 0)
{
using ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
foreach (var error in parseResult.Errors)
{
builder.AddConsole();
builder.SetMinimumLevel(LogLevel.Information);
});
var urlOption = new System.CommandLine.Option<string>("--url") { Arity = ArgumentArity.ExactlyOne };
var userOption = new System.CommandLine.Option<string>("--user") { Arity = ArgumentArity.ExactlyOne };
var passwordOption = new System.CommandLine.Option<string>("--password") { Arity = ArgumentArity.ExactlyOne };
var projectAreaOption = new System.CommandLine.Option<string>("--project") { Arity = ArgumentArity.ExactlyOne };
var rootCommand = new System.CommandLine.RootCommand("ERM Sample");
rootCommand.Add(urlOption);
rootCommand.Add(userOption);
rootCommand.Add(passwordOption);
rootCommand.Add(projectAreaOption);
var parseResult = rootCommand.Parse(args);
if (parseResult.Errors.Count > 0)
{
foreach (var error in parseResult.Errors)
{
Console.Error.WriteLine(error.Message);
}
return;
Console.Error.WriteLine(error.Message);
}
var url = parseResult.GetValue(urlOption)!;
var user = parseResult.GetValue(userOption)!;
var password = parseResult.GetValue(passwordOption)!;
var projectArea = parseResult.GetValue(projectAreaOption)!;
var sample = new ERMSample(loggerFactory);
await sample.RunAsync(url, user, password, projectArea);
return;
}
if (parseResult.Errors.Count > 0)
{
foreach (var error in parseResult.Errors)
{
Console.Error.WriteLine(error.Message);
}
throw new ArgumentException("Invalid command-line arguments");
}
🤖 Prompt for AI Agents
In OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ERMSample.cs around lines 69 to
77, parse errors are currently written to Console.Error and then the method
returns silently; change this so invalid arguments cause the sample to fail:
after writing each parse error, terminate with a non-zero exit (e.g., call
Environment.Exit(1)) or throw a descriptive exception so the process exits with
failure; ensure you include a clear message/context when exiting or throwing so
CI and callers detect the error.

Comment on lines +200 to 210
if (creationResponse.IsSuccessStatusCode)
{
featureInstanceShape = await RmUtil.LookupRequirementsInstanceShapesAsync(
serviceProviderUrl,
OSLCConstants.OSLC_RM_V2,
OSLCConstants.RM_REQUIREMENT_TYPE,
client,
"Feature");
req01URL = creationResponse.Headers.Location?.ToString();
Logger.LogInformation("REQ01 created: {Url}", req01URL);
creationResponse.ConsumeContent();
}
catch (ResourceNotFoundException)
else
{
featureInstanceShape = await RmUtil.LookupRequirementsInstanceShapesAsync(
serviceProviderUrl,
OSLCConstants.OSLC_RM_V2,
OSLCConstants.RM_REQUIREMENT_TYPE,
client,
"User Requirement");
Logger.LogWarning("Failed to create REQ01: {StatusCode}", creationResponse.StatusCode);
creationResponse.ConsumeContent();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Creation failures logged as warnings but don't fail the sample.

When requirement creation fails, the code logs a warning and continues. This contradicts the PR objective to "ensure samples fail if there is any error." Consider throwing on failure:

                         if (creationResponse.IsSuccessStatusCode)
                         {
                             req01URL = creationResponse.Headers.Location?.ToString();
                             Logger.LogInformation("REQ01 created: {Url}", req01URL);
                             creationResponse.ConsumeContent();
                         }
                         else
                         {
-                            Logger.LogWarning("Failed to create REQ01: {StatusCode}", creationResponse.StatusCode);
-                            creationResponse.ConsumeContent();
+                            string errorContent = await creationResponse.Content.ReadAsStringAsync().ConfigureAwait(false);
+                            throw new InvalidOperationException($"Failed to create REQ01 (HTTP {creationResponse.StatusCode}): {errorContent}");
                         }

The same pattern applies to REQ02, REQ03, REQ04, and Collection01 creation blocks.

🤖 Prompt for AI Agents
In OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ERMSample.cs around lines 200
to 210, the sample currently logs a warning and continues when
creationResponse.IsSuccessStatusCode is false; update the failure handling to
throw an exception (or otherwise abort) when the response indicates failure so
the sample fails on errors: replace the warning log path with code that
reads/consumes the response content and then throws a descriptive exception
including status code and response body/headers; apply the same change to the
REQ02, REQ03, REQ04 and Collection01 creation blocks so any non-success HTTP
response causes the sample to stop with an error.

Comment on lines +316 to +319
catch (Exception ex)
{
Logger.LogWarning(ex, "Error during requirement creation");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Creation errors caught and swallowed.

This catch block logs a warning but doesn't rethrow, allowing the sample to continue after creation failures. Per the PR objective, consider rethrowing:

                 catch (Exception ex)
                 {
-                    Logger.LogWarning(ex, "Error during requirement creation");
+                    Logger.LogError(ex, "Error during requirement creation");
+                    throw;
                 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
catch (Exception ex)
{
Logger.LogWarning(ex, "Error during requirement creation");
}
catch (Exception ex)
{
Logger.LogError(ex, "Error during requirement creation");
throw;
}
🤖 Prompt for AI Agents
In OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ERMSample.cs around lines 316
to 319, the catch block logs creation exceptions but swallows them which lets
execution continue after a failed requirement creation; modify the handler to
rethrow the exception (or throw a new, descriptive exception preserving the
original as InnerException) after logging so the failure propagates and the
sample/CI can detect the error. Ensure you preserve the original exception
details when rethrowing to retain stack trace and context.

Comment on lines +91 to 99
if (parseResult.Errors.Count > 0)
{
await RunSample(args);
foreach (var error in parseResult.Errors)
{
Console.Error.WriteLine(error.Message);
}

return;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Parse errors return silently without failing the sample.

Same issue as ETMSample. When command-line arguments are invalid, the method returns without signaling failure.

         if (parseResult.Errors.Count > 0)
         {
             foreach (var error in parseResult.Errors)
             {
                 Console.Error.WriteLine(error.Message);
             }
 
-            return;
+            throw new ArgumentException("Invalid command-line arguments");
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (parseResult.Errors.Count > 0)
{
await RunSample(args);
foreach (var error in parseResult.Errors)
{
Console.Error.WriteLine(error.Message);
}
return;
}
if (parseResult.Errors.Count > 0)
{
foreach (var error in parseResult.Errors)
{
Console.Error.WriteLine(error.Message);
}
throw new ArgumentException("Invalid command-line arguments");
}
🤖 Prompt for AI Agents
In OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs around lines 91 to
99, parse errors are written to stderr but the method returns silently; replace
the silent return with a failure signal so the sample process exits non‑zero
(e.g., call Environment.Exit(1) or throw an exception) after printing each
error. Ensure the exit/exception is used consistently with other samples (like
ETMSample) so invalid command-line args cause a non-zero termination.

Comment on lines +226 to +231
HttpResponseMessage updateResponse = await client.UpdateResourceRawAsync(
new Uri(updateUrl), changeRequest,
OslcMediaType.APPLICATION_RDF_XML,
OslcMediaType.APPLICATION_RDF_XML).ConfigureAwait(false);

//Get the change request from the service provider and update its title property
changeRequest = await (await client.GetResourceRawAsync(changeRequestLocation,
OslcMediaType.APPLICATION_RDF_XML)).Content.ReadAsAsync<ChangeRequest>(client.GetFormatters());
changeRequest.SetTitle(changeRequest.GetTitle() + " (updated)");
updateResponse.ConsumeContent();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Update response status not validated.

The creation response is properly validated (lines 206-210), but the update response is consumed without checking success. If the update fails, the sample will appear successful.

                 HttpResponseMessage updateResponse = await client.UpdateResourceRawAsync(
                                 new Uri(updateUrl), changeRequest,
                                 OslcMediaType.APPLICATION_RDF_XML,
                                 OslcMediaType.APPLICATION_RDF_XML).ConfigureAwait(false);
 
+                if (!updateResponse.IsSuccessStatusCode)
+                {
+                    string errorString = await updateResponse.Content.ReadAsStringAsync().ConfigureAwait(false);
+                    throw new InvalidOperationException($"Failed to update change request (HTTP {updateResponse.StatusCode}): {errorString}");
+                }
                 updateResponse.ConsumeContent();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
HttpResponseMessage updateResponse = await client.UpdateResourceRawAsync(
new Uri(updateUrl), changeRequest,
OslcMediaType.APPLICATION_RDF_XML,
OslcMediaType.APPLICATION_RDF_XML).ConfigureAwait(false);
//Get the change request from the service provider and update its title property
changeRequest = await (await client.GetResourceRawAsync(changeRequestLocation,
OslcMediaType.APPLICATION_RDF_XML)).Content.ReadAsAsync<ChangeRequest>(client.GetFormatters());
changeRequest.SetTitle(changeRequest.GetTitle() + " (updated)");
updateResponse.ConsumeContent();
HttpResponseMessage updateResponse = await client.UpdateResourceRawAsync(
new Uri(updateUrl), changeRequest,
OslcMediaType.APPLICATION_RDF_XML,
OslcMediaType.APPLICATION_RDF_XML).ConfigureAwait(false);
if (!updateResponse.IsSuccessStatusCode)
{
string errorString = await updateResponse.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new InvalidOperationException($"Failed to update change request (HTTP {updateResponse.StatusCode}): {errorString}");
}
updateResponse.ConsumeContent();
🤖 Prompt for AI Agents
In OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/EWMSample.cs around lines
226-231, the HttpResponseMessage returned from UpdateResourceRawAsync is
consumed without validating the response status; change the code to check
updateResponse.IsSuccessStatusCode (or check StatusCode range) and only call
ConsumeContent() when successful, otherwise read the response content and log or
throw an exception with the status code and body to surface the failure; also
ensure the response is disposed in all branches (use using or finally) so
resources are released.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (7)
OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzFormAuthClient.cs (4)

25-32: Use lowercase string keyword for fields and constants.

The fields and constants use String instead of the lowercase string keyword, which violates .NET design guidelines. Additionally, with nullable reference types enabled (C# 14), fields should have proper nullable annotations.

As per coding guidelines, follow Microsoft .NET design guidelines and use C# 14 with nullable reference types.

Apply this diff to fix the field and constant declarations:

-    private String url;
-    private String authUrl;
-    private String project;
-    private String user;
-    private String password;
+    private string? url;
+    private string? authUrl;
+    private string? project;
+    private string? user;
+    private string? password;

-    private const String JAZZ_AUTH_MESSAGE_HEADER = "X-com-ibm-team-repository-web-auth-msg";
-    private const String JAZZ_AUTH_FAILED = "authfailed";
+    private const string JAZZ_AUTH_MESSAGE_HEADER = "X-com-ibm-team-repository-web-auth-msg";
+    private const string JAZZ_AUTH_FAILED = "authfailed";

191-194: CRITICAL: Exception not rethrown after logging.

The catch block logs the exception but does not rethrow it, directly violating the PR objective: "ensures exceptions are rethrown after logging." This causes authentication failures to be silently swallowed, and the method will incorrectly return HttpStatusCode.Unused instead of propagating the error.

Apply this diff to rethrow the exception:

     catch (Exception e)
     {
         _logger.LogError(e, "Error during login");
+        throw;
     }

210-213: CRITICAL: Exception not rethrown after logging.

The catch block logs the exception but does not rethrow it, directly violating the PR objective: "ensures exceptions are rethrown after logging." This causes redirect errors to be silently swallowed instead of propagating to the caller.

Apply this diff to rethrow the exception:

     catch (Exception e)
     {
         _logger.LogError(e, "Error following redirect");
+        throw;
     }

74-116: Replace Java-style getters/setters with C# properties.

The code uses Java-style Get*/Set* methods instead of idiomatic C# properties, which violates Microsoft .NET design guidelines. Properties provide better syntax, IntelliSense support, and integration with .NET frameworks.

As per coding guidelines, follow Microsoft .NET design guidelines.

Replace the getter/setter methods with C# properties:

-    public String GetUrl()
-    {
-        return url;
-    }
-    public void SetUrl(String url)
-    {
-        this.url = url;
-    }
-
-    public String GetAuthUrl()
-    {
-        return authUrl;
-    }
-
-    public void SetAuthUrl(String authUrl)
-    {
-        this.authUrl = authUrl;
-    }
-
-    public String GetProject()
-    {
-        return project;
-    }
-    public void SetProject(String project)
-    {
-        this.project = project;
-    }
-    public String GetUser()
-    {
-        return user;
-    }
-    public void SetUser(String user)
-    {
-        this.user = user;
-    }
-    public String GetPassword()
-    {
-        return password;
-    }
-    public void SetPassword(String password)
-    {
-        this.password = password;
-    }
+    public string? Url { get; set; }
+    public string? AuthUrl { get; set; }
+    public string? Project { get; set; }
+    public string? User { get; set; }
+    public string? Password { get; set; }

Then update the constructors to use the properties:

     public JazzFormAuthClient(String url, String user, String password, ILogger<OslcClient> logger) :
         this(logger)
     {
-        this.url = url;
-        this.authUrl = url;  //default to base URL
-        this.user = user;
-        this.password = password;
+        this.Url = url;
+        this.AuthUrl = url;  //default to base URL
+        this.User = user;
+        this.Password = password;
     }
OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs (3)

69-77: Parse errors return silently without propagating failure.

When command-line parsing fails, errors are written to stderr but the method returns normally, preventing Program.cs from setting a non-zero exit code. This issue was previously flagged but remains unaddressed.

Consider throwing an exception to ensure proper exit code:

         if (parseResult.Errors.Count > 0)
         {
             foreach (var error in parseResult.Errors)
             {
                 Console.Error.WriteLine(error.Message);
             }

-            return;
+            throw new ArgumentException("Invalid command-line arguments");
         }

162-162: Obsolete method usage: GetRdfTypes().

The GetRdfTypes() method is obsolete. Use the RdfTypes property with First() instead.

Apply this diff:

-                testcase.GetRdfTypes()[0].ToString()).ConfigureAwait(false);
+                testcase.RdfTypes.First().ToString()).ConfigureAwait(false);

165-170: Missing status code validation before accessing Location header.

The code accesses creationResponse.Headers.Location without first verifying that the creation succeeded (status code 201 Created). This could throw if the request failed. Similar validation was added in EWMSample.cs at lines 217-221.

Add status validation before accessing the Location header:

         creationResponse.ConsumeContent();
+        if (creationResponse.StatusCode != HttpStatusCode.Created)
+        {
+            String errorString = await creationResponse.Content.ReadAsStringAsync();
+            throw new InvalidOperationException($"Failed to create test case (HTTP {creationResponse.StatusCode}): {errorString}");
+        }
         String testcaseLocation = creationResponse.Headers.Location.ToString();
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a2aa0b7 and 549992f.

📒 Files selected for processing (2)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzFormAuthClient.cs (2 hunks)
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.cs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.cs: Follow Microsoft .NET design guidelines (https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/) for code style
Run dotnet format before commit to maintain code formatting consistency
Use C# 14 with nullable reference types enabled
Follow .NET code analysis and Meziantou.Analyzer rules

Files:

  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzFormAuthClient.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs

⚙️ CodeRabbit configuration file

**/*.cs: Review the C# code against the Microsoft Framework design guidelines as well as 10 guidelines
from "Building Maintainable Software" by Joost Visser. Point out deviations and improvements.

Files:

  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzFormAuthClient.cs
  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: OSLC/oslc4net PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-29T19:12:48.610Z
Learning: Applies to **/Tests/**/*.cs : Prefer Verify and round-tripping checks when dealing with RDF data in tests
📚 Learning: 2025-11-29T19:12:48.610Z
Learnt from: CR
Repo: OSLC/oslc4net PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-29T19:12:48.610Z
Learning: Applies to **/*.cs : Follow Microsoft .NET design guidelines (https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/) for code style

Applied to files:

  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzFormAuthClient.cs
📚 Learning: 2025-11-29T19:12:48.610Z
Learnt from: CR
Repo: OSLC/oslc4net PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-29T19:12:48.610Z
Learning: Applies to **/Tests/**/*.cs : Prefer Verify and round-tripping checks when dealing with RDF data in tests

Applied to files:

  • OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Analyze (csharp)
  • GitHub Check: test (ubuntu-24.04, 10.x, net10.0)
  • GitHub Check: test (windows-latest, 10.x, net10.0)
🔇 Additional comments (4)
OSLC4Net_SDK/Examples/OSLC4Net.Client.Samples/ETMSample.cs (4)

16-26: LGTM! Using directives properly cleaned up.

The using directives are now correctly organized with only necessary namespaces included, addressing previous review feedback.


36-43: LGTM! Proper use of sealed class and dependency injection.

The class correctly implements the dependency injection pattern with ILoggerFactory, and the sealed modifier is appropriate for this concrete sample implementation.


88-94: LGTM! Clean override with proper null checking and structured logging.

The method correctly implements the base class contract with appropriate null checking and uses structured logging with named parameters.


186-200: LGTM! Proper error handling with logging and rethrow.

The error handling correctly implements the pattern described in the PR objectives: exceptions are logged with appropriate context and then rethrown to ensure the sample fails explicitly rather than silently.

string location;
if (statusCode == HttpStatusCode.Found)
{
location = resp.Headers.Location.AbsoluteUri;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential null reference exception when accessing Location header.

Lines 135 and 177 access resp.Headers.Location.AbsoluteUri without checking if Location is null. If the Location header is missing, this will throw a NullReferenceException.

Apply this diff to add null safety:

-            location = resp.Headers.Location.AbsoluteUri;
+            location = resp.Headers.Location?.AbsoluteUri;

And at line 177:

-                location = resp.Headers.Location.AbsoluteUri;
+                location = resp.Headers.Location?.AbsoluteUri;

Also applies to: 177-177

🤖 Prompt for AI Agents
In OSLC4Net_SDK/Examples/OSLC4Net.Client.Jazz/Oslc/Jazz/JazzFormAuthClient.cs
around lines 135 and 177, the code reads resp.Headers.Location.AbsoluteUri
without null checks which can throw a NullReferenceException if the Location
header is absent; update both sites to guard against null by checking
resp.Headers.Location != null (or using the null-conditional operator) before
accessing AbsoluteUri and provide a safe fallback or throw a clear exception/log
message when Location is missing so execution does not dereference a null
Location.

@berezovskyi
berezovskyi merged commit 6d30d7a into main Dec 7, 2025
9 of 10 checks passed
@berezovskyi
berezovskyi deleted the b-strict-smoke branch December 7, 2025 13:44
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.

2 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.