@@ -265,4 +265,191 @@ public async Task GitHubRepoConnector_GetBuildInformationAsync_WithOpenIssues_Id
265265 var hasExpectedIssue = knownIssueTitles . Exists ( t => t . Contains ( "Known bug" ) || t . Contains ( "Feature request" ) ) ;
266266 Assert . IsTrue ( hasExpectedIssue , "Should have at least one of the open issues as a known issue" ) ;
267267 }
268+
269+ /// <summary>
270+ /// Test that pre-release baseline selection skips tags with the same commit hash.
271+ /// Example: 1.1.2-rc.1 (hash a1b2c3d4) and 1.1.2-beta.2 (hash a1b2c3d4) are re-tags.
272+ /// When processing 1.1.2-rc.1, it should skip 1.1.2-beta.2 and use 1.1.2-beta.1 (hash 734713bc).
273+ /// </summary>
274+ [ TestMethod ]
275+ public async Task GitHubRepoConnector_GetBuildInformationAsync_PreReleaseWithSameCommitHash_SkipsToNextDifferentHash ( )
276+ {
277+ // Arrange - Create mock responses with multiple pre-releases on same and different hashes
278+ using var mockHandler = new MockGitHubGraphQLHttpMessageHandler ( )
279+ . AddCommitsResponse ( "a1b2c3d4" , "734713bc" , "commit1" )
280+ . AddReleasesResponse (
281+ new MockRelease ( "1.1.2-rc.1" , "2024-03-03T00:00:00Z" ) , // Same hash as beta.2
282+ new MockRelease ( "1.1.2-beta.2" , "2024-03-02T00:00:00Z" ) , // Same hash as rc.1
283+ new MockRelease ( "1.1.2-beta.1" , "2024-03-01T00:00:00Z" ) , // Different hash
284+ new MockRelease ( "v1.1.1" , "2024-02-01T00:00:00Z" ) )
285+ . AddPullRequestsResponse ( )
286+ . AddIssuesResponse ( )
287+ . AddTagsResponse (
288+ new MockTag ( "1.1.2-rc.1" , "a1b2c3d4" ) , // rc.1 and beta.2 on same hash
289+ new MockTag ( "1.1.2-beta.2" , "a1b2c3d4" ) , // Same hash as rc.1
290+ new MockTag ( "1.1.2-beta.1" , "734713bc" ) , // Different hash
291+ new MockTag ( "v1.1.1" , "commit1" ) ) ;
292+
293+ using var mockHttpClient = new HttpClient ( mockHandler ) ;
294+ var connector = new MockableGitHubRepoConnector ( mockHttpClient ) ;
295+
296+ // Set up mock command responses
297+ connector . SetCommandResponse ( "git remote get-url origin" , "https://github.com/test/repo.git" ) ;
298+ connector . SetCommandResponse ( "git rev-parse --abbrev-ref HEAD" , "main" ) ;
299+ connector . SetCommandResponse ( "git rev-parse HEAD" , "a1b2c3d4" ) ;
300+ connector . SetCommandResponse ( "gh auth token" , "test-token" ) ;
301+
302+ // Act - Process 1.1.2-rc.1
303+ var buildInfo = await connector . GetBuildInformationAsync ( Version . Create ( "1.1.2-rc.1" ) ) ;
304+
305+ // Assert
306+ Assert . IsNotNull ( buildInfo ) ;
307+ Assert . AreEqual ( "1.1.2-rc.1" , buildInfo . CurrentVersionTag . VersionInfo . FullVersion ) ;
308+ Assert . AreEqual ( "a1b2c3d4" , buildInfo . CurrentVersionTag . CommitHash ) ;
309+
310+ // Should have skipped 1.1.2-beta.2 (same hash) and selected 1.1.2-beta.1 (different hash)
311+ Assert . IsNotNull ( buildInfo . BaselineVersionTag ) ;
312+ Assert . AreEqual ( "1.1.2-beta.1" , buildInfo . BaselineVersionTag . VersionInfo . FullVersion ) ;
313+ Assert . AreEqual ( "734713bc" , buildInfo . BaselineVersionTag . CommitHash ) ;
314+
315+ // Should have changelog link between beta.1 and rc.1
316+ Assert . IsNotNull ( buildInfo . CompleteChangelogLink ) ;
317+ Assert . Contains ( "1.1.2-beta.1...1.1.2-rc.1" , buildInfo . CompleteChangelogLink . TargetUrl ) ;
318+ }
319+
320+ /// <summary>
321+ /// Test that release baseline selection skips all pre-release versions.
322+ /// Example: 1.1.2 should skip 1.1.2-rc.1, 1.1.2-beta.2, 1.1.2-beta.1 and use 1.1.1.
323+ /// </summary>
324+ [ TestMethod ]
325+ public async Task GitHubRepoConnector_GetBuildInformationAsync_ReleaseVersion_SkipsAllPreReleases ( )
326+ {
327+ // Arrange - Create mock responses with release and multiple pre-releases
328+ using var mockHandler = new MockGitHubGraphQLHttpMessageHandler ( )
329+ . AddCommitsResponse ( "commit5" , "commit4" , "commit3" , "commit2" , "commit1" )
330+ . AddReleasesResponse (
331+ new MockRelease ( "1.1.2" , "2024-03-05T00:00:00Z" ) ,
332+ new MockRelease ( "1.1.2-rc.1" , "2024-03-04T00:00:00Z" ) ,
333+ new MockRelease ( "1.1.2-beta.2" , "2024-03-03T00:00:00Z" ) ,
334+ new MockRelease ( "1.1.2-beta.1" , "2024-03-02T00:00:00Z" ) ,
335+ new MockRelease ( "v1.1.1" , "2024-02-01T00:00:00Z" ) )
336+ . AddPullRequestsResponse ( )
337+ . AddIssuesResponse ( )
338+ . AddTagsResponse (
339+ new MockTag ( "1.1.2" , "commit5" ) ,
340+ new MockTag ( "1.1.2-rc.1" , "commit4" ) ,
341+ new MockTag ( "1.1.2-beta.2" , "commit3" ) ,
342+ new MockTag ( "1.1.2-beta.1" , "commit2" ) ,
343+ new MockTag ( "v1.1.1" , "commit1" ) ) ;
344+
345+ using var mockHttpClient = new HttpClient ( mockHandler ) ;
346+ var connector = new MockableGitHubRepoConnector ( mockHttpClient ) ;
347+
348+ // Set up mock command responses
349+ connector . SetCommandResponse ( "git remote get-url origin" , "https://github.com/test/repo.git" ) ;
350+ connector . SetCommandResponse ( "git rev-parse --abbrev-ref HEAD" , "main" ) ;
351+ connector . SetCommandResponse ( "git rev-parse HEAD" , "commit5" ) ;
352+ connector . SetCommandResponse ( "gh auth token" , "test-token" ) ;
353+
354+ // Act - Process 1.1.2
355+ var buildInfo = await connector . GetBuildInformationAsync ( Version . Create ( "1.1.2" ) ) ;
356+
357+ // Assert
358+ Assert . IsNotNull ( buildInfo ) ;
359+ Assert . AreEqual ( "1.1.2" , buildInfo . CurrentVersionTag . VersionInfo . FullVersion ) ;
360+ Assert . AreEqual ( "commit5" , buildInfo . CurrentVersionTag . CommitHash ) ;
361+
362+ // Should have skipped all pre-releases and selected 1.1.1
363+ Assert . IsNotNull ( buildInfo . BaselineVersionTag ) ;
364+ Assert . AreEqual ( "1.1.1" , buildInfo . BaselineVersionTag . VersionInfo . FullVersion ) ;
365+ Assert . AreEqual ( "commit1" , buildInfo . BaselineVersionTag . CommitHash ) ;
366+
367+ // Should have changelog link between 1.1.1 and 1.1.2
368+ Assert . IsNotNull ( buildInfo . CompleteChangelogLink ) ;
369+ Assert . Contains ( "v1.1.1...1.1.2" , buildInfo . CompleteChangelogLink . TargetUrl ) ;
370+ }
371+
372+ /// <summary>
373+ /// Test that pre-release baseline selection works correctly when target is not in release history.
374+ /// This happens when generating build notes for a version that hasn't been tagged yet.
375+ /// </summary>
376+ [ TestMethod ]
377+ public async Task GitHubRepoConnector_GetBuildInformationAsync_PreReleaseNotInHistory_UsesLatestDifferentHash ( )
378+ {
379+ // Arrange - Create mock responses where target version doesn't exist yet
380+ using var mockHandler = new MockGitHubGraphQLHttpMessageHandler ( )
381+ . AddCommitsResponse ( "new-hash-123" , "commit2" , "commit1" )
382+ . AddReleasesResponse (
383+ new MockRelease ( "1.1.2-beta.1" , "2024-03-01T00:00:00Z" ) ,
384+ new MockRelease ( "v1.1.1" , "2024-02-01T00:00:00Z" ) )
385+ . AddPullRequestsResponse ( )
386+ . AddIssuesResponse ( )
387+ . AddTagsResponse (
388+ new MockTag ( "1.1.2-beta.1" , "commit2" ) ,
389+ new MockTag ( "v1.1.1" , "commit1" ) ) ;
390+
391+ using var mockHttpClient = new HttpClient ( mockHandler ) ;
392+ var connector = new MockableGitHubRepoConnector ( mockHttpClient ) ;
393+
394+ // Set up mock command responses
395+ connector . SetCommandResponse ( "git remote get-url origin" , "https://github.com/test/repo.git" ) ;
396+ connector . SetCommandResponse ( "git rev-parse --abbrev-ref HEAD" , "main" ) ;
397+ connector . SetCommandResponse ( "git rev-parse HEAD" , "new-hash-123" ) ;
398+ connector . SetCommandResponse ( "gh auth token" , "test-token" ) ;
399+
400+ // Act - Process 1.1.2-beta.2 which doesn't exist in releases yet
401+ var buildInfo = await connector . GetBuildInformationAsync ( Version . Create ( "1.1.2-beta.2" ) ) ;
402+
403+ // Assert
404+ Assert . IsNotNull ( buildInfo ) ;
405+ Assert . AreEqual ( "1.1.2-beta.2" , buildInfo . CurrentVersionTag . VersionInfo . FullVersion ) ;
406+ Assert . AreEqual ( "new-hash-123" , buildInfo . CurrentVersionTag . CommitHash ) ;
407+
408+ // Should use most recent release with different hash
409+ Assert . IsNotNull ( buildInfo . BaselineVersionTag ) ;
410+ Assert . AreEqual ( "1.1.2-beta.1" , buildInfo . BaselineVersionTag . VersionInfo . FullVersion ) ;
411+ Assert . AreEqual ( "commit2" , buildInfo . BaselineVersionTag . CommitHash ) ;
412+ }
413+
414+ /// <summary>
415+ /// Test that pre-release baseline selection returns null when all previous versions have the same hash.
416+ /// This is an edge case where all previous tags are re-tags of the current commit.
417+ /// </summary>
418+ [ TestMethod ]
419+ public async Task GitHubRepoConnector_GetBuildInformationAsync_PreReleaseAllPreviousSameHash_ReturnsNullBaseline ( )
420+ {
421+ // Arrange - Create mock responses where all versions are on the same commit
422+ using var mockHandler = new MockGitHubGraphQLHttpMessageHandler ( )
423+ . AddCommitsResponse ( "same-hash-123" )
424+ . AddReleasesResponse (
425+ new MockRelease ( "1.1.2-rc.1" , "2024-03-03T00:00:00Z" ) ,
426+ new MockRelease ( "1.1.2-beta.2" , "2024-03-02T00:00:00Z" ) ,
427+ new MockRelease ( "1.1.2-beta.1" , "2024-03-01T00:00:00Z" ) )
428+ . AddPullRequestsResponse ( )
429+ . AddIssuesResponse ( )
430+ . AddTagsResponse (
431+ new MockTag ( "1.1.2-rc.1" , "same-hash-123" ) ,
432+ new MockTag ( "1.1.2-beta.2" , "same-hash-123" ) ,
433+ new MockTag ( "1.1.2-beta.1" , "same-hash-123" ) ) ;
434+
435+ using var mockHttpClient = new HttpClient ( mockHandler ) ;
436+ var connector = new MockableGitHubRepoConnector ( mockHttpClient ) ;
437+
438+ // Set up mock command responses
439+ connector . SetCommandResponse ( "git remote get-url origin" , "https://github.com/test/repo.git" ) ;
440+ connector . SetCommandResponse ( "git rev-parse --abbrev-ref HEAD" , "main" ) ;
441+ connector . SetCommandResponse ( "git rev-parse HEAD" , "same-hash-123" ) ;
442+ connector . SetCommandResponse ( "gh auth token" , "test-token" ) ;
443+
444+ // Act - Process 1.1.2-rc.1
445+ var buildInfo = await connector . GetBuildInformationAsync ( Version . Create ( "1.1.2-rc.1" ) ) ;
446+
447+ // Assert
448+ Assert . IsNotNull ( buildInfo ) ;
449+ Assert . AreEqual ( "1.1.2-rc.1" , buildInfo . CurrentVersionTag . VersionInfo . FullVersion ) ;
450+ Assert . AreEqual ( "same-hash-123" , buildInfo . CurrentVersionTag . CommitHash ) ;
451+
452+ // Should have null baseline since all previous versions are on the same hash
453+ Assert . IsNull ( buildInfo . BaselineVersionTag ) ;
454+ }
268455}
0 commit comments