@@ -33,21 +33,25 @@ is constructed dynamically by scanning all the .so files directly under the C<in
3333
3434=item 3.
3535
36- The module identifies a baseline reference for comparison. This can be :
36+ The module identifies a baseline reference for comparison by using the following precedence order :
3737
3838=over
3939
4040=item *
4141
42- The most recent tag on the branch (e.g., REL_16_1), if found and not older than the branch point .
42+ The tag specified for the current branch in the animal's configuration file using C< tag_for_branch > .
4343
4444=item *
4545
46- The first commit of the current branch, if no suitable tag is found or if the latest tag predates the branch.
46+ A custom commit/tag specified in C<pgsql/.abi-compliance-history > file.
47+
48+ =item *
49+
50+ The most recent tag on the branch (e.g., REL_16_1), if found and not older than the branch point.
4751
4852=item *
4953
50- A custom commit/tag specified in C< pgsql/.abi-compliance-history > file (this overrides the automatic selection) .
54+ The first commit of the current branch as the last fallback, if no suitable tag is found or if the latest tag predates the branch .
5155
5256=back
5357
@@ -75,7 +79,7 @@ directory.
7579
7680It uses C<abidw > to generate XML representations of the ABI for key binaries
7781(the C<postgres > executable and all shared libraries found directly under the
78- installation's C<lib > directory) from this baseline build. These are stored for
82+ installation's C<lib > directory) from this baseline build. These are stored for
7983future runs.
8084
8185=back
@@ -131,7 +135,7 @@ An array reference containing flags to pass to C<abidw>. Defaults to:
131135A hash reference mapping branch names to their corresponding tags or tag
132136patterns for ABI comparison. Supports exact tag names or patterns (e.g.,
133137'REL_17_*'). If a pattern matches multiple tags, the first one is used. Defaults
134- to empty hash, which means automatic tag selection for all branches.
138+ to an empty hash, which means automatic tag selection for all branches.
135139
136140=back
137141
@@ -152,7 +156,7 @@ ABI policy for minor releases.
152156
153157=item *
154158
155- Debug information is required in the build to be able to use this module
159+ Debug information is required in the build to be able to use this module.
156160
157161=item *
158162
@@ -296,7 +300,7 @@ sub setup
296300 mkdir $abi_compare_root
297301 unless -d $abi_compare_root ;
298302
299- # could even set up several of these (e.g. for different branches)
303+ # Store module configuration for later use in hooks.
300304 my $self = {
301305 buildroot => $buildroot ,
302306 pgbranch => $branch ,
@@ -313,6 +317,118 @@ sub setup
313317 return ;
314318}
315319
320+ # Determine the comparison reference from the animal's config file.
321+ sub _get_comparison_ref_from_config
322+ {
323+ my $self = shift ;
324+ my $tag_pattern = $self -> {tag_for_branch }-> { $self -> {pgbranch } };
325+ my @tags = run_log(qq{ git -C ./pgsql tag --list '$tag_pattern '} )
326+ ; # get the list of tags based on the tag pattern provided in config
327+ chomp (@tags );
328+
329+ unless (@tags )
330+ {
331+ emit
332+ " Specified tag pattern '$tag_pattern ' for branch '$self ->{pgbranch}' does not match any tags." ;
333+ return ' ' ;
334+ }
335+
336+ # If multiple tags match, use the first one.
337+ return $tags [0];
338+ }
339+
340+ # Determine the comparison reference from the .abi-compliance-history file.
341+ sub _get_comparison_ref_from_history_file
342+ {
343+ my $self = shift ;
344+
345+ # this function reads the .abi-compliance-history file and returns the first valid line
346+ # that is not a comment(starting with a '#' symbol) or empty line, assumes it to be a commit SHA
347+ # and verifies if it actually exists in the git history
348+ open my $fh , ' <' , " pgsql/.abi-compliance-history"
349+ or die " Cannot open pgsql/.abi-compliance-history: $! " ;
350+ while (my $line = <$fh >)
351+ {
352+ next if $line =~ / ^\s *#/ || $line =~ / ^\s *$ / ;
353+ $line =~ s /\s *#.*// ;
354+ $line =~ s / ^\s +|\s +$// g ;
355+
356+ # Check that the commit SHA actually exists.
357+ my $exit_status =
358+ system (qq{ git -C ./pgsql cat-file -e $line ^{commit} 2>/dev/null} );
359+ if ($exit_status != 0)
360+ {
361+ die
362+ " Wrong or non-existent commit/tag '$line ' found in .abi-compliance-history" ;
363+ }
364+ close $fh ;
365+ return $line ;
366+ }
367+ return ' ' ;
368+ }
369+
370+ # Determine the default comparison reference by finding the latest tag or the
371+ # first commit of the branch.
372+ sub _get_default_comparison_ref
373+ {
374+ my $self = shift ;
375+
376+ # Find the most recent tag on the branch, or fallback to first commit of branch
377+
378+ my $pgbranch = $self -> {pgbranch };
379+ my $comparison_ref = ' ' ;
380+
381+ # If no specific tag is configured, find the most recent tag on the branch.
382+ emit " Finding latest tag for branch $pgbranch " ;
383+ my $baseline =
384+ run_log(qq{ git -C ./pgsql describe --tags --abbrev=0 2>/dev/null} );
385+ chomp $baseline ;
386+
387+ # Default to the latest tag if found.
388+ if ($baseline )
389+ {
390+ # Find the first commit of the current branch.
391+ my $first_commit =
392+ run_log(qq{ git -C ./pgsql merge-base master bf_$pgbranch } );
393+ die " git merge-base failed: $? " if $? ;
394+ chomp $first_commit ;
395+
396+ # Check if the latest tag is an ancestor of the first commit of the branch.
397+ # If it is, it's likely a tag from a previous branch, so we should
398+ # use the first commit of the current branch as the baseline instead.
399+ my $is_ancestor = system (
400+ qq{ git -C ./pgsql merge-base --is-ancestor $baseline $first_commit 2>/dev/null}
401+ );
402+
403+ if ($is_ancestor == 0)
404+ {
405+ # The tag is an ancestor of the branch point, so it's too old.
406+ # Use the first commit of the branch as the baseline.
407+ $comparison_ref = $first_commit ;
408+ emit
409+ " Latest tag '$baseline ' is older than branch point. Using first branch commit '$comparison_ref ' as baseline." ;
410+ }
411+ else
412+ {
413+ # The tag is on the current branch, so use it.
414+ $comparison_ref = $baseline ;
415+ emit " Using latest tag '$comparison_ref ' as baseline." ;
416+ }
417+ }
418+ else
419+ {
420+ # As a fallback, find the first commit of the current branch.
421+ # This is not ideal as it might be too old for a meaningful ABI comparison.
422+ $comparison_ref =
423+ run_log(qq{ git -C ./pgsql merge-base master bf_$pgbranch } );
424+ die " git merge-base failed: $? " if $? ;
425+ chomp $comparison_ref ;
426+ emit
427+ " No tags found. Using first branch commit '$comparison_ref ' as baseline." ;
428+ }
429+ return $comparison_ref ;
430+ }
431+
316432# Main function - runs after PostgreSQL installation to perform ABI comparison
317433sub installcheck
318434{
@@ -344,98 +460,28 @@ sub installcheck
344460 my $tag_for_branch = $self -> {tag_for_branch } || {};
345461 my $comparison_ref = ' ' ;
346462
347- # find the tag to compare with for the branch
463+ # Determine the baseline reference for comparison, in order of precedence:
464+ # 1. Animal-specific config
465+ # 2. .abi-compliance-history file
466+ # 3. Default (latest tag or first commit of the branch)
348467 if (exists $tag_for_branch -> {$pgbranch })
349468 {
350- my $tag_pattern = $tag_for_branch -> {$pgbranch };
351- my @tags = run_log(qq{ git -C ./pgsql tag --list '$tag_pattern '} )
352- ; # get the list of tags based on the tag pattern provided in config
353- chomp (@tags );
354-
355- unless (@tags )
356- {
357- emit
358- " Specified tag pattern '$tag_pattern ' for branch '$pgbranch ' does not match any tags." ;
359- return ;
360- }
361-
362- # use the first tag from the list in case of regex
469+ $comparison_ref = $self -> _get_comparison_ref_from_config();
363470 emit
364- " Using $tags [0] as the baseline tag for branch $pgbranch based on pattern ' $tag_pattern ' " ;
365- $comparison_ref = $tags [0] ;
471+ " Using $comparison_ref as the baseline tag based on the animal config "
472+ if $comparison_ref ;
366473 }
367- else
474+ elsif ( -f " pgsql/.abi-compliance-history " )
368475 {
369- # If no specific tag is configured, find the most recent tag on the branch.
370- emit " Finding latest tag for branch $pgbranch " ;
371- my $baseline = run_log(qq{ git -C ./pgsql describe --tags --abbrev=0 2>/dev/null} );
372- chomp $baseline ;
373-
374- # Default to the latest tag if found.
375- if ($baseline )
376- {
377- # Find the first commit of the current branch.
378- my $first_commit =
379- run_log(qq{ git -C ./pgsql merge-base master bf_$pgbranch } );
380- die " git merge-base failed: $? " if $? ;
381- chomp $first_commit ;
382-
383- # Check if the latest tag is an ancestor of the first commit of the branch.
384- # If it is, it's likely a tag from a previous branch, so we should
385- # use the first commit of the current branch as the baseline instead.
386- my $is_ancestor = system (qq{ git -C ./pgsql merge-base --is-ancestor $baseline $first_commit 2>/dev/null} );
387-
388- if ($is_ancestor == 0)
389- {
390- # The tag is an ancestor of the branch point, so it's too old.
391- # Use the first commit of the branch as the baseline.
392- $comparison_ref = $first_commit ;
393- emit " Latest tag '$baseline ' is older than branch point. Using first branch commit '$comparison_ref ' as baseline." ;
394- }
395- else
396- {
397- # The tag is on the current branch, so use it.
398- $comparison_ref = $baseline ;
399- emit " Using latest tag '$comparison_ref ' as baseline." ;
400- }
401- }
402- else
403- {
404- # As a fallback, find the first commit of the current branch.
405- # This is not ideal as it might be too old for a meaningful ABI comparison.
406- $comparison_ref =
407- run_log(qq{ git -C ./pgsql merge-base master bf_$pgbranch } );
408- die " git merge-base failed: $? " if $? ;
409- chomp $comparison_ref ;
410- emit " No tags found. Using first branch commit '$comparison_ref ' as baseline." ;
411- }
412-
413- # Allow overriding the baseline via .abi-compliance-history file.
414- if (-f " pgsql/.abi-compliance-history" )
415- {
416- open my $fh , ' <' , " pgsql/.abi-compliance-history"
417- or die " Cannot open pgsql/.abi-compliance-history: $! " ;
418- while (my $line = <$fh >)
419- {
420- next if $line =~ / ^\s *#/ || $line =~ / ^\s *$ / ;
421- $line =~ s /\s *#.*// ;
422- $line =~ s / ^\s +|\s +$// g ;
423- # Check that the commit/tag actually exists.
424- my $exit_status = system (qq{ git -C ./pgsql cat-file -e $line ^{commit} 2>/dev/null} );
425- if ($exit_status != 0)
426- {
427- die
428- " Wrong or non-existent commit/tag '$line ' found in .abi-compliance-history" ;
429- }
430- $comparison_ref = $line ;
431- emit
432- " Overriding baseline with '$comparison_ref ' from .abi-compliance-history" ;
433- last ;
434- }
435- close $fh ;
436- }
476+ $comparison_ref = $self -> _get_comparison_ref_from_history_file();
477+ emit " Using baseline '$comparison_ref ' from .abi-compliance-history"
478+ if $comparison_ref ;
437479 }
438480
481+ # Fallback to default if no ref is found from config or history file
482+ $comparison_ref = $self -> _get_default_comparison_ref()
483+ unless $comparison_ref ;
484+
439485 # Get the previous tag from the latest_tag file for current branch if it exists.
440486 my $baseline_tag_file = " $abi_compare_loc /latest_tag" ;
441487 my $previous_tag = ' ' ;
@@ -533,7 +579,10 @@ sub installcheck
533579 # Add binaries comparison status to output at the start
534580 if ($success_binaries && @$success_binaries )
535581 {
536- push (@saveout , " Binaries compared: \n " .join (" \n " , sort @$success_binaries )." \n\n " );
582+ push (@saveout ,
583+ " Binaries compared: \n "
584+ . join (" \n " , sort @$success_binaries )
585+ . " \n\n " );
537586 }
538587
539588 # Add comparison results to output
@@ -976,8 +1025,7 @@ sub _compare_and_log_abi_diff
9761025 my $abi_compare_root = $self -> {abi_compare_root };
9771026 my $pgbranch = $self -> {pgbranch };
9781027
979- emit
980- " Comparing ABI between baseline tag $latest_tag and it's latest commit" ;
1028+ emit " Comparing ABI between baseline $latest_tag and the latest commit" ;
9811029
9821030 # Set up directories for comparison
9831031 my $tag_xml_dir = " $abi_compare_root /$pgbranch /$latest_tag /xmls" ;
@@ -1002,7 +1050,7 @@ sub _compare_and_log_abi_diff
10021050 if (-e $tag_file && -e $branch_file )
10031051 {
10041052 push (@success_binaries , $value );
1005-
1053+
10061054 # Run abidiff to compare ABI XML files
10071055 my $log_file = " $log_dir /$key -$latest_tag .log" ;
10081056 my $exit_status = $self -> _log_command_output(
0 commit comments