diff --git a/scripts/lib/packages-directory-names.js b/scripts/lib/packages-directory-names.js new file mode 100644 index 0000000000..462c5292d5 --- /dev/null +++ b/scripts/lib/packages-directory-names.js @@ -0,0 +1,6 @@ +const { readdirSync } = require('fs') +const PACKAGES_DIRECTORY_NAMES = readdirSync('packages') + +module.exports = { + packagesDirectoryNames: PACKAGES_DIRECTORY_NAMES, +} diff --git a/scripts/release/generate-changelog.js b/scripts/release/generate-changelog.js index 411a6c8fe0..ab15d5fa2d 100644 --- a/scripts/release/generate-changelog.js +++ b/scripts/release/generate-changelog.js @@ -1,6 +1,7 @@ 'use strict' const util = require('util') +const fs = require('fs') const readFile = util.promisify(require('fs').readFile) const emojiNameMap = require('emoji-name-map') @@ -9,11 +10,11 @@ const { browserSdkVersion } = require('../lib/browser-sdk-version') const { spawnCommand, printError, runMain } = require('../lib/execution-utils') const { command } = require('../lib/command') const { modifyFile } = require('../lib/files-utils') +const { packagesDirectoryNames } = require('../lib/packages-directory-names') const CHANGELOG_FILE = 'CHANGELOG.md' const CONTRIBUTING_FILE = 'CONTRIBUTING.md' const PUBLIC_EMOJI_PRIORITY = ['💥', '✨', '🐛', '⚡', '📝'] - const INTERNAL_EMOJI_PRIORITY = [ '👷', '🔧', @@ -29,6 +30,20 @@ const INTERNAL_EMOJI_PRIORITY = [ '⚗️', // experiment ] const EMOJI_REGEX = /^\p{Emoji_Presentation}/u + +const PACKAGES_REVERSE_DEPENDENCIES = (() => { + const result = new Map() + packagesDirectoryNames.forEach((packageDirectoryName) => { + for (const dependency of getDepenciesRecursively(packageDirectoryName)) { + if (!result.has(dependency)) { + result.set(dependency, new Set()) + } + result.get(dependency).add(packageDirectoryName) + } + }) + return result +})() + runMain(async () => { if (!process.env.EDITOR) { printError('Please configure your environment variable EDITOR') @@ -88,7 +103,7 @@ function getChangesList() { const lastTagHash = command`git rev-list --tags --max-count=1`.run().trim() const lastTagName = command`git describe --tags ${lastTagHash}`.run() - const commits = command`git log ${lastTagName.trimEnd()}..HEAD --pretty=format:%s`.run() + const commits = command`git log ${[`${lastTagName.trimEnd()}..HEAD`, '--pretty=format:%H %s']}`.run() const changesWithEmojis = emojiNameToUnicode(commits) let changes = changesWithEmojis.split('\n').filter(isNotVersionEntry) @@ -97,10 +112,18 @@ function getChangesList() { changes.forEach((entry) => { let trimmedEntry = entry.trim() - if (PUBLIC_EMOJI_PRIORITY.some((emoji) => trimmedEntry.startsWith(emoji))) { - publicChanges.push(entry) + const hash = trimmedEntry.split(' ')[0] + const message = trimmedEntry.slice(trimmedEntry.indexOf(' ') + 1) + const affectedPackages = getAffectedPackages(hash) + + const formattedPackages = affectedPackages + .map((packageDirectoryName) => `[${packageDirectoryName.toUpperCase()}]`) + .join(' ') + + if (PUBLIC_EMOJI_PRIORITY.some((emoji) => message.startsWith(emoji))) { + publicChanges.push(`${message} ${formattedPackages}`) } else { - internalChanges.push(entry) + internalChanges.push(`${message} ${formattedPackages}`) } }) @@ -120,6 +143,38 @@ ${internalChanges.join('\n')} `.replace(/\(#(\d+)\)/gm, (_, id) => `([#${id}](https://github.com/DataDog/browser-sdk/pull/${id}))`) } +function getAffectedPackages(hash) { + const changedFiles = command`git diff-tree --no-commit-id --name-only -r ${hash}`.run().trim().split('\n') + const affectedPackages = new Set() + + changedFiles.forEach((filePath) => { + const packageDirectoryName = getPackageDirectoryNameFromFilePath(filePath) + if (packageDirectoryName) { + if (!isToplevelPackage(packageDirectoryName)) { + PACKAGES_REVERSE_DEPENDENCIES.get(packageDirectoryName).forEach((dependentPackageDirectoryName) => { + if (isToplevelPackage(dependentPackageDirectoryName)) { + affectedPackages.add(dependentPackageDirectoryName) + } + }) + } else { + affectedPackages.add(packageDirectoryName) + } + } + }) + + return Array.from(affectedPackages) +} + +function getPackageDirectoryNameFromFilePath(filePath) { + if (filePath.startsWith('packages/')) { + return filePath.split('/')[1] + } +} + +function isToplevelPackage(packageDirectoryName) { + return !PACKAGES_REVERSE_DEPENDENCIES.has(packageDirectoryName) +} + function sortByEmojiPriority(a, b, priorityList) { const getFirstRelevantEmojiIndex = (text) => { const matches = text.match(EMOJI_REGEX) || [] @@ -137,3 +192,25 @@ function emojiNameToUnicode(changes) { function isNotVersionEntry(line) { return !/^v\d+\.\d+\.\d+/.test(line) } +function getPackageDirectoryNameFromPackageName(packageName) { + if (packageName.startsWith('@datadog/browser-')) { + return packageName.slice('@datadog/browser-'.length) + } +} + +function getDepenciesRecursively(packageDirectoryName) { + const packageDirectoryNameJson = JSON.parse( + fs.readFileSync(`packages/${packageDirectoryName}/package.json`, { encoding: 'utf-8' }) + ) + const dependencies = new Set() + if (packageDirectoryNameJson.dependencies) { + for (const dependencyPackageName of Object.keys(packageDirectoryNameJson.dependencies)) { + const packageDirectoryName = getPackageDirectoryNameFromPackageName(dependencyPackageName) + dependencies.add(packageDirectoryName) + for (let transitiveDependency of getDepenciesRecursively(packageDirectoryName)) { + dependencies.add(transitiveDependency) + } + } + } + return dependencies +} diff --git a/scripts/release/update-peer-dependency-versions.js b/scripts/release/update-peer-dependency-versions.js index cdfea976b7..c6d63dad6e 100644 --- a/scripts/release/update-peer-dependency-versions.js +++ b/scripts/release/update-peer-dependency-versions.js @@ -1,10 +1,10 @@ -const { readdirSync } = require('fs') const { runMain } = require('../lib/execution-utils') const { modifyFile } = require('../lib/files-utils') const { command } = require('../lib/command') const { browserSdkVersion } = require('../lib/browser-sdk-version') +const { packagesDirectoryNames } = require('../lib/packages-directory-names') -const JSON_FILES = readdirSync('./packages').map((packageName) => `./packages/${packageName}/package.json`) +const JSON_FILES = packagesDirectoryNames.map((packageName) => `./packages/${packageName}/package.json`) // This script updates the peer dependency versions between rum and logs packages to match the new // version during a release.