diff --git a/.gitignore b/.gitignore index 03b7512a00c05..96e153ea6e266 100644 --- a/.gitignore +++ b/.gitignore @@ -46,4 +46,3 @@ yarn-error.log # Cloud9 .c9 -/.versionrc.json diff --git a/.versionrc.json b/.versionrc.json new file mode 100644 index 0000000000000..3178955551057 --- /dev/null +++ b/.versionrc.json @@ -0,0 +1,5 @@ +{ + "skip": { "tag": true }, + "packageFiles": [ { "filename": "lerna.json", "type": "json" } ], + "bumpFiles": [ { "filename": "lerna.json", "type": "json" } ] +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7ff39118418be..0c5137c77a4a5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -779,59 +779,24 @@ CDK](https://github.com/aws/aws-cdk/issues/3398) we will either remove the legacy behavior or flip the logic for all these features and then reset the `FEATURE_FLAGS` map for the next cycle. -### Versioning and Release - -The `release.json` file at the root of the repo determines which release line -this branch belongs to. - -```js -{ - "majorVersion": "1" | "2", - "releaseType": "stable" | "alpha" | "rc" -} -``` - -To reduce merge conflicts in automatic merges between version branches, the -current version number is stored under `version.vNN.json` (where `NN` is -`majorVersion`) and changelogs are stored under `CHANGELOG.NN.md` (for -historical reasons, the changelog for 1.x is under `CHANGELOG.md`). When we -fork to a new release branch (e.g. `main-v2`), we will update `release.json` in -this branch to reflect the new version line, and this information will be used -to determine how releases are cut. - -The actual `version` field in all `package.json` files should always be `0.0.0`. -This means that local development builds will use version `0.0.0` instead of the -official version from the version file. - -#### `./bump.sh` - -This script uses [standard-version] to update the version in `version.vNN.json` -to the next version. By default it will perform a **minor** bump, but `./bump.sh -patch` can be used to perform a patch release if that's needed. - -This script will also update the relevant changelog file. - -[standard-version]: https://github.com/conventional-changelog/standard-version - -#### `scripts/resolve-version.js` - -The script evaluates evaluates the configuration in `release.json` exports an -object like this: - -```js -{ - version: '2.0.0-alpha.1', // the current version - versionFile: 'version.v2.json', // the version file - changelogFile: 'CHANGELOG.v2.md', // changelog file name - prerelease: 'alpha', // prerelease tag (undefined for stable) - marker: '0.0.0' // version marker in package.json files -} -``` - -#### scripts/align-version.sh - -In official builds, the `scripts/align-version.sh` is used to update all -`package.json` files based on the version from `version.vNN.json`. +### Versioning + +All `package.json` files in this repo use a stable marker version of `0.0.0`. +This means that when you declare dependencies, you should always use `0.0.0`. +This makes it easier for us to bump a new version (the `bump.sh` script will +just update the central version and create a CHANGELOG entry) and also reduces +the chance of merge conflicts after a new version is released. + +Additional scripts that take part in the versioning mechanism: + +- `scripts/get-version.js` can be used to obtain the actual version of the repo. + You can use either from JavaScript code by `require('./scripts/get-version')` + or from a shell script `node -p "require('./scripts/get-version')"`. +- `scripts/get-version-marker.js` returns `0.0.0` and used to DRY the version + marker. +- `scripts/align-version.sh` and `scripts/align-version.js` are used to align + all package.json files in the repo to the official version. This script is + invoked in CI builds and should not be used inside a development environment. ## Troubleshooting diff --git a/bump.sh b/bump.sh index 750d452da496d..028779e5a748d 100755 --- a/bump.sh +++ b/bump.sh @@ -13,4 +13,21 @@ # # -------------------------------------------------------------------------------------------------- set -euo pipefail -./scripts/bump.js ${1:-minor} +version=${1:-minor} + +echo "Starting ${version} version bump" + +# /bin/bash ./install.sh + +# Generate CHANGELOG and create a commit (see .versionrc.json) +npx standard-version --release-as ${version} + +# I am sorry. +# +# I've gone diving through the code of `conventional-changelog` to see if there +# was a way to configure the string and ultimately I decided that a 'sed' was the simpler +# way to go. +sed -i.tmp -e 's/BREAKING CHANGES$/BREAKING CHANGES TO EXPERIMENTAL FEATURES/' CHANGELOG.md +rm CHANGELOG.md.tmp +git add CHANGELOG.md +git commit --amend --no-edit diff --git a/lerna.json b/lerna.json index 0fcae573a32ae..16f32cc984c13 100644 --- a/lerna.json +++ b/lerna.json @@ -8,9 +8,8 @@ "packages/@aws-cdk-containers/*", "packages/@monocdk-experiment/*", "packages/@aws-cdk/*/lambda-packages/*", - "tools/*", - "scripts/script-tests" + "tools/*" ], "rejectCycles": "true", - "version": "0.0.0" + "version": "1.71.0" } diff --git a/pack.sh b/pack.sh index a61a461ce9f3e..02b901f141273 100755 --- a/pack.sh +++ b/pack.sh @@ -7,11 +7,6 @@ export PATH=$PWD/node_modules/.bin:$PATH export NODE_OPTIONS="--max-old-space-size=4096 ${NODE_OPTIONS:-}" root=$PWD -# Get version and changelog file name (these require that .versionrc.json would have been generated) -version=$(node -p "require('./scripts/resolve-version').version") -changelog_file=$(node -p "require('./scripts/resolve-version').changelogFile") -marker=$(node -p "require('./scripts/resolve-version').marker") - PACMAK=${PACMAK:-jsii-pacmak} ROSETTA=${ROSETTA:-jsii-rosetta} TMPDIR=${TMPDIR:-$(dirname $(mktemp -u))} @@ -62,6 +57,15 @@ done # Remove a JSII aggregate POM that may have snuk past rm -rf dist/java/software/amazon/jsii +# Get version +version="$(node -p "require('./scripts/get-version')")" + +# Ensure we don't publish anything beyond 1.x for now +if [[ ! "${version}" == "1."* ]]; then + echo "ERROR: accidentally releasing a major version? Expecting repo version to start with '1.' but got '${version}'" + exit 1 +fi + # Get commit from CodePipeline (or git, if we are in CodeBuild) # If CODEBUILD_RESOLVED_SOURCE_VERSION is not defined (i.e. local # build or CodePipeline build), use the HEAD commit hash). @@ -79,11 +83,12 @@ cat > ${distdir}/build.json < { - console.error(err.stack); - process.exit(1); -}); \ No newline at end of file diff --git a/scripts/changelog-experimental-fix.sh b/scripts/changelog-experimental-fix.sh deleted file mode 100755 index 15284ac0c69bc..0000000000000 --- a/scripts/changelog-experimental-fix.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -set -euo pipefail -changelog="${1:-}" - -if [ -z "${changelog}" ]; then - echo "Usage: $0 CHANGELOG.md" - exit 1 -fi - -sed -i.tmp -e 's/BREAKING CHANGES$/BREAKING CHANGES TO EXPERIMENTAL FEATURES/' ${changelog} -rm ${changelog}.tmp diff --git a/scripts/get-version-marker.js b/scripts/get-version-marker.js new file mode 100644 index 0000000000000..e5f8c49806a67 --- /dev/null +++ b/scripts/get-version-marker.js @@ -0,0 +1,13 @@ +/** + * Returns the version marker used to indicate this is a local dependency. + * + * Usage: + * + * const version = require('./get-version-marker'); + * + * Or from the command line: + * + * node -p require('./get-version-marker') + * + */ +module.exports = '0.0.0'; diff --git a/scripts/get-version.js b/scripts/get-version.js new file mode 100644 index 0000000000000..9e6972582c427 --- /dev/null +++ b/scripts/get-version.js @@ -0,0 +1,18 @@ +/** + * Returns the current repo version. + * + * Usage: + * + * const version = require('./get-version'); + * + * Or from the command line: + * + * node -p require('./get-version') + * + */ +const versionFile = require('../.versionrc.json').packageFiles[0].filename; +if (!versionFile) { + throw new Error(`unable to determine version filename from .versionrc.json at the root of the repo`); +} + +module.exports = require(`../${versionFile}`).version; diff --git a/scripts/resolve-version-lib.js b/scripts/resolve-version-lib.js deleted file mode 100755 index bc14d278d1a5e..0000000000000 --- a/scripts/resolve-version-lib.js +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env node -const path = require('path'); -const fs = require('fs'); - -//============================================================= -// UNIT TESTS: tools/script-tests/test/resolve-version.test.js -//============================================================= - -function resolveVersion(rootdir) { - const ALLOWED_RELEASE_TYPES = [ 'alpha', 'rc', 'stable' ]; - const MIN_MAJOR = 1, MAX_MAJOR = 2; // extra safety: update to allow new major versions - - // - // parse release.json - // - const releaseFile = path.join(rootdir, 'release.json'); - const releaseConfig = require(releaseFile); - const majorVersion = releaseConfig.majorVersion; - const releaseType = releaseConfig.releaseType; - if (!majorVersion) { throw new Error(`"majorVersion"" must be defined in ${releaseFile}`); } - if (!releaseType) { throw new Error(`"releaseType" must be defined in ${releaseFile}`); } - if (typeof(majorVersion) !== 'number') { throw new Error(`majorVersion=${majorVersion} must be a number`); } - if (majorVersion < MIN_MAJOR || majorVersion > MAX_MAJOR) { throw new Error(`majorVersion=${majorVersion} is an unsupported major version (should be between ${MIN_MAJOR} and ${MAX_MAJOR})`); } - if (!ALLOWED_RELEASE_TYPES.includes(releaseType)) { throw new Error(`releaseType=${releaseType} is not allowed. Allowed values: ${ALLOWED_RELEASE_TYPES.join(',')}`); } - - // - // resolve and check that we have a version file - // - - const versionFile = `version.v${majorVersion}.json`; - const versionFilePath = path.join(rootdir, versionFile); - if (!fs.existsSync(versionFilePath)) { - throw new Error(`unable to find version file ${versionFile} for major version ${majorVersion}`); - } - - // - // validate that current version matches the requirements - // - - const currentVersion = require(versionFilePath).version; - console.error(`current version: ${currentVersion}`); - if (!currentVersion.startsWith(`${majorVersion}.`)) { - throw new Error(`current version "${currentVersion}" does not use the expected major version ${majorVersion}`); - } - if (releaseType === 'stable') { - if (currentVersion.includes('-')) { - throw new Error(`found pre-release tag in version specified in ${versionFile} is ${currentVersion} but "releaseType"" is set to "stable"`); - } - } else { - if (!currentVersion.includes(`-${releaseType}.`)) { - throw new Error(`could not find pre-release tag "${releaseType}" in current version "${currentVersion}" defined in ${versionFile}`); - } - } - - // - // determine changelog file name - // - - const changelogFile = majorVersion === '1' - ? 'CHANGELOG.md' - : `CHANGELOG.v${majorVersion}.md`; - - // - // export all of it - // - - return { - version: currentVersion, - versionFile: versionFile, - changelogFile: changelogFile, - prerelease: releaseType !== 'stable' ? releaseType : undefined, - marker: '0.0.0', - }; -} - -module.exports = resolveVersion; \ No newline at end of file diff --git a/scripts/resolve-version.js b/scripts/resolve-version.js deleted file mode 100755 index 0f101333d95be..0000000000000 --- a/scripts/resolve-version.js +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env node -const ROOTDIR = path.resolve(__dirname, '..'); -const resolveVersion = require('./resolve-version-lib'); -module.exports = resolveVersion(ROOTDIR); diff --git a/scripts/script-tests/.gitignore b/scripts/script-tests/.gitignore deleted file mode 100644 index dfd5365951031..0000000000000 --- a/scripts/script-tests/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ - -.LAST_BUILD -*.snk -junit.xml -.nyc_output -coverage -nyc.config.js -!.eslintrc.js \ No newline at end of file diff --git a/scripts/script-tests/README.md b/scripts/script-tests/README.md deleted file mode 100644 index a819fff580b1e..0000000000000 --- a/scripts/script-tests/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# script tests - -This directory includes tests for scripts under `./scripts`. \ No newline at end of file diff --git a/scripts/script-tests/package.json b/scripts/script-tests/package.json deleted file mode 100644 index 2c6d0ff48e94a..0000000000000 --- a/scripts/script-tests/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "script-tests", - "private": true, - "version": "0.0.0", - "description": "various tests for development and build scripts", - "scripts": { - "build": "echo ok", - "test": "jest", - "build+test": "npm run build && npm test", - "build+test+package": "npm run build+test" - }, - "devDependencies": { - "jest": "^26.6.2" - } -} diff --git a/scripts/script-tests/resolve-version.test.js b/scripts/script-tests/resolve-version.test.js deleted file mode 100644 index 075f768fe6801..0000000000000 --- a/scripts/script-tests/resolve-version.test.js +++ /dev/null @@ -1,132 +0,0 @@ -const fs = require('fs'); -const os = require('os'); -const path = require('path'); -const resolveVersion = require('../resolve-version-lib'); - -beforeAll(() => spyOn(console, 'error')); - -happy({ - name: 'stable release', - inputs: { - 'release.json': { majorVersion: 2, releaseType: 'stable' }, - 'version.v2.json': { version: '2.1.0' }, - }, - expected: { - changelogFile: 'CHANGELOG.v2.md', - marker: '0.0.0', - prerelease: undefined, - version: '2.1.0', - versionFile: 'version.v2.json' - } -}); - -happy({ - name: 'alpha releases', - inputs: { - 'release.json': { majorVersion: 2, releaseType: 'alpha' }, - 'version.v2.json': { version: '2.1.0-alpha.0' }, - }, - expected: { - changelogFile: 'CHANGELOG.v2.md', - marker: '0.0.0', - prerelease: 'alpha', - version: '2.1.0-alpha.0', - versionFile: 'version.v2.json' - } -}); - -happy({ - name: 'rc releases', - inputs: { - 'release.json': { majorVersion: 2, releaseType: 'rc' }, - 'version.v2.json': { version: '2.1.0-rc.0' }, - }, - expected: { - changelogFile: 'CHANGELOG.v2.md', - marker: '0.0.0', - prerelease: 'rc', - version: '2.1.0-rc.0', - versionFile: 'version.v2.json' - } -}); - -failure({ - name: 'invalid release type', - inputs: { 'release.json': { majorVersion: 2, releaseType: 'build' } }, - expected: 'releaseType=build is not allowed. Allowed values: alpha,rc,stable' -}); - -failure({ - name: 'invalid major version (less then min)', - inputs: { 'release.json': { majorVersion: -1, releaseType: 'rc' } }, - expected: 'majorVersion=-1 is an unsupported major version (should be between 1 and 2)' -}); - -failure({ - name: 'invalid major version (over max)', - inputs: { 'release.json': { majorVersion: 3, releaseType: 'rc' } }, - expected: 'majorVersion=3 is an unsupported major version (should be between 1 and 2)' -}); - -failure({ - name: 'invalid major version (non-number)', - inputs: { 'release.json': { majorVersion: '2', releaseType: 'rc' } }, - expected: 'majorVersion=2 must be a number' -}); - -failure({ - name: 'no version file', - inputs: { 'release.json': { majorVersion: 2, releaseType: 'alpha' } }, - expected: 'unable to find version file version.v2.json for major version 2' -}); - -failure({ - name: 'actual version not the right major', - inputs: { - 'release.json': { majorVersion: 1, releaseType: 'stable' }, - 'version.v1.json': { version: '2.0.0' } - }, - expected: 'current version "2.0.0" does not use the expected major version 1' -}); - -failure({ - name: 'actual version not the right pre-release', - inputs: { - 'release.json': { majorVersion: 2, releaseType: 'alpha' }, - 'version.v2.json': { version: '2.0.0-rc.0' } - }, - expected: 'could not find pre-release tag "alpha" in current version "2.0.0-rc.0" defined in version.v2.json' -}); - -failure({ - name: 'actual version not the right pre-release (stable)', - inputs: { - 'release.json': { majorVersion: 2, releaseType: 'stable' }, - 'version.v2.json': { version: '2.0.0-alpha.0' } - }, - expected: 'found pre-release tag in version specified in version.v2.json is 2.0.0-alpha.0 but "releaseType"" is set to "stable"' -}); - -function happy({ name, inputs, expected } = opts) { - test(name, () => { - const tmpdir = stage(inputs); - const actual = resolveVersion(tmpdir); - expect(actual).toStrictEqual(expected); - }); -} - -function failure({ name, inputs, expected } = opts) { - test(name, () => { - const tmpdir = stage(inputs); - expect(() => resolveVersion(tmpdir)).toThrow(expected); - }); -} - -function stage(inputs) { - const tmpdir = fs.mkdtempSync(path.join(os.tmpdir(), 'resolve-version-')); - for (const [ name, contents ] of Object.entries(inputs)) { - const data = typeof(contents) === 'string' ? contents : JSON.stringify(contents); - fs.writeFileSync(path.join(tmpdir, name), data); - } - return tmpdir; -} diff --git a/tools/pkglint/lib/rules.ts b/tools/pkglint/lib/rules.ts index 9c35dc39ca0f0..23c791c4cac23 100644 --- a/tools/pkglint/lib/rules.ts +++ b/tools/pkglint/lib/rules.ts @@ -1499,14 +1499,9 @@ function hasIntegTests(pkg: PackageJson) { * Return whether this package should use CDK build tools */ function shouldUseCDKBuildTools(pkg: PackageJson) { - const exclude = [ - 'cdk-build-tools', - 'merkle-build', - 'awslint', - 'script-tests', - ]; - - return !exclude.includes(pkg.packageName); + // The packages that DON'T use CDKBuildTools are the package itself + // and the packages used by it. + return pkg.packageName !== 'cdk-build-tools' && pkg.packageName !== 'merkle-build' && pkg.packageName !== 'awslint'; } function repoRoot(dir: string) { diff --git a/version.v1.json b/version.v1.json deleted file mode 100644 index 003975241dcee..0000000000000 --- a/version.v1.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "version": "1.71.0" -} \ No newline at end of file