Skip to content

ci: add TypeScript public interface breaking-change-check project - #9825

Draft
danieljbruce wants to merge 3 commits into
googleapis:mainfrom
danieljbruce:ci/breaking-change-check-b578145435
Draft

danieljbruce wants to merge 3 commits into
googleapis:mainfrom
danieljbruce:ci/breaking-change-check-b578145435

Conversation

@danieljbruce

Copy link
Copy Markdown
Contributor

Description

Adds a compiler-driven TypeScript breaking-change check project and GitHub Actions workflow.

Impact

Catches unannounced breaking public TypeScript interface changes while allowing marked major releases.

Testing

  • Verified consumer probe compilation across all handwritten/core public packages and a representative GAPIC package (>= 28,000 compiled consumer probes, < 1% invalid base probes).
  • Verified breaking-change detection and intent-aware governance (feat!:, fix!:, BREAKING CHANGE: footers, squash-merge title warnings, shallow-clone safety, and strict exports map handling) across 5 consecutive runs on Node.js and 5 consecutive runs on Bun (16 passing each).
  • Verified GIT_DIFF_ARG="upstream/main...HEAD -- :!packages" node ./bin/linter.mjs --strict and GIT_DIFF_ARG="upstream/main...HEAD -- :!packages" ./ci/run_conditional_tests.sh --strict.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a new TypeScript-based breaking change check tool under ci/breaking-change-check and integrates it into the monorepo workspace. It also updates ci/run_conditional_tests.sh to support a new --list-dirs option and includes the ci directory in the test execution paths while excluding the breaking change check from triggering full CI runs. Feedback on the shell script points out a critical bug where pathspecs in GIT_DIFF_ARG can cause incorrect git diff evaluations, falsely triggering full test runs; a suggestion is provided to isolate the commit range and correctly scope the diff to the ci directory.

Comment thread ci/run_conditional_tests.sh Outdated
Comment on lines 115 to 131
if [[ "${GIT_DIFF_ARG}" == *" -- "* ]]; then
ci_diff_sep=""
else
ci_diff_sep="--"
fi
set +e
git diff --quiet ${GIT_DIFF_ARG} ci
git diff --quiet ${GIT_DIFF_ARG} ${ci_diff_sep} ci ':!ci/breaking-change-check' ':!ci/run_conditional_tests.sh'
changed=$?
set -e
if [[ "${changed}" -eq 0 ]]; then
echo "no change detected in ci"
else
echo "change detected in ci, we should test everything"
echo "result of git diff ${GIT_DIFF_ARG} ci:"
git diff ${GIT_DIFF_ARG} ci
echo "result of git diff ${GIT_DIFF_ARG} ${ci_diff_sep} ci ':!ci/breaking-change-check' ':!ci/run_conditional_tests.sh':"
git diff ${GIT_DIFF_ARG} ${ci_diff_sep} ci ':!ci/breaking-change-check' ':!ci/run_conditional_tests.sh'
GIT_DIFF_ARG=""
fi

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.

high

When GIT_DIFF_ARG contains pathspecs (e.g., upstream/main...HEAD -- :!packages), appending ci directly to the command results in multiple pathspecs: :!packages, ci, :!ci/breaking-change-check, and :!ci/run_conditional_tests.sh.

In Git, multiple pathspecs are evaluated as a logical OR. This means any change in a file that is NOT in packages (such as files in core/) will match the :!packages pathspec, causing git diff to exit with a non-zero status even if there are absolutely no changes in the ci directory. This completely breaks the conditional test logic, causing any change in core/ to falsely trigger a full test run ("change detected in ci, we should test everything").

By extracting only the commit range from GIT_DIFF_ARG (using ${GIT_DIFF_ARG%% -- *}) and explicitly using -- ci ..., we ensure that we only check for changes in the ci directory, completely isolating the check from other pathspecs.

Suggested change
if [[ "${GIT_DIFF_ARG}" == *" -- "* ]]; then
ci_diff_sep=""
else
ci_diff_sep="--"
fi
set +e
git diff --quiet ${GIT_DIFF_ARG} ci
git diff --quiet ${GIT_DIFF_ARG} ${ci_diff_sep} ci ':!ci/breaking-change-check' ':!ci/run_conditional_tests.sh'
changed=$?
set -e
if [[ "${changed}" -eq 0 ]]; then
echo "no change detected in ci"
else
echo "change detected in ci, we should test everything"
echo "result of git diff ${GIT_DIFF_ARG} ci:"
git diff ${GIT_DIFF_ARG} ci
echo "result of git diff ${GIT_DIFF_ARG} ${ci_diff_sep} ci ':!ci/breaking-change-check' ':!ci/run_conditional_tests.sh':"
git diff ${GIT_DIFF_ARG} ${ci_diff_sep} ci ':!ci/breaking-change-check' ':!ci/run_conditional_tests.sh'
GIT_DIFF_ARG=""
fi
commit_range="${GIT_DIFF_ARG%% -- *}"
set +e
git diff --quiet ${commit_range} -- ci ':!ci/breaking-change-check' ':!ci/run_conditional_tests.sh'
changed=$?
set -e
if [[ "${changed}" -eq 0 ]]; then
echo "no change detected in ci"
else
echo "change detected in ci, we should test everything"
echo "result of git diff ${commit_range} -- ci ':!ci/breaking-change-check' ':!ci/run_conditional_tests.sh':"
git diff ${commit_range} -- ci ':!ci/breaking-change-check' ':!ci/run_conditional_tests.sh'
GIT_DIFF_ARG=""
fi

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in ff1dcf2: extracted commit_range="${GIT_DIFF_ARG%% -- *}" before running the ci directory diff check so any pathspecs present in GIT_DIFF_ARG are not combined with the ci pathspec.

