diff --git a/.gitignore b/.gitignore index 6b8cf44394..2c183ddde3 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,7 @@ bones/ .vs/ .vscode/ -.config/ \ No newline at end of file +.config/ + +# Python virtual environments +**/*env/ \ No newline at end of file diff --git a/tools/changelog/.gitignore b/tools/changelog/.gitignore new file mode 100644 index 0000000000..f8e7b4185b --- /dev/null +++ b/tools/changelog/.gitignore @@ -0,0 +1,3 @@ +# Ignore input and output files for git-log.js +*.txt +*.md \ No newline at end of file diff --git a/tools/changelog/README.md b/tools/changelog/README.md new file mode 100644 index 0000000000..a46bfb2dfc --- /dev/null +++ b/tools/changelog/README.md @@ -0,0 +1,55 @@ +# Generating repository changelogs + +This script uses the developer's clone of the repository to generate a changelog via `git log`. + +## Requirements: +- Node.js > 10.0.0 +- Current clone of https://github.com/microsoft/botframework-sdk +- Current clone of the repository and branch to generate a changelog from + +## Preferred setup: +- **Each repository should only permit squash merges** + - In most scenarios, the developer calling the script will need to manually update the final contents with better descriptions. + - If the repository accepts all PR merge types, the developer will need to perform more manual edits due to the commit messages. + - Squash merges on GitHub result in commit messages like the following: `"Fix fetch in token server used in E2E Streaming Test (#2944)"` + - Other merges will result in commit messages such as: `"Merge pull request #1411 from "` + - This results in a non-descriptive format: + ```md + - Merge pull request #4661 from microsoft/johtaylo/private-cloud-patch [[PR 4661]](https://github.com/microsoft/botbuilder-dotnet/pull/4661) + ``` +- **Developers should generate the changelog from the branch that is about to be released** + - Instead of generating it on the default or development branch (e.g `main`), the script should be run on the version branch (e.g. `4.11`). + +## Steps +_The steps below use [botbuilder-dotnet](https://github.com/microsoft/botbuilder-dotnet) as an example._ +- Clone the target repository and switch to the selected branch for generating a changelog. + - `git clone -b 4.11 https://github.com/microsoft/botbuilder-dotnet && cd botbuilder-dotnet` +- Run `git log` with the following flags and arguments. + - `git log --show-pulls --pretty=tformat:"%s" c6ff4a4.. > dotnet.txt` + - `c6ff4a4..` represents the desired range of commits to log **after commit `c6ff4a4`**. + - In this example, `c6ff4a4` was the latest commit included in the previous changelog. +- Move the `dotnet.txt` file to the folder containing [git-log.js](./git-log.js). +- Navigate to `botframework-sdk\tools\changelog` in your CLI. +- Execute the following command to generate the changelog. + - `node git-log.js dotnet.txt` + - With this command, the changelog can be found as `dotnet.md`. + - `git-log.js` takes an optional second argument which is used as the filename for the output. (Note: the files content will still be [Markdown](https://daringfireball.net/projects/markdown)) + +The contents of the file should look like the following snippet generated for the 4.11.0 release of the Bot Framework SDK for .NET: + +```md +- Teams: MeetingParticipantInfo.InMeeting might be null, if unknown [[PR 4868]](https://github.com/microsoft/botbuilder-dotnet/pull/4868) +- Fix issues with ExpectReplies and Invoke [[PR 4845]](https://github.com/microsoft/botbuilder-dotnet/pull/4845) +- Enable middleware in TestScript and refactor BeginSkill tests [[PR 4866]](https://github.com/microsoft/botbuilder-dotnet/pull/4866) +``` + +## Questions and Help +For bug reports, feature requests or other feedback, please file an issue in https://github.com/microsoft/botframework-sdk. + +## Additional reading +- [About merge methods on GitHub](https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/about-merge-methods-on-github) + - [Squashing your merge commits](https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/about-merge-methods-on-github#squashing-your-merge-commits) +- [Configuring commit squashing for pull requests](https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/configuring-commit-squashing-for-pull-requests) +- [Git - git-log Documentation](https://git-scm.com/docs/git-log) + - [Commit Limiting](https://git-scm.com/docs/git-log#_commit_limiting) (e.g. `--since`, `--before` options) +- [Git - gitrevisions Documentation](https://git-scm.com/docs/gitrevisions) \ No newline at end of file diff --git a/tools/changelog/git-log.js b/tools/changelog/git-log.js new file mode 100644 index 0000000000..c3059e68dc --- /dev/null +++ b/tools/changelog/git-log.js @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +const { createReadStream, createWriteStream, existsSync } = require('fs'); +const { once } = require('events'); +const { join } = require('path'); +const { argv, exit } = require('process'); +const { createInterface } = require('readline'); + +// Remove first two elements from argv, which are `node` and `script.js`. +// Currently the script takes two arguments, which are assigned to +// gitLogFromRepo and optionalOutputName. +const [ gitLogFromRepo, optionalOutputName ] = argv.slice(2); + +if (!gitLogFromRepo) { + throw new TypeError('The captured output of `git log` must be passed in.'); +} + +if (!existsSync(join(__dirname, gitLogFromRepo))) { + throw new ReferenceError(`The provided file "${gitLogFromRepo}" was not found in ${__dirname}`); +} + +// Determine the changelogFile (which contains the formatted merges to main) +// and the repository URL. +let changelogFile; +let repository; +if (gitLogFromRepo.startsWith('dotnet')) { + changelogFile = optionalOutputName || 'dotnet.md'; + repository = 'botbuilder-dotnet'; +} else if (gitLogFromRepo.startsWith('js')) { + changelogFile = optionalOutputName || 'js.md'; + repository = 'botbuilder-js'; +} else if (gitLogFromRepo.startsWith('python')) { + changelogFile = optionalOutputName || 'python.md'; + repository = 'botbuilder-python'; +} else if (gitLogFromRepo.startsWith('java')) { + changelogFile = optionalOutputName || 'java.md'; + repository = 'botbuilder-java'; +} else if (gitLogFromRepo.startsWith('bf-cli')) { + changelogFile = optionalOutputName || 'bf-cli.md'; + repository = 'botframework-cli'; +} + +// git log --show-pulls --pretty=tformat:"%s" --since=2020-08-13 > dotnet.txt +// git log --show-pulls --pretty=tformat:"%s" --since=2020-08-07 > js.txt +// git log --show-pulls --pretty=tformat:"%s" --since=2020-08-10 > python.txt +// git log --show-pulls --pretty=tformat:"%s" --since=2020-08-17 > java.txt +// git log --show-pulls --pretty=tformat:"%s" --since=2020-08-10 > bf-cli.txt + +const preparedStream = createWriteStream(changelogFile); +(async function processLineByLine() { + try { + const rl = createInterface({ + input: createReadStream(gitLogFromRepo), + crlfDelay: Infinity + }); + + rl.on('line', (line) => { + // Check for squash merges first. This generates a bulletpoint that + // by default uses the title of the PR and appends the PR number to + // the end of the commit message. + // E.g. "Fix fetch in token server used in E2E Streaming Test (#2944)" + const matches = /(?.*)\s\(#(?\d*)\)$/gim.exec(line); + if (matches) { + const { message, num } = matches.groups; + preparedStream.write(`- ${message} [[PR ${num}]](https://github.com/microsoft/${repository}/pull/${num})\n`); + } else { + // This second check is for PRs that were not squashed and merged. + // E.g. "Merge pull request #1411 from " + const otherFormatMatches = /^(?Merge pull request #(?\d*) from.*)/gim.exec(line); + if (otherFormatMatches) { + const { message, num } = otherFormatMatches.groups; + preparedStream.write(`- ${message} [[PR ${num}]](https://github.com/microsoft/${repository}/pull/${num})\n`) + } + } + }); + + await once(rl, 'close'); + console.log(`Changelog "${changelogFile}" created.`); + } catch (err) { + const errMsgPrefix = `An error occurred during the creation of the changelog. +Please file an issue in https://github.com/microsoft/botframework-sdk and provide the necessary reproduction steps.\n` + console.error(errMsgPrefix); + console.error(err); + exit(1); + } +})();