Skip to content

Commit

Permalink
fix: API compatibility check fails in CI pipeline (#19069)
Browse files Browse the repository at this point in the history
This is a re-roll of #19070, fixing a bug introduced in that one.

In the master build, we do a version bump which turns `1.146.0` into
`1.146.0-rc.0`, which makes the API compatibility checker try to install
packages with those versions.

Because none of those packages exist, the list of packages ends up
empty, which turns our `npm install $PACKAGES` command into `npm
install`, which subsequently complains that there's no `package.json`.

In order to make this work properly, we need to query the ACTUAL
released version numbers on GitHub so we can properly find the
version to diff against.

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
rix0rrr committed Feb 22, 2022
1 parent a87dee7 commit 6ec1005
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 20 deletions.
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -25,6 +25,7 @@
"jsii-pacmak": "^1.54.0",
"jsii-reflect": "^1.54.0",
"jsii-rosetta": "^1.54.0",
"semver": "^6.3.0",
"lerna": "^4.0.0",
"patch-package": "^6.4.7",
"standard-version": "^9.3.2",
Expand Down
47 changes: 27 additions & 20 deletions scripts/check-api-compatibility.sh
Expand Up @@ -14,7 +14,7 @@ package_name() {
# Doesn't use 'npm view' as that is slow. Direct curl'ing npmjs is better
package_exists_on_npm() {
pkg=$1
ver=$2 # optional
ver=${2:-} # optional
curl -I 2>/dev/null https://registry.npmjs.org/$pkg/$ver | head -n 1 | grep 200 >/dev/null
}

Expand All @@ -32,10 +32,13 @@ jsii_package_dirs=$(list_jsii_packages)

#----------------------------------------------------------------------

# Input a directory, output the directory IF it exists on NPM
# dirs_for_existing_pkgs DIRECTORY VERSION
#
# Input a directory and a version, output the directory IF it exists on NPM at that version
dirs_for_existing_pkgs() {
local dir="$1"
if package_exists_on_npm $(package_name $dir); then
local ver="$2"
if package_exists_on_npm $(package_name $dir) $ver; then
echo "$dir"
echo -n "." >&2
else
Expand All @@ -49,30 +52,34 @@ export -f dirs_for_existing_pkgs

if ! ${SKIP_DOWNLOAD:-false}; then
echo "Filtering on existing packages on NPM..." >&2
# In parallel
existing_pkg_dirs=$(echo "$jsii_package_dirs" | xargs -n1 -P4 -I {} bash -c 'dirs_for_existing_pkgs "$@"' _ {})
existing_names=$(echo "$existing_pkg_dirs" | xargs -n1 -P4 -I {} bash -c 'package_name "$@"' _ {})
echo " Done." >&2

echo "Determining baseline version..." >&2
version=$(node -p 'require("./scripts/resolve-version.js").version')
echo " Current version is $version." >&2
echo "Determining baseline version... " >&2
build_version=$(node -p 'require("./scripts/resolve-version.js").version')
echo "Build version: ${build_version}." >&2

if ! package_exists_on_npm aws-cdk $version; then
major_version=$(echo "$version" | sed -e 's/\..*//g')
echo " Version $version does not exist in npm. Falling back to package major version ${major_version}" >&2
existing_names=$(echo "$existing_names" | sed -e "s/$/@$major_version/")
else
echo "Using version '$version' as the baseline..."
existing_names=$(echo "$existing_names" | sed -e "s/$/@$version/")
fi
# Either called as:
# - find-latest-release "<=2.14.0" (PR build); or
# - find-latest-release "<=2.15.0-rc.0" (CI build); or
# - find-latest-release "<=2.15.0" (release build)
# all of which will find 2.14.0 as the version to compare against.
version=$(node ./scripts/find-latest-release.js "<=${build_version}")
echo "Released version: $version." >&2

echo "Using version '$version' as the baseline..." >&2

# Filter packages by existing at the target version
existing_pkg_dirs=$(echo "$jsii_package_dirs" | xargs -n1 -P4 -I {} bash -c 'dirs_for_existing_pkgs "$@" "'$version'"' _ {})
existing_names=$(echo "$existing_pkg_dirs" | xargs -n1 -P4 -I {} bash -c 'package_name "$@"' _ {})
install_versions=$(for name in $existing_names; do echo "${name}@${version}"; done)
echo " Done." >&2

rm -rf $tmpdir
mkdir -p $tmpdir

echo "Installing from NPM..." >&2
# use npm7 to automatically install peer dependencies
(cd $tmpdir && npx npm@^7.0.0 install --prefix $tmpdir $existing_names)
# Use npm7 instead of whatever the current NPM version is to make sure we
# automatically install peer dependencies
(cd $tmpdir && npx npm@^7.0.0 install --prefix $tmpdir $install_versions)
fi

#----------------------------------------------------------------------
Expand Down
34 changes: 34 additions & 0 deletions scripts/find-latest-release.js
@@ -0,0 +1,34 @@
// Find the latest CDK release on GitHub matching a particular semver range
//
// The range can be something like '<1.2.3' to find the latest release before a given version,
// or '2' to find the latest v2 release.
//
// Only searches the most recent 100 GitHub releases, so only use this to query fairly recent versions.
const cp = require('child_process');
const semver = require('semver');

async function main(matchRange) {
if (matchRange === undefined) {
throw new Error('Usage: find-latest-release.js RANGE');
}
const range = semver.validRange(matchRange);
if (!range) {
throw new Error(`Not a valid range: ${matchRange}`);
}

const { stdout, error } = cp.spawnSync('curl', ['https://api.github.com/repos/aws/aws-cdk/releases?per_page=100'], { maxBuffer: 10_000_000 });
if (error) { throw error; }
const releases = JSON.parse(stdout);
const versions = releases.map(r => r.name.replace(/^v/, '')); // v1.2.3 -> 1.2.3

const sat = semver.maxSatisfying(versions, range);
if (!sat) {
throw new Error(`No range satisfied ${range} (on the first page of GitHub releases)`);
}
console.log(sat);
}

main(process.argv[2]).catch(e => {
console.error(e);
process.exitCode = 1;
});

0 comments on commit 6ec1005

Please sign in to comment.