@danieljbruce

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a new breaking-change-check package under the ci/ directory and integrates it into the workspace. It also updates ci/run_conditional_tests.sh to support a --list-dirs option and refactors how changes in the ci directory are detected and tested. The review feedback suggests improving the robustness of the git diff command in the shell script by isolating the revision range from any pathspecs in GIT_DIFF_ARG, and recommends removing the unused c8 dependency from the new package's configuration.

Comment thread ci/run_conditional_tests.sh Outdated
Comment on lines 115 to 131
if [[ "${GIT_DIFF_ARG}" == *" -- "* ]]; then
ci_diff_sep=""
else
ci_diff_sep="--"
fi
set +e
git diff --quiet ${GIT_DIFF_ARG} ci
git diff --quiet ${GIT_DIFF_ARG} ${ci_diff_sep} ci ':!ci/breaking-change-check' ':!ci/run_conditional_tests.sh'
changed=$?
set -e
if [[ "${changed}" -eq 0 ]]; then
echo "no change detected in ci"
else
echo "change detected in ci, we should test everything"
echo "result of git diff ${GIT_DIFF_ARG} ci:"
git diff ${GIT_DIFF_ARG} ci
echo "result of git diff ${GIT_DIFF_ARG} ${ci_diff_sep} ci ':!ci/breaking-change-check' ':!ci/run_conditional_tests.sh':"
git diff ${GIT_DIFF_ARG} ${ci_diff_sep} ci ':!ci/breaking-change-check' ':!ci/run_conditional_tests.sh'
GIT_DIFF_ARG=""
fi

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.

high

When checking for changes in the ci directory, using GIT_DIFF_ARG directly can lead to incorrect results if it contains pathspecs for other packages (e.g., upstream/main...HEAD -- packages/foo). In such cases, any change in those packages will trigger a full test run, defeating the purpose of conditional testing. Extracting only the revision range using bash parameter expansion ${GIT_DIFF_ARG%% -- *} and explicitly specifying the ci pathspecs is much more robust and correct.

Suggested change
if [[ "${GIT_DIFF_ARG}" == *" -- "* ]]; then
ci_diff_sep=""
else
ci_diff_sep="--"
fi
set +e
git diff --quiet ${GIT_DIFF_ARG} ci
git diff --quiet ${GIT_DIFF_ARG} ${ci_diff_sep} ci ':!ci/breaking-change-check' ':!ci/run_conditional_tests.sh'
changed=$?
set -e
if [[ "${changed}" -eq 0 ]]; then
echo "no change detected in ci"
else
echo "change detected in ci, we should test everything"
echo "result of git diff ${GIT_DIFF_ARG} ci:"
git diff ${GIT_DIFF_ARG} ci
echo "result of git diff ${GIT_DIFF_ARG} ${ci_diff_sep} ci ':!ci/breaking-change-check' ':!ci/run_conditional_tests.sh':"
git diff ${GIT_DIFF_ARG} ${ci_diff_sep} ci ':!ci/breaking-change-check' ':!ci/run_conditional_tests.sh'
GIT_DIFF_ARG=""
fi
set +e
git diff --quiet ${GIT_DIFF_ARG%% -- *} -- ci ':!ci/breaking-change-check' ':!ci/run_conditional_tests.sh'
changed=$?
set -e
if [[ "${changed}" -eq 0 ]]; then
echo "no change detected in ci"
else
echo "change detected in ci, we should test everything"
echo "result of git diff ${GIT_DIFF_ARG%% -- *} -- ci ':!ci/breaking-change-check' ':!ci/run_conditional_tests.sh':"
git diff ${GIT_DIFF_ARG%% -- *} -- ci ':!ci/breaking-change-check' ':!ci/run_conditional_tests.sh'
GIT_DIFF_ARG=""
fi

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in ff1dcf2: replaced ${GIT_DIFF_ARG} ${ci_diff_sep} with commit_range="${GIT_DIFF_ARG%% -- *}" and explicit -- ci ':!ci/breaking-change-check' ':!ci/run_conditional_tests.sh' so package pathspecs in GIT_DIFF_ARG cannot cause false-positive full test runs.

Comment on lines +31 to +33
"@types/node": "^22.13.8",
"c8": "^10.1.3",
"gts": "^6.0.2",

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.

medium

The c8 package is listed as a devDependency but is not used in any of the scripts (which explicitly pass --no-c8 to disable coverage). Removing it keeps the dependencies clean and avoids unnecessary package installations.

Suggested change
"@types/node": "^22.13.8",
"c8": "^10.1.3",
"gts": "^6.0.2",
"@types/node": "^22.13.8",
"gts": "^6.0.2",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in ff1dcf2: removed the unused c8 devDependency from ci/breaking-change-check/package.json and updated pnpm-lock.yaml.

@danieljbruce

Copy link
Copy Markdown
Contributor Author

I think we should close this in favour of #9826

@danieljbruce
danieljbruce marked this pull request as ready for review November 6, 2026 21:45
@danieljbruce
danieljbruce requested a review from a team as a code owner November 6, 2026 21:45
@danieljbruce
danieljbruce marked this pull request as draft November 6, 2026 21:45
@github-actions
github-actions Bot requested a review from shivanee-p November 6, 2026 21:45

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant