From 5c448884e16e8bebbf8aa1fd76327dc125cb2357 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Wed, 2 Feb 2022 16:25:18 +0100 Subject: [PATCH 01/42] wip --- doc/changelogs/java.md | 0 doc/changelogs/js.md | 0 doc/changelogs/php.md | 0 package.json | 4 + .../release/prepare-release-pull-requests.js | 221 ++++++++++++++++++ scripts/release/process-release-commit.js | 120 ++++++++++ yarn.lock | 190 ++++++++++++++- 7 files changed, 532 insertions(+), 3 deletions(-) create mode 100644 doc/changelogs/java.md create mode 100644 doc/changelogs/js.md create mode 100644 doc/changelogs/php.md create mode 100755 scripts/release/prepare-release-pull-requests.js create mode 100755 scripts/release/process-release-commit.js diff --git a/doc/changelogs/java.md b/doc/changelogs/java.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/doc/changelogs/js.md b/doc/changelogs/js.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/doc/changelogs/php.md b/doc/changelogs/php.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/package.json b/package.json index 392c9e7c4ab..d9a5792c056 100644 --- a/package.json +++ b/package.json @@ -29,11 +29,13 @@ "github-actions:lint": "eslint --ext=yml .github/" }, "devDependencies": { + "@octokit/rest": "18.12.0", "@openapitools/openapi-generator-cli": "2.4.18", "@redocly/openapi-cli": "1.0.0-beta.79", "@typescript-eslint/eslint-plugin": "5.5.0", "@typescript-eslint/parser": "5.5.0", "babel-eslint": "10.1.0", + "dotenv": "14.3.2", "eslint": "8.6.0", "eslint-config-algolia": "20.0.0", "eslint-config-prettier": "8.3.0", @@ -44,10 +46,12 @@ "eslint-plugin-prettier": "4.0.0", "eslint-plugin-unused-imports": "2.0.0", "eslint-plugin-yml": "0.12.0", + "execa": "5.1.1", "json": "11.0.0", "mustache": "4.2.0", "prettier": "2.5.1", "prettier-plugin-java": "1.6.0", + "semver": "7.3.5", "typescript": "4.5.4" }, "engines": { diff --git a/scripts/release/prepare-release-pull-requests.js b/scripts/release/prepare-release-pull-requests.js new file mode 100755 index 00000000000..d72a0344f41 --- /dev/null +++ b/scripts/release/prepare-release-pull-requests.js @@ -0,0 +1,221 @@ +#!/usr/bin/env node +/* eslint-disable no-console */ +/* eslint-disable import/no-commonjs */ +/* eslint-disable @typescript-eslint/no-var-requires */ +const fs = require('fs'); + +const { Octokit } = require('@octokit/rest'); +const execa = require('execa'); // https://github.com/sindresorhus/execa/tree/v5.1.1 +const semver = require('semver'); + +const RELEASE_BRANCH = 'release'; +const MAIN_BRANCH = 'main'; + +const OWNER = 'algolia'; +const REPO = 'api-clients-automation'; + +const LANG_NAME_ALIAS = { + js: 'javascript', +}; + +function run(command) { + const result = execa.commandSync(command); + if (result.exitCode !== 0) { + throw new Error(result.stderr); + } + return result.stdout; +} + +function readVersions() { + const versions = {}; + + const generators = JSON.parse( + fs.readFileSync('openapitools.json').toString() + )['generator-cli'].generators; + + Object.keys(generators).forEach((generator) => { + const lang = generator.split('-')[0]; + if (!versions[lang]) { + versions[lang] = { + current: generators[generator].additionalProperties.packageVersion, + langName: lang, + next: undefined, + }; + } + }); + return versions; +} + +if (run('git rev-parse --abbrev-ref HEAD') !== MAIN_BRANCH) { + throw new Error( + `You can run this script only from \`${MAIN_BRANCH}\` branch.` + ); +} + +if (!run('git status --porcelain')) { + throw new Error( + 'Working directory is not clean. Commit all the changes first.' + ); +} + +// Reading versions from `openapitools.json` +const versions = readVersions(); +const langs = Object.keys(versions); // ["javascript", "php", "java", ...] + +// Reading commits since last release +console.log('Pulling from origin...'); +run(`git pull origin ${MAIN_BRANCH}`); + +const header = [ + `## Summary`, + `Once ready, squash and merge this PR to trigger a release.`, +].join('\n'); + +const skippedCommits = []; +const latestCommits = run(`git log --oneline ${RELEASE_BRANCH}..${MAIN_BRANCH}`) + .split('\n') + .filter(Boolean) + .map((commit) => { + const hash = commit.slice(0, 7); + let message = commit.slice(8); + let type = message.slice(0, message.indexOf(':')); + const matchResult = type.match(/(.+)\((.+)\)/); + if (!matchResult) { + skippedCommits.push(commit); + // console.warn(`Skipping commit ${hash} due to lack of language scope:`); + // console.warn(` > ${message}`); + return undefined; + } + message = message.slice(message.indexOf(':') + 2); + type = matchResult[1]; + let lang = matchResult[2]; + lang = LANG_NAME_ALIAS[lang] || lang; + + return { + hash, + type, // e.g. `fix` + lang, // e.g. `javascript` + message, + raw: commit, + }; + }) + .filter(Boolean); + +console.warn('Skipping these commits due to lack of language scope:'); +console.log(skippedCommits.map((commit) => ` ${commit}`).join('\n')); + +langs.forEach((lang) => { + const commits = latestCommits.filter( + (lastestCommit) => lastestCommit.lang === lang + ); + const currentVersion = versions[lang].current; + + if (commits.length === 0) { + versions[lang].next = currentVersion; + versions[lang].noCommit = true; + return; + } + + if (semver.prerelease(currentVersion)) { + // if version is like 0.1.2-beta.1, it increases to 0.1.2-beta.2, even if there's a breaking change. + versions[lang].next = semver.inc(currentVersion, 'prerelease'); + return; + } + + if (commits.some((commit) => commit.message.includes('BREAKING CHANGE'))) { + versions[lang].next = semver.inc(currentVersion, 'major'); + return; + } + + const commitTypes = new Set(commits.map(({ type }) => type)); + if (commitTypes.has('feat')) { + versions[lang].next = semver.inc(currentVersion, 'minor'); + return; + } + + versions[lang].next = semver.inc(currentVersion, 'patch'); + if (!commitTypes.has('fix')) { + versions[lang].skipRelease = true; + } +}); + +const versionChangeHeader = [`## Version Changes`].join('\n'); + +const versionChanges = langs + .map((lang) => { + const { current, next, noCommit, skipRelease, langName } = versions[lang]; + + if (!current) { + return `- [ ] ~${langName}: (current version not found)~`; + } + + if (noCommit) { + return `- ~${langName}: v${current} (no commit)~`; + } + + if (skipRelease) { + return [ + `- [ ] ${langName}: v${current} -> v${next}`, + ` * No \`feat\` or \`fix\` commit, thus unchecked by default.`, + ` * If you check it, ${lang} repo will be updated, and the library will be released with the new version.`, + ` * If you leave it unchecked, ${lang} repo will still be updated (no version update).`, + ` * If you don't want to update ${lang} repo at all, edit this pull request to remove the line above.`, + ].join('\n'); + } + + return [ + `- [x] ${langName}: v${current} -> v${next}`, + ` * Uncheck if you want to skip it.`, + ].join('\n'); + }) + .join('\n'); + +const changelogHeader = [ + `## CHANGELOG`, + `Update the following lines. Once merged, it will be reflected to \`docs/changelogs/*.\``, +].join('\n'); + +const changelogs = langs + .flatMap((lang) => { + if (versions[lang].noCommit) { + return []; + } + + return [ + `### ${versions[lang].langName}`, + ...latestCommits + .filter((commit) => commit.lang === lang) + .map((commit) => `- ${commit.raw}`), + ]; + }) + .join('\n'); + +const body = [ + header, + versionChangeHeader, + versionChanges, + changelogHeader, + changelogs, +].join('\n\n'); + +const octokit = new Octokit({ + auth: `token ${process.env.GITHUB_TOKEN}`, +}); + +octokit.rest.pulls + .create({ + owner: OWNER, + repo: REPO, + head: MAIN_BRANCH, + base: RELEASE_BRANCH, + title: `chore: release ${new Date().toISOString().split('T')[0]}`, + body, + }) + .then((result) => { + const { + data: { number, html_url: url }, + } = result; + + console.log(`Pull Request #${number} is ready for review.`); + console.log(` > ${url}`); + }); diff --git a/scripts/release/process-release-commit.js b/scripts/release/process-release-commit.js new file mode 100755 index 00000000000..dccd1e8167c --- /dev/null +++ b/scripts/release/process-release-commit.js @@ -0,0 +1,120 @@ +#!/usr/bin/env node +/* eslint-disable no-console */ +/* eslint-disable no-process-exit */ +/* eslint-disable import/no-commonjs */ +/* eslint-disable @typescript-eslint/no-var-requires */ +const fs = require('fs'); + +// eslint-disable-next-line import/order +const dotenv = require('dotenv'); + +dotenv.config(); + +const execa = require('execa'); + +const RELEASE_BRANCH = 'release'; + +function run(command) { + const result = execa.commandSync(command); + if (result.exitCode !== 0) { + throw new Error(result.stderr); + } + return result.stdout; +} + +function getMarkdownSection(markdown, title) { + const levelIndicator = title.split(' ')[0]; // e.g. `##` + const lines = markdown.slice(markdown.indexOf(title)).split('\n'); + let endIndex = lines.length; + for (let i = 1; i < lines.length; i++) { + if (lines[i].startsWith(`${levelIndicator} `)) { + endIndex = i; + break; + } + } + return lines.slice(0, endIndex).join('\n'); +} + +if (run('git rev-parse --abbrev-ref HEAD') !== RELEASE_BRANCH) { + throw new Error( + `You can run this script only from \`${RELEASE_BRANCH}\` branch.` + ); +} + +const lastCommit = run('git log --oneline -n 1').trim(); +if (!lastCommit.slice(8).startsWith('chore: release')) { + console.log("Quitting because the latest commit isn't a release commit."); + process.exit(0); +} + +const [, prNumber] = lastCommit.match(/\(#(\d+)\)$/); + +const pullRequestBody = JSON.parse( + execa.sync('curl', [ + '-H', + `Authorization: token ${process.env.GITHUB_TOKEN}`, + `https://api.github.com/repos/algolia/api-clients-automation/pulls/${prNumber}`, + ]).stdout +).body; + +// const pullRequestBody = `## Summary +// Once ready, squash and merge this PR to trigger a release. + +// ## Version Changes + +// - [x] javascript: v5.0.0 -> v5.0.1 +// * Uncheck if you want to skip it. +// - [ ] ~java: v4.0.0 (no commit)~ + +// ## CHANGELOG +// Update the following lines. Once merged, it will be reflected to \`docs/changelogs/*.\` + +// ### javascript +// - 70369f5 fix(js): add version to user agent (#105)`; + +const versionsToRelease = {}; +getMarkdownSection(pullRequestBody, '## Version Changes') + .split('\n') + .forEach((line) => { + const result = line.match(/- \[x\] (.+): v(.+) -> v(.+)/); + if (!result) { + return; + } + const [, lang, currentVersion, nextVersion] = result; + versionsToRelease[lang] = { + currentVersion, + nextVersion, + }; + }); + +const langsToUpdateRepo = getMarkdownSection( + pullRequestBody, + '## Version Changes' +) + .split('\n') + .map((line) => { + const result = line.match(/- \[ \] (.+): v(.+) -> v(.+)/); + return result?.[1]; + }) + .filter(Boolean); + +const json = JSON.parse(fs.readFileSync('openapitools.json').toString()); +Object.keys(json['generator-cli'].generators).forEach((client) => { + const lang = client.split('-')[0]; + if (versionsToRelease[lang]) { + json['generator-cli'].generators[ + client + ].additionalProperties.packageVersion = versionsToRelease[lang].nextVersion; + } +}); +fs.writeFileSync('openapitools.json', JSON.stringify(json, null, 2)); + +Object.keys(versionsToRelease).forEach((lang) => { + console.log(`Generating ${lang} client(s)...`); + run(`yarn generate ${lang}`).pipe(process.stdout); +}); + +langsToUpdateRepo.forEach((lang) => { + console.log(`Generating ${lang} client(s)...`); + run(`yarn generate ${lang}`).pipe(process.stdout); +}); diff --git a/yarn.lock b/yarn.lock index dacd71a1468..11d79d050bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9,11 +9,13 @@ __metadata: version: 0.0.0-use.local resolution: "@algolia/api-client-automation@workspace:." dependencies: + "@octokit/rest": 18.12.0 "@openapitools/openapi-generator-cli": 2.4.18 "@redocly/openapi-cli": 1.0.0-beta.79 "@typescript-eslint/eslint-plugin": 5.5.0 "@typescript-eslint/parser": 5.5.0 babel-eslint: 10.1.0 + dotenv: 14.3.2 eslint: 8.6.0 eslint-config-algolia: 20.0.0 eslint-config-prettier: 8.3.0 @@ -24,10 +26,12 @@ __metadata: eslint-plugin-prettier: 4.0.0 eslint-plugin-unused-imports: 2.0.0 eslint-plugin-yml: 0.12.0 + execa: 5.1.1 json: 11.0.0 mustache: 4.2.0 prettier: 2.5.1 prettier-plugin-java: 1.6.0 + semver: 7.3.5 typescript: 4.5.4 languageName: unknown linkType: soft @@ -944,6 +948,137 @@ __metadata: languageName: node linkType: hard +"@octokit/auth-token@npm:^2.4.4": + version: 2.5.0 + resolution: "@octokit/auth-token@npm:2.5.0" + dependencies: + "@octokit/types": ^6.0.3 + checksum: 45949296c09abcd6beb4c3f69d45b0c1f265f9581d2a9683cf4d1800c4cf8259c2f58d58e44c16c20bffb85a0282a176c0d51f4af300e428b863f27b910e6297 + languageName: node + linkType: hard + +"@octokit/core@npm:^3.5.1": + version: 3.5.1 + resolution: "@octokit/core@npm:3.5.1" + dependencies: + "@octokit/auth-token": ^2.4.4 + "@octokit/graphql": ^4.5.8 + "@octokit/request": ^5.6.0 + "@octokit/request-error": ^2.0.5 + "@octokit/types": ^6.0.3 + before-after-hook: ^2.2.0 + universal-user-agent: ^6.0.0 + checksum: 67179739fc9712b201f2400f132287a2c56a18506e00900bc9d2a3f742b74f1ba69ad998e42f28f3964c0bd1d5478232c1ec7b485c97702b821fbe22b76afa90 + languageName: node + linkType: hard + +"@octokit/endpoint@npm:^6.0.1": + version: 6.0.12 + resolution: "@octokit/endpoint@npm:6.0.12" + dependencies: + "@octokit/types": ^6.0.3 + is-plain-object: ^5.0.0 + universal-user-agent: ^6.0.0 + checksum: b48b29940af11c4b9bca41cf56809754bb8385d4e3a6122671799d27f0238ba575b3fde86d2d30a84f4dbbc14430940de821e56ecc6a9a92d47fc2b29a31479d + languageName: node + linkType: hard + +"@octokit/graphql@npm:^4.5.8": + version: 4.8.0 + resolution: "@octokit/graphql@npm:4.8.0" + dependencies: + "@octokit/request": ^5.6.0 + "@octokit/types": ^6.0.3 + universal-user-agent: ^6.0.0 + checksum: f68afe53f63900d4a16a0a733f2f500df2695b731f8ed32edb728d50edead7f5011437f71d069c2d2f6d656227703d0c832a3c8af58ecf82bd5dcc051f2d2d74 + languageName: node + linkType: hard + +"@octokit/openapi-types@npm:^11.2.0": + version: 11.2.0 + resolution: "@octokit/openapi-types@npm:11.2.0" + checksum: eb373ea496bc96bf0233505a0916eb38cb193d1829cab935e1cf1fd21839c402a1d835d3c0326290c756c0ed980a64d0ae73ad3c5d5decde9000f0828aa7ff52 + languageName: node + linkType: hard + +"@octokit/plugin-paginate-rest@npm:^2.16.8": + version: 2.17.0 + resolution: "@octokit/plugin-paginate-rest@npm:2.17.0" + dependencies: + "@octokit/types": ^6.34.0 + peerDependencies: + "@octokit/core": ">=2" + checksum: c8753cda6f7ede79d0e9df43a54e56020aa1c9c6887684e0e0d45cb6ee0dcabf460c3e4b8a18edabef711bb269fd826616e99e78dc29fb30d47c210c562603a0 + languageName: node + linkType: hard + +"@octokit/plugin-request-log@npm:^1.0.4": + version: 1.0.4 + resolution: "@octokit/plugin-request-log@npm:1.0.4" + peerDependencies: + "@octokit/core": ">=3" + checksum: 2086db00056aee0f8ebd79797b5b57149ae1014e757ea08985b71eec8c3d85dbb54533f4fd34b6b9ecaa760904ae6a7536be27d71e50a3782ab47809094bfc0c + languageName: node + linkType: hard + +"@octokit/plugin-rest-endpoint-methods@npm:^5.12.0": + version: 5.13.0 + resolution: "@octokit/plugin-rest-endpoint-methods@npm:5.13.0" + dependencies: + "@octokit/types": ^6.34.0 + deprecation: ^2.3.1 + peerDependencies: + "@octokit/core": ">=3" + checksum: f331457e4317130adb456b27df2a99609fb54a4dc2da6f87009e567c7325680c901abf18ad08483535bab4ec1c892e4236f4135a2804603aebb12c0698c678c8 + languageName: node + linkType: hard + +"@octokit/request-error@npm:^2.0.5, @octokit/request-error@npm:^2.1.0": + version: 2.1.0 + resolution: "@octokit/request-error@npm:2.1.0" + dependencies: + "@octokit/types": ^6.0.3 + deprecation: ^2.0.0 + once: ^1.4.0 + checksum: baec2b5700498be01b4d958f9472cb776b3f3b0ea52924323a07e7a88572e24cac2cdf7eb04a0614031ba346043558b47bea2d346e98f0e8385b4261f138ef18 + languageName: node + linkType: hard + +"@octokit/request@npm:^5.6.0": + version: 5.6.3 + resolution: "@octokit/request@npm:5.6.3" + dependencies: + "@octokit/endpoint": ^6.0.1 + "@octokit/request-error": ^2.1.0 + "@octokit/types": ^6.16.1 + is-plain-object: ^5.0.0 + node-fetch: ^2.6.7 + universal-user-agent: ^6.0.0 + checksum: c0b4542eb4baaf880d673c758d3e0b5c4a625a4ae30abf40df5548b35f1ff540edaac74625192b1aff42a79ac661e774da4ab7d5505f1cb4ef81239b1e8510c5 + languageName: node + linkType: hard + +"@octokit/rest@npm:18.12.0": + version: 18.12.0 + resolution: "@octokit/rest@npm:18.12.0" + dependencies: + "@octokit/core": ^3.5.1 + "@octokit/plugin-paginate-rest": ^2.16.8 + "@octokit/plugin-request-log": ^1.0.4 + "@octokit/plugin-rest-endpoint-methods": ^5.12.0 + checksum: c18bd6676a60b66819b016b0f969fcd04d8dfa04d01b7af9af9a7410ff028c621c995185e29454c23c47906da506c1e01620711259989a964ebbfd9106f5b715 + languageName: node + linkType: hard + +"@octokit/types@npm:^6.0.3, @octokit/types@npm:^6.16.1, @octokit/types@npm:^6.34.0": + version: 6.34.0 + resolution: "@octokit/types@npm:6.34.0" + dependencies: + "@octokit/openapi-types": ^11.2.0 + checksum: f122b9aee8f6baddd515e34a0913e73b21d4bc82d6ee59d77a8aaf01b4a02c10867dd013003d087a83dc96db23511893669015af6d30c27cece185e21cf1df89 + languageName: node + linkType: hard + "@openapitools/openapi-generator-cli@npm:2.4.18": version: 2.4.18 resolution: "@openapitools/openapi-generator-cli@npm:2.4.18" @@ -1693,6 +1828,13 @@ __metadata: languageName: node linkType: hard +"before-after-hook@npm:^2.2.0": + version: 2.2.2 + resolution: "before-after-hook@npm:2.2.2" + checksum: dc2e1ffe389e5afbef2a46790b1b5a50247ed57aba67649cfa9ec2552d248cc9278f222e72fb5a8ff59bbb39d78fbaa97e7234ead0c6b5e8418b67a8644ce207 + languageName: node + linkType: hard + "binary-extensions@npm:^2.0.0": version: 2.2.0 resolution: "binary-extensions@npm:2.2.0" @@ -2295,6 +2437,13 @@ __metadata: languageName: node linkType: hard +"deprecation@npm:^2.0.0, deprecation@npm:^2.3.1": + version: 2.3.1 + resolution: "deprecation@npm:2.3.1" + checksum: f56a05e182c2c195071385455956b0c4106fe14e36245b00c689ceef8e8ab639235176a96977ba7c74afb173317fac2e0ec6ec7a1c6d1e6eaa401c586c714132 + languageName: node + linkType: hard + "detect-newline@npm:^3.0.0": version: 3.1.0 resolution: "detect-newline@npm:3.1.0" @@ -2359,6 +2508,13 @@ __metadata: languageName: node linkType: hard +"dotenv@npm:14.3.2": + version: 14.3.2 + resolution: "dotenv@npm:14.3.2" + checksum: 86c06758915d6facc35275f4a7fafc16705b6f3b44befaa8abca91367991efc8ff8db5437d3cc14778231d19fb97610fe82d60f8a53ba723cdb69fe4171439aa + languageName: node + linkType: hard + "easy-table@npm:1.1.0": version: 1.1.0 resolution: "easy-table@npm:1.1.0" @@ -2823,7 +2979,7 @@ __metadata: languageName: node linkType: hard -"execa@npm:^5.0.0": +"execa@npm:5.1.1, execa@npm:^5.0.0": version: 5.1.1 resolution: "execa@npm:5.1.1" dependencies: @@ -3637,6 +3793,13 @@ __metadata: languageName: node linkType: hard +"is-plain-object@npm:^5.0.0": + version: 5.0.0 + resolution: "is-plain-object@npm:5.0.0" + checksum: e32d27061eef62c0847d303125440a38660517e586f2f3db7c9d179ae5b6674ab0f469d519b2e25c147a1a3bc87156d0d5f4d8821e0ce4a9ee7fe1fcf11ce45c + languageName: node + linkType: hard + "is-potential-custom-element-name@npm:^1.0.1": version: 1.0.1 resolution: "is-potential-custom-element-name@npm:1.0.1" @@ -4857,6 +5020,20 @@ __metadata: languageName: node linkType: hard +"node-fetch@npm:^2.6.7": + version: 2.6.7 + resolution: "node-fetch@npm:2.6.7" + dependencies: + whatwg-url: ^5.0.0 + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + checksum: 8d816ffd1ee22cab8301c7756ef04f3437f18dace86a1dae22cf81db8ef29c0bf6655f3215cb0cdb22b420b6fe141e64b26905e7f33f9377a7fa59135ea3e10b + languageName: node + linkType: hard + "node-gyp@npm:latest": version: 8.4.1 resolution: "node-gyp@npm:8.4.1" @@ -4981,7 +5158,7 @@ __metadata: languageName: node linkType: hard -"once@npm:^1.3.0": +"once@npm:^1.3.0, once@npm:^1.4.0": version: 1.4.0 resolution: "once@npm:1.4.0" dependencies: @@ -5590,7 +5767,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:7.x, semver@npm:^7.2.1, semver@npm:^7.3.2, semver@npm:^7.3.5": +"semver@npm:7.3.5, semver@npm:7.x, semver@npm:^7.2.1, semver@npm:^7.3.2, semver@npm:^7.3.5": version: 7.3.5 resolution: "semver@npm:7.3.5" dependencies: @@ -6307,6 +6484,13 @@ __metadata: languageName: node linkType: hard +"universal-user-agent@npm:^6.0.0": + version: 6.0.0 + resolution: "universal-user-agent@npm:6.0.0" + checksum: 5092bbc80dd0d583cef0b62c17df0043193b74f425112ea6c1f69bc5eda21eeec7a08d8c4f793a277eb2202ffe9b44bec852fa3faff971234cd209874d1b79ef + languageName: node + linkType: hard + "universalify@npm:^0.1.2": version: 0.1.2 resolution: "universalify@npm:0.1.2" From 1675bf8e5e45650424ecab2fe96adacb8f8ea494 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Wed, 2 Feb 2022 16:34:25 +0100 Subject: [PATCH 02/42] use dotenv --- scripts/release/prepare-release-pull-requests.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/release/prepare-release-pull-requests.js b/scripts/release/prepare-release-pull-requests.js index d72a0344f41..c19f3506ba2 100755 --- a/scripts/release/prepare-release-pull-requests.js +++ b/scripts/release/prepare-release-pull-requests.js @@ -5,6 +5,7 @@ const fs = require('fs'); const { Octokit } = require('@octokit/rest'); +const dotenv = require('dotenv'); const execa = require('execa'); // https://github.com/sindresorhus/execa/tree/v5.1.1 const semver = require('semver'); @@ -14,6 +15,8 @@ const MAIN_BRANCH = 'main'; const OWNER = 'algolia'; const REPO = 'api-clients-automation'; +dotenv.config(); + const LANG_NAME_ALIAS = { js: 'javascript', }; From af8170e0535822a92db31ec5e1181db163bd4e98 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Wed, 2 Feb 2022 16:35:01 +0100 Subject: [PATCH 03/42] push after pull --- scripts/release/prepare-release-pull-requests.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/release/prepare-release-pull-requests.js b/scripts/release/prepare-release-pull-requests.js index c19f3506ba2..87c46cdd694 100755 --- a/scripts/release/prepare-release-pull-requests.js +++ b/scripts/release/prepare-release-pull-requests.js @@ -69,6 +69,9 @@ const langs = Object.keys(versions); // ["javascript", "php", "java", ...] console.log('Pulling from origin...'); run(`git pull origin ${MAIN_BRANCH}`); +console.log('Pushing to origin...'); +run(`git push origin ${MAIN_BRANCH}`); + const header = [ `## Summary`, `Once ready, squash and merge this PR to trigger a release.`, From e263c9187199af987cdcde856c2802c48af89a17 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Wed, 2 Feb 2022 16:35:45 +0100 Subject: [PATCH 04/42] checking working directory --- scripts/release/prepare-release-pull-requests.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release/prepare-release-pull-requests.js b/scripts/release/prepare-release-pull-requests.js index 87c46cdd694..d8f06cb19c2 100755 --- a/scripts/release/prepare-release-pull-requests.js +++ b/scripts/release/prepare-release-pull-requests.js @@ -55,7 +55,7 @@ if (run('git rev-parse --abbrev-ref HEAD') !== MAIN_BRANCH) { ); } -if (!run('git status --porcelain')) { +if (run('git status --porcelain')) { throw new Error( 'Working directory is not clean. Commit all the changes first.' ); From 59065d1b607239eea14f1b59b70863bc300a3d17 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Wed, 2 Feb 2022 16:42:01 +0100 Subject: [PATCH 05/42] fix github info --- scripts/release/prepare-release-pull-requests.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release/prepare-release-pull-requests.js b/scripts/release/prepare-release-pull-requests.js index d8f06cb19c2..9db128cac55 100755 --- a/scripts/release/prepare-release-pull-requests.js +++ b/scripts/release/prepare-release-pull-requests.js @@ -12,7 +12,7 @@ const semver = require('semver'); const RELEASE_BRANCH = 'release'; const MAIN_BRANCH = 'main'; -const OWNER = 'algolia'; +const OWNER = 'eunjae-lee'; // TODO: change this later const REPO = 'api-clients-automation'; dotenv.config(); From afe00ca816caaf56a95472e404469003c7fff000 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Wed, 2 Feb 2022 16:51:24 +0100 Subject: [PATCH 06/42] update pr description --- .../release/prepare-release-pull-requests.js | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/scripts/release/prepare-release-pull-requests.js b/scripts/release/prepare-release-pull-requests.js index 9db128cac55..2f403abe371 100755 --- a/scripts/release/prepare-release-pull-requests.js +++ b/scripts/release/prepare-release-pull-requests.js @@ -151,28 +151,25 @@ const versionChanges = langs .map((lang) => { const { current, next, noCommit, skipRelease, langName } = versions[lang]; - if (!current) { - return `- [ ] ~${langName}: (current version not found)~`; - } - if (noCommit) { return `- ~${langName}: v${current} (no commit)~`; } - if (skipRelease) { - return [ - `- [ ] ${langName}: v${current} -> v${next}`, - ` * No \`feat\` or \`fix\` commit, thus unchecked by default.`, - ` * If you check it, ${lang} repo will be updated, and the library will be released with the new version.`, - ` * If you leave it unchecked, ${lang} repo will still be updated (no version update).`, - ` * If you don't want to update ${lang} repo at all, edit this pull request to remove the line above.`, - ].join('\n'); + if (!current) { + return `- ~${langName}: (current version not found)~`; } + const checked = skipRelease ? ' ' : 'x'; return [ - `- [x] ${langName}: v${current} -> v${next}`, - ` * Uncheck if you want to skip it.`, - ].join('\n'); + `- [${checked}] ${langName}: v${current} -> v${next}`, + skipRelease && + ` - No \`feat\` or \`fix\` commit, thus unchecked by default.`, + ` - **Checked** → Update version, update repository, and release the library.`, + ` - **Unchecked** → Update repository.`, + ` - **Line removed** → Do nothing.`, + ] + .filter(Boolean) + .join('\n'); }) .join('\n'); @@ -182,6 +179,7 @@ const changelogHeader = [ ].join('\n'); const changelogs = langs + .filter((lang) => !versions[lang].noCommit && versions[lang].current) .flatMap((lang) => { if (versions[lang].noCommit) { return []; @@ -222,6 +220,7 @@ octokit.rest.pulls data: { number, html_url: url }, } = result; + console.log(''); console.log(`Pull Request #${number} is ready for review.`); console.log(` > ${url}`); }); From a46ddc663e53e7a5bdc914dc6493b0a30134b585 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Wed, 2 Feb 2022 17:19:57 +0100 Subject: [PATCH 07/42] setup github action --- .github/workflows/process-release.yml | 24 +++++++++++++++++++ .../release/prepare-release-pull-requests.js | 4 ++-- 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/process-release.yml diff --git a/.github/workflows/process-release.yml b/.github/workflows/process-release.yml new file mode 100644 index 00000000000..f824025b079 --- /dev/null +++ b/.github/workflows/process-release.yml @@ -0,0 +1,24 @@ +name: Process release +on: + pull_request: + types: + - closed + branches: + - release +jobs: + build: + name: Release + runs-on: ubuntu-20.04 + if: "github.event.pull_request.merged == true && github.head_ref == 'main' && startsWith(github.event.head_commit.message, 'chore: release')" + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Setup + id: setup + uses: ./.github/actions/setup + + - run: ./scripts/release/process-release-commit.js + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/scripts/release/prepare-release-pull-requests.js b/scripts/release/prepare-release-pull-requests.js index 2f403abe371..b9930e365b9 100755 --- a/scripts/release/prepare-release-pull-requests.js +++ b/scripts/release/prepare-release-pull-requests.js @@ -164,8 +164,8 @@ const versionChanges = langs `- [${checked}] ${langName}: v${current} -> v${next}`, skipRelease && ` - No \`feat\` or \`fix\` commit, thus unchecked by default.`, - ` - **Checked** → Update version, update repository, and release the library.`, - ` - **Unchecked** → Update repository.`, + ` - **Checked** → Update version, update ${langName} repository, and release the library.`, + ` - **Unchecked** → Update ${langName} repository.`, ` - **Line removed** → Do nothing.`, ] .filter(Boolean) From a6033014ab4f210d2d4191a13d80da9052ba3f52 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Wed, 2 Feb 2022 17:20:48 +0100 Subject: [PATCH 08/42] update script in package.json --- package.json | 3 ++- ...elease-pull-requests.js => prepare-release-pull-request.js} | 0 2 files changed, 2 insertions(+), 1 deletion(-) rename scripts/release/{prepare-release-pull-requests.js => prepare-release-pull-request.js} (100%) diff --git a/package.json b/package.json index d9a5792c056..2146ffb65a0 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ "playground": "./scripts/multiplexer.sh ${2:-nonverbose} ./scripts/playground.sh ${0:-javascript} ${1:-search}", "specs:fix": "eslint --ext=yml specs/ --fix", "specs:lint": "eslint --ext=yml specs/$0", - "github-actions:lint": "eslint --ext=yml .github/" + "github-actions:lint": "eslint --ext=yml .github/", + "release": "./scripts/release/prepare-release-pull-request.js" }, "devDependencies": { "@octokit/rest": "18.12.0", diff --git a/scripts/release/prepare-release-pull-requests.js b/scripts/release/prepare-release-pull-request.js similarity index 100% rename from scripts/release/prepare-release-pull-requests.js rename to scripts/release/prepare-release-pull-request.js From fc0f1860d06caeefe64d98131a30e17e8a095ad7 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Wed, 2 Feb 2022 17:38:09 +0100 Subject: [PATCH 09/42] change pr desc --- .github/workflows/process-release.yml | 2 +- scripts/release/prepare-release-pull-request.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/process-release.yml b/.github/workflows/process-release.yml index f824025b079..6caceb5994c 100644 --- a/.github/workflows/process-release.yml +++ b/.github/workflows/process-release.yml @@ -9,7 +9,7 @@ jobs: build: name: Release runs-on: ubuntu-20.04 - if: "github.event.pull_request.merged == true && github.head_ref == 'main' && startsWith(github.event.head_commit.message, 'chore: release')" + if: github.event.pull_request.merged == true && github.head_ref == 'main' steps: - uses: actions/checkout@v2 with: diff --git a/scripts/release/prepare-release-pull-request.js b/scripts/release/prepare-release-pull-request.js index b9930e365b9..dfa15facb1f 100755 --- a/scripts/release/prepare-release-pull-request.js +++ b/scripts/release/prepare-release-pull-request.js @@ -74,7 +74,7 @@ run(`git push origin ${MAIN_BRANCH}`); const header = [ `## Summary`, - `Once ready, squash and merge this PR to trigger a release.`, + `To trigger a release, merge this PR by "Create a merge commit".`, ].join('\n'); const skippedCommits = []; From eea302e4a7e01136c4d5adb6a5b9a0de5be01314 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Wed, 2 Feb 2022 17:44:09 +0100 Subject: [PATCH 10/42] get pull-request number from action --- .github/workflows/process-release.yml | 1 + scripts/release/process-release-commit.js | 11 +---------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/.github/workflows/process-release.yml b/.github/workflows/process-release.yml index 6caceb5994c..a595a2e4eb7 100644 --- a/.github/workflows/process-release.yml +++ b/.github/workflows/process-release.yml @@ -21,4 +21,5 @@ jobs: - run: ./scripts/release/process-release-commit.js env: + PR_NUMBER: $${{ github.event.number }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/scripts/release/process-release-commit.js b/scripts/release/process-release-commit.js index dccd1e8167c..4e6c92ca2be 100755 --- a/scripts/release/process-release-commit.js +++ b/scripts/release/process-release-commit.js @@ -1,6 +1,5 @@ #!/usr/bin/env node /* eslint-disable no-console */ -/* eslint-disable no-process-exit */ /* eslint-disable import/no-commonjs */ /* eslint-disable @typescript-eslint/no-var-requires */ const fs = require('fs'); @@ -41,19 +40,11 @@ if (run('git rev-parse --abbrev-ref HEAD') !== RELEASE_BRANCH) { ); } -const lastCommit = run('git log --oneline -n 1').trim(); -if (!lastCommit.slice(8).startsWith('chore: release')) { - console.log("Quitting because the latest commit isn't a release commit."); - process.exit(0); -} - -const [, prNumber] = lastCommit.match(/\(#(\d+)\)$/); - const pullRequestBody = JSON.parse( execa.sync('curl', [ '-H', `Authorization: token ${process.env.GITHUB_TOKEN}`, - `https://api.github.com/repos/algolia/api-clients-automation/pulls/${prNumber}`, + `https://api.github.com/repos/algolia/api-clients-automation/pulls/${process.env.PR_NUMBER}`, ]).stdout ).body; From 8dbb6d4489713325c3c1e6682c921a42c7442ad8 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Thu, 3 Feb 2022 10:59:00 +0100 Subject: [PATCH 11/42] use issue instead of pr --- .github/workflows/process-release.yml | 6 ++-- package.json | 2 +- ...ull-request.js => create-release-issue.js} | 24 +++++++++------- scripts/release/process-release-commit.js | 28 +++++++++++++------ 4 files changed, 36 insertions(+), 24 deletions(-) rename scripts/release/{prepare-release-pull-request.js => create-release-issue.js} (92%) diff --git a/.github/workflows/process-release.yml b/.github/workflows/process-release.yml index a595a2e4eb7..bcb17f81ab3 100644 --- a/.github/workflows/process-release.yml +++ b/.github/workflows/process-release.yml @@ -1,10 +1,8 @@ name: Process release on: - pull_request: + issues: types: - closed - branches: - - release jobs: build: name: Release @@ -21,5 +19,5 @@ jobs: - run: ./scripts/release/process-release-commit.js env: - PR_NUMBER: $${{ github.event.number }} + EVENT_NUMBER: $${{ github.event.number }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/package.json b/package.json index 2146ffb65a0..ce01c32a73a 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "specs:fix": "eslint --ext=yml specs/ --fix", "specs:lint": "eslint --ext=yml specs/$0", "github-actions:lint": "eslint --ext=yml .github/", - "release": "./scripts/release/prepare-release-pull-request.js" + "release": "./scripts/release/create-release-issue.js" }, "devDependencies": { "@octokit/rest": "18.12.0", diff --git a/scripts/release/prepare-release-pull-request.js b/scripts/release/create-release-issue.js similarity index 92% rename from scripts/release/prepare-release-pull-request.js rename to scripts/release/create-release-issue.js index dfa15facb1f..7051c8bd45a 100755 --- a/scripts/release/prepare-release-pull-request.js +++ b/scripts/release/create-release-issue.js @@ -9,7 +9,8 @@ const dotenv = require('dotenv'); const execa = require('execa'); // https://github.com/sindresorhus/execa/tree/v5.1.1 const semver = require('semver'); -const RELEASE_BRANCH = 'release'; +const RELEASED_TAG = 'released'; + const MAIN_BRANCH = 'main'; const OWNER = 'eunjae-lee'; // TODO: change this later @@ -72,13 +73,10 @@ run(`git pull origin ${MAIN_BRANCH}`); console.log('Pushing to origin...'); run(`git push origin ${MAIN_BRANCH}`); -const header = [ - `## Summary`, - `To trigger a release, merge this PR by "Create a merge commit".`, -].join('\n'); +const header = [`## Summary`].join('\n'); const skippedCommits = []; -const latestCommits = run(`git log --oneline ${RELEASE_BRANCH}..${MAIN_BRANCH}`) +const latestCommits = run(`git log --oneline ${RELEASED_TAG}..${MAIN_BRANCH}`) .split('\n') .filter(Boolean) .map((commit) => { @@ -194,24 +192,30 @@ const changelogs = langs }) .join('\n'); +const approval = [ + `## Confirmation`, + `To proceed this release, check the box below and close the issue.`, + `To skip this release, just close the issue.`, + `- [ ] Approved`, +].join('\n'); + const body = [ header, versionChangeHeader, versionChanges, changelogHeader, changelogs, + approval, ].join('\n\n'); const octokit = new Octokit({ auth: `token ${process.env.GITHUB_TOKEN}`, }); -octokit.rest.pulls +octokit.rest.issues .create({ owner: OWNER, repo: REPO, - head: MAIN_BRANCH, - base: RELEASE_BRANCH, title: `chore: release ${new Date().toISOString().split('T')[0]}`, body, }) @@ -221,6 +225,6 @@ octokit.rest.pulls } = result; console.log(''); - console.log(`Pull Request #${number} is ready for review.`); + console.log(`Release issue #${number} is ready for review.`); console.log(` > ${url}`); }); diff --git a/scripts/release/process-release-commit.js b/scripts/release/process-release-commit.js index 4e6c92ca2be..5c4e5447e87 100755 --- a/scripts/release/process-release-commit.js +++ b/scripts/release/process-release-commit.js @@ -1,5 +1,6 @@ #!/usr/bin/env node /* eslint-disable no-console */ +/* eslint-disable no-process-exit */ /* eslint-disable import/no-commonjs */ /* eslint-disable @typescript-eslint/no-var-requires */ const fs = require('fs'); @@ -11,7 +12,8 @@ dotenv.config(); const execa = require('execa'); -const RELEASE_BRANCH = 'release'; +const OWNER = 'eunjae-lee'; // TODO: change this later +const REPO = 'api-clients-automation'; function run(command) { const result = execa.commandSync(command); @@ -40,15 +42,17 @@ if (run('git rev-parse --abbrev-ref HEAD') !== RELEASE_BRANCH) { ); } -const pullRequestBody = JSON.parse( +const issueBody = JSON.parse( execa.sync('curl', [ '-H', `Authorization: token ${process.env.GITHUB_TOKEN}`, - `https://api.github.com/repos/algolia/api-clients-automation/pulls/${process.env.PR_NUMBER}`, + `https://api.github.com/repos/${OWNER}/${REPO}/issues/${process.env.EVENT_NUMBER}`, ]).stdout ).body; -// const pullRequestBody = `## Summary +console.log('# issueBody', issueBody); + +// const issueBody = `## Summary // Once ready, squash and merge this PR to trigger a release. // ## Version Changes @@ -63,8 +67,17 @@ const pullRequestBody = JSON.parse( // ### javascript // - 70369f5 fix(js): add version to user agent (#105)`; +if ( + !getMarkdownSection(issueBody, '## Confirmation') + .split('\n') + .find((line) => line.startsWith('- [x] Approved')) +) { + console.log('The issue was not approved.'); + process.exit(0); +} + const versionsToRelease = {}; -getMarkdownSection(pullRequestBody, '## Version Changes') +getMarkdownSection(issueBody, '## Version Changes') .split('\n') .forEach((line) => { const result = line.match(/- \[x\] (.+): v(.+) -> v(.+)/); @@ -78,10 +91,7 @@ getMarkdownSection(pullRequestBody, '## Version Changes') }; }); -const langsToUpdateRepo = getMarkdownSection( - pullRequestBody, - '## Version Changes' -) +const langsToUpdateRepo = getMarkdownSection(issueBody, '## Version Changes') .split('\n') .map((line) => { const result = line.match(/- \[ \] (.+): v(.+) -> v(.+)/); From e0c7bb78a38fa90dd2dd9beeb29e9b6de9e5b03c Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Thu, 3 Feb 2022 11:08:14 +0100 Subject: [PATCH 12/42] check released tag --- scripts/release/create-release-issue.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/release/create-release-issue.js b/scripts/release/create-release-issue.js index 7051c8bd45a..0d044f66c52 100755 --- a/scripts/release/create-release-issue.js +++ b/scripts/release/create-release-issue.js @@ -22,10 +22,10 @@ const LANG_NAME_ALIAS = { js: 'javascript', }; -function run(command) { +function run(command, errorMessage = undefined) { const result = execa.commandSync(command); if (result.exitCode !== 0) { - throw new Error(result.stderr); + throw new Error(errorMessage || result.stderr); } return result.stdout; } @@ -62,6 +62,11 @@ if (run('git status --porcelain')) { ); } +run( + `git rev-parse --verify refs/tags/${RELEASED_TAG}`, + '`released` tag is missing in this repository.' +); + // Reading versions from `openapitools.json` const versions = readVersions(); const langs = Object.keys(versions); // ["javascript", "php", "java", ...] From 741cf2684a28ff83e0429efa7f7c0a7114ee8a59 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Thu, 3 Feb 2022 11:13:52 +0100 Subject: [PATCH 13/42] check released tag --- scripts/release/create-release-issue.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/scripts/release/create-release-issue.js b/scripts/release/create-release-issue.js index 0d044f66c52..b54bdb8007b 100755 --- a/scripts/release/create-release-issue.js +++ b/scripts/release/create-release-issue.js @@ -1,5 +1,6 @@ #!/usr/bin/env node /* eslint-disable no-console */ +/* eslint-disable no-process-exit */ /* eslint-disable import/no-commonjs */ /* eslint-disable @typescript-eslint/no-var-requires */ const fs = require('fs'); @@ -23,9 +24,16 @@ const LANG_NAME_ALIAS = { }; function run(command, errorMessage = undefined) { - const result = execa.commandSync(command); - if (result.exitCode !== 0) { - throw new Error(errorMessage || result.stderr); + let result; + try { + result = execa.commandSync(command); + } catch (err) { + if (errorMessage) { + console.error(`[ERROR] ${errorMessage}`); + process.exit(err.exitCode); + } else { + throw err; + } } return result.stdout; } From 49c74c33db2993c61c006f9de432245ce3f5976f Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Thu, 3 Feb 2022 11:22:49 +0100 Subject: [PATCH 14/42] update gh action condition --- .github/workflows/process-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/process-release.yml b/.github/workflows/process-release.yml index bcb17f81ab3..db96d1a008d 100644 --- a/.github/workflows/process-release.yml +++ b/.github/workflows/process-release.yml @@ -7,7 +7,7 @@ jobs: build: name: Release runs-on: ubuntu-20.04 - if: github.event.pull_request.merged == true && github.head_ref == 'main' + if: "startsWith(github.event.issue.title, 'chore: release')" steps: - uses: actions/checkout@v2 with: From 86520404e407f0600c70882768dfef77a6734d2c Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Thu, 3 Feb 2022 11:25:08 +0100 Subject: [PATCH 15/42] fix --- .github/workflows/process-release.yml | 2 +- .../{process-release-commit.js => process-release.js} | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) rename scripts/release/{process-release-commit.js => process-release.js} (95%) diff --git a/.github/workflows/process-release.yml b/.github/workflows/process-release.yml index db96d1a008d..5e3a3f506be 100644 --- a/.github/workflows/process-release.yml +++ b/.github/workflows/process-release.yml @@ -17,7 +17,7 @@ jobs: id: setup uses: ./.github/actions/setup - - run: ./scripts/release/process-release-commit.js + - run: ./scripts/release/process-release.js env: EVENT_NUMBER: $${{ github.event.number }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/scripts/release/process-release-commit.js b/scripts/release/process-release.js similarity index 95% rename from scripts/release/process-release-commit.js rename to scripts/release/process-release.js index 5c4e5447e87..038daca945a 100755 --- a/scripts/release/process-release-commit.js +++ b/scripts/release/process-release.js @@ -36,12 +36,6 @@ function getMarkdownSection(markdown, title) { return lines.slice(0, endIndex).join('\n'); } -if (run('git rev-parse --abbrev-ref HEAD') !== RELEASE_BRANCH) { - throw new Error( - `You can run this script only from \`${RELEASE_BRANCH}\` branch.` - ); -} - const issueBody = JSON.parse( execa.sync('curl', [ '-H', From c74b2de16b550815cf09315a525df44268f65ddf Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Thu, 3 Feb 2022 11:30:22 +0100 Subject: [PATCH 16/42] . --- scripts/release/process-release.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/release/process-release.js b/scripts/release/process-release.js index 038daca945a..afb4b70e88d 100755 --- a/scripts/release/process-release.js +++ b/scripts/release/process-release.js @@ -36,6 +36,11 @@ function getMarkdownSection(markdown, title) { return lines.slice(0, endIndex).join('\n'); } +console.log('# hey!!', { + EVENT_NUMBER: process.env.EVENT_NUMBER, + GITHUB_TOKEN: process.env.GITHUB_TOKEN ? 'exists' : 'nope', +}); + const issueBody = JSON.parse( execa.sync('curl', [ '-H', From 60c3cc4e61dada59bc31760ddc705293cae69170 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Thu, 3 Feb 2022 11:32:45 +0100 Subject: [PATCH 17/42] another fix --- .github/workflows/process-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/process-release.yml b/.github/workflows/process-release.yml index 5e3a3f506be..dd44ecdb5f2 100644 --- a/.github/workflows/process-release.yml +++ b/.github/workflows/process-release.yml @@ -19,5 +19,5 @@ jobs: - run: ./scripts/release/process-release.js env: - EVENT_NUMBER: $${{ github.event.number }} + EVENT_NUMBER: ${{ github.event.number }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 3712cfca5ffaae8e5373056d09e2086156a191da Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Thu, 3 Feb 2022 11:38:03 +0100 Subject: [PATCH 18/42] . --- .github/workflows/process-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/process-release.yml b/.github/workflows/process-release.yml index dd44ecdb5f2..1d25c16aecd 100644 --- a/.github/workflows/process-release.yml +++ b/.github/workflows/process-release.yml @@ -19,5 +19,5 @@ jobs: - run: ./scripts/release/process-release.js env: - EVENT_NUMBER: ${{ github.event.number }} + EVENT_NUMBER: ${{ github.event.issue.number }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From fd7622996ebf2a6774b62d8243310a96ac15a8d2 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Thu, 3 Feb 2022 11:40:30 +0100 Subject: [PATCH 19/42] fail when not approved --- scripts/release/process-release.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/scripts/release/process-release.js b/scripts/release/process-release.js index afb4b70e88d..78c043d905d 100755 --- a/scripts/release/process-release.js +++ b/scripts/release/process-release.js @@ -36,11 +36,6 @@ function getMarkdownSection(markdown, title) { return lines.slice(0, endIndex).join('\n'); } -console.log('# hey!!', { - EVENT_NUMBER: process.env.EVENT_NUMBER, - GITHUB_TOKEN: process.env.GITHUB_TOKEN ? 'exists' : 'nope', -}); - const issueBody = JSON.parse( execa.sync('curl', [ '-H', @@ -49,8 +44,6 @@ const issueBody = JSON.parse( ]).stdout ).body; -console.log('# issueBody', issueBody); - // const issueBody = `## Summary // Once ready, squash and merge this PR to trigger a release. @@ -72,7 +65,7 @@ if ( .find((line) => line.startsWith('- [x] Approved')) ) { console.log('The issue was not approved.'); - process.exit(0); + process.exit(1); } const versionsToRelease = {}; From b60b1ef4f954697c7d684d3388823f48840749f2 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Thu, 3 Feb 2022 12:00:01 +0100 Subject: [PATCH 20/42] commit versions --- scripts/release/process-release.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/release/process-release.js b/scripts/release/process-release.js index 78c043d905d..3f50f27b02e 100755 --- a/scripts/release/process-release.js +++ b/scripts/release/process-release.js @@ -12,6 +12,7 @@ dotenv.config(); const execa = require('execa'); +const MAIN_BRANCH = 'main'; const OWNER = 'eunjae-lee'; // TODO: change this later const REPO = 'api-clients-automation'; @@ -102,6 +103,12 @@ Object.keys(json['generator-cli'].generators).forEach((client) => { }); fs.writeFileSync('openapitools.json', JSON.stringify(json, null, 2)); +run('git -c user.name="Algolia Bot"'); +run('git -c user.email="bot@algolia.com"'); +run('git add openapitools.json'); +run('git commit -m "chore: update versions"'); +run(`git push origin ${MAIN_BRANCH}`); + Object.keys(versionsToRelease).forEach((lang) => { console.log(`Generating ${lang} client(s)...`); run(`yarn generate ${lang}`).pipe(process.stdout); From 3b119d1f42357de474adbc7a02ed14ab5740c265 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Thu, 3 Feb 2022 15:07:10 +0100 Subject: [PATCH 21/42] change config --- scripts/release/process-release.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/release/process-release.js b/scripts/release/process-release.js index 3f50f27b02e..a425f4b14bf 100755 --- a/scripts/release/process-release.js +++ b/scripts/release/process-release.js @@ -103,8 +103,8 @@ Object.keys(json['generator-cli'].generators).forEach((client) => { }); fs.writeFileSync('openapitools.json', JSON.stringify(json, null, 2)); -run('git -c user.name="Algolia Bot"'); -run('git -c user.email="bot@algolia.com"'); +run('git -c user.name=api-client-bot'); +run('git -c user.email=bot@algolia.com'); run('git add openapitools.json'); run('git commit -m "chore: update versions"'); run(`git push origin ${MAIN_BRANCH}`); From 28d1198bd58d11e01924e4fd7cafa58ec5484912 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Thu, 3 Feb 2022 15:41:00 +0100 Subject: [PATCH 22/42] update git config --- scripts/release/process-release.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/release/process-release.js b/scripts/release/process-release.js index a425f4b14bf..11f3f36bf87 100755 --- a/scripts/release/process-release.js +++ b/scripts/release/process-release.js @@ -103,8 +103,8 @@ Object.keys(json['generator-cli'].generators).forEach((client) => { }); fs.writeFileSync('openapitools.json', JSON.stringify(json, null, 2)); -run('git -c user.name=api-client-bot'); -run('git -c user.email=bot@algolia.com'); +run('git config user.name=api-client-bot'); +run('git config user.email=bot@algolia.com'); run('git add openapitools.json'); run('git commit -m "chore: update versions"'); run(`git push origin ${MAIN_BRANCH}`); From 0b9931ebf4047004a67229d60d5d8b40188d2ca2 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Thu, 3 Feb 2022 15:48:51 +0100 Subject: [PATCH 23/42] update git config --- scripts/release/process-release.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/release/process-release.js b/scripts/release/process-release.js index 11f3f36bf87..67d3848439c 100755 --- a/scripts/release/process-release.js +++ b/scripts/release/process-release.js @@ -103,8 +103,8 @@ Object.keys(json['generator-cli'].generators).forEach((client) => { }); fs.writeFileSync('openapitools.json', JSON.stringify(json, null, 2)); -run('git config user.name=api-client-bot'); -run('git config user.email=bot@algolia.com'); +run('git config user.name "api-client-bot"'); +run('git config user.email "bot@algolia.com"'); run('git add openapitools.json'); run('git commit -m "chore: update versions"'); run(`git push origin ${MAIN_BRANCH}`); From 1160d7ba7404fb89f1c0bd92cdf1e56c285b1e93 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Thu, 3 Feb 2022 15:54:24 +0100 Subject: [PATCH 24/42] update command --- scripts/release/process-release.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release/process-release.js b/scripts/release/process-release.js index 67d3848439c..533c45751d7 100755 --- a/scripts/release/process-release.js +++ b/scripts/release/process-release.js @@ -106,7 +106,7 @@ fs.writeFileSync('openapitools.json', JSON.stringify(json, null, 2)); run('git config user.name "api-client-bot"'); run('git config user.email "bot@algolia.com"'); run('git add openapitools.json'); -run('git commit -m "chore: update versions"'); +execa.sync('git', ['commit', '-m', 'chore: update versions']); run(`git push origin ${MAIN_BRANCH}`); Object.keys(versionsToRelease).forEach((lang) => { From 703d47fa504bd0e3860747005952f416324bd851 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Thu, 3 Feb 2022 17:33:36 +0100 Subject: [PATCH 25/42] clean up --- scripts/release/common.js | 8 ++++++++ scripts/release/create-release-issue.js | 26 ++++++++++++------------- scripts/release/process-release.js | 4 +--- 3 files changed, 22 insertions(+), 16 deletions(-) create mode 100644 scripts/release/common.js diff --git a/scripts/release/common.js b/scripts/release/common.js new file mode 100644 index 00000000000..469c430947c --- /dev/null +++ b/scripts/release/common.js @@ -0,0 +1,8 @@ +// eslint-disable-next-line import/no-commonjs +module.exports = { + RELEASED_TAG: 'released', + MAIN_BRANCH: 'main', + OWNER: 'eunjae-lee', // TODO: change this later + REPO: 'api-clients-automation', + LANGS: new Set(['javascript', 'php', 'java']), +}; diff --git a/scripts/release/create-release-issue.js b/scripts/release/create-release-issue.js index b54bdb8007b..0cfe061b98f 100755 --- a/scripts/release/create-release-issue.js +++ b/scripts/release/create-release-issue.js @@ -10,19 +10,10 @@ const dotenv = require('dotenv'); const execa = require('execa'); // https://github.com/sindresorhus/execa/tree/v5.1.1 const semver = require('semver'); -const RELEASED_TAG = 'released'; - -const MAIN_BRANCH = 'main'; - -const OWNER = 'eunjae-lee'; // TODO: change this later -const REPO = 'api-clients-automation'; +const { RELEASED_TAG, MAIN_BRANCH, OWNER, REPO, LANGS } = require('./common'); dotenv.config(); -const LANG_NAME_ALIAS = { - js: 'javascript', -}; - function run(command, errorMessage = undefined) { let result; try { @@ -89,6 +80,7 @@ run(`git push origin ${MAIN_BRANCH}`); const header = [`## Summary`].join('\n'); const skippedCommits = []; +const wronglyScopedCommits = []; const latestCommits = run(`git log --oneline ${RELEASED_TAG}..${MAIN_BRANCH}`) .split('\n') .filter(Boolean) @@ -105,8 +97,12 @@ const latestCommits = run(`git log --oneline ${RELEASED_TAG}..${MAIN_BRANCH}`) } message = message.slice(message.indexOf(':') + 2); type = matchResult[1]; - let lang = matchResult[2]; - lang = LANG_NAME_ALIAS[lang] || lang; + const lang = matchResult[2]; + + if (!LANGS.has(lang)) { + wronglyScopedCommits.push(commit); + return undefined; + } return { hash, @@ -118,9 +114,13 @@ const latestCommits = run(`git log --oneline ${RELEASED_TAG}..${MAIN_BRANCH}`) }) .filter(Boolean); -console.warn('Skipping these commits due to lack of language scope:'); +console.log('[INFO] Skipping these commits due to lack of language scope:'); console.log(skippedCommits.map((commit) => ` ${commit}`).join('\n')); +console.log(''); +console.log('[INFO] Skipping these commits due to wrong scopes:'); +console.log(wronglyScopedCommits.map((commit) => ` ${commit}`).join('\n')); + langs.forEach((lang) => { const commits = latestCommits.filter( (lastestCommit) => lastestCommit.lang === lang diff --git a/scripts/release/process-release.js b/scripts/release/process-release.js index 533c45751d7..e32b9464e6f 100755 --- a/scripts/release/process-release.js +++ b/scripts/release/process-release.js @@ -12,9 +12,7 @@ dotenv.config(); const execa = require('execa'); -const MAIN_BRANCH = 'main'; -const OWNER = 'eunjae-lee'; // TODO: change this later -const REPO = 'api-clients-automation'; +const { MAIN_BRANCH, OWNER, REPO } = require('./common'); function run(command) { const result = execa.commandSync(command); From cdd385c3f4f46815da2e64d9ed459ad03eef2946 Mon Sep 17 00:00:00 2001 From: api-client-bot Date: Thu, 3 Feb 2022 17:43:37 +0100 Subject: [PATCH 26/42] chore: update versions --- openapitools.json | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/openapitools.json b/openapitools.json index 4c4eba0dba3..e550ac3ab73 100644 --- a/openapitools.json +++ b/openapitools.json @@ -18,8 +18,7 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/client-search", - "packageVersion": "5.0.0", - + "packageVersion": "5.1.0", "packageName": "@algolia/client-search", "isSearchHost": true } @@ -39,8 +38,7 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/recommend", - "packageVersion": "5.0.0", - + "packageVersion": "5.1.0", "packageName": "@algolia/recommend", "isSearchHost": true } @@ -59,8 +57,7 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/client-personalization", - "packageVersion": "5.0.0", - + "packageVersion": "5.1.0", "packageName": "@algolia/client-personalization", "hasRegionalHost": true, "isEuHost": true, @@ -81,8 +78,7 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/client-analytics", - "packageVersion": "5.0.0", - + "packageVersion": "5.1.0", "packageName": "@algolia/client-analytics", "hasRegionalHost": true, "isDeHost": true, @@ -104,8 +100,7 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/client-insights", - "packageVersion": "5.0.0", - + "packageVersion": "5.1.0", "packageName": "@algolia/client-insights", "host": "insights" } @@ -124,8 +119,7 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/client-abtesting", - "packageVersion": "5.0.0", - + "packageVersion": "5.1.0", "packageName": "@algolia/client-abtesting", "hasRegionalHost": true, "isDeHost": true, @@ -146,8 +140,7 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/client-query-suggestions", - "packageVersion": "5.0.0", - + "packageVersion": "5.1.0", "packageName": "@algolia/client-query-suggestions", "hasRegionalHost": true, "isEuHost": true, @@ -168,8 +161,7 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/client-sources", - "packageVersion": "0.0.1", - + "packageVersion": "5.1.0", "packageName": "@algolia/client-sources", "hasRegionalHost": true, "isDeHost": true, @@ -195,10 +187,9 @@ "sourceFolder": "algoliasearch-core", "java8": true, "dateLibrary": "java8", - "packageName": "algoliasearch-client-java-2" } } } } -} +} \ No newline at end of file From 2d33b1ad0a2bf3da927af75b2ab6fe85dca786d7 Mon Sep 17 00:00:00 2001 From: api-client-bot Date: Thu, 3 Feb 2022 17:44:06 +0100 Subject: [PATCH 27/42] prepend changelog --- doc/changelogs/{js.md => javascript.md} | 0 scripts/release/process-release.js | 41 +++++++++++++------------ 2 files changed, 22 insertions(+), 19 deletions(-) rename doc/changelogs/{js.md => javascript.md} (100%) diff --git a/doc/changelogs/js.md b/doc/changelogs/javascript.md similarity index 100% rename from doc/changelogs/js.md rename to doc/changelogs/javascript.md diff --git a/scripts/release/process-release.js b/scripts/release/process-release.js index e32b9464e6f..0385752b1a9 100755 --- a/scripts/release/process-release.js +++ b/scripts/release/process-release.js @@ -43,21 +43,6 @@ const issueBody = JSON.parse( ]).stdout ).body; -// const issueBody = `## Summary -// Once ready, squash and merge this PR to trigger a release. - -// ## Version Changes - -// - [x] javascript: v5.0.0 -> v5.0.1 -// * Uncheck if you want to skip it. -// - [ ] ~java: v4.0.0 (no commit)~ - -// ## CHANGELOG -// Update the following lines. Once merged, it will be reflected to \`docs/changelogs/*.\` - -// ### javascript -// - 70369f5 fix(js): add version to user agent (#105)`; - if ( !getMarkdownSection(issueBody, '## Confirmation') .split('\n') @@ -75,10 +60,10 @@ getMarkdownSection(issueBody, '## Version Changes') if (!result) { return; } - const [, lang, currentVersion, nextVersion] = result; + const [, lang, current, next] = result; versionsToRelease[lang] = { - currentVersion, - nextVersion, + current, + next, }; }); @@ -96,11 +81,29 @@ Object.keys(json['generator-cli'].generators).forEach((client) => { if (versionsToRelease[lang]) { json['generator-cli'].generators[ client - ].additionalProperties.packageVersion = versionsToRelease[lang].nextVersion; + ].additionalProperties.packageVersion = versionsToRelease[lang].next; } }); fs.writeFileSync('openapitools.json', JSON.stringify(json, null, 2)); +new Set([...Object.keys(versionsToRelease), ...langsToUpdateRepo]).forEach( + (lang) => { + const filePath = `doc/changelogs/${lang}.md`; + const header = versionsToRelease[lang] + ? `## ${versionsToRelease[lang].next}` + : `## ${new Date().toISOString().split('T')[0]}`; + const newChangelog = getMarkdownSection( + getMarkdownSection(issueBody, '## CHANGELOG'), + `### ${lang}` + ); + const existingContent = fs.readFileSync(filePath).toString(); + fs.writeFileSync( + filePath, + [header, newChangelog, existingContent].join('\n\n') + ); + } +); + run('git config user.name "api-client-bot"'); run('git config user.email "bot@algolia.com"'); run('git add openapitools.json'); From 8bdb9ed2c47463cd36844bf61ea50ef05d2ca5c8 Mon Sep 17 00:00:00 2001 From: api-client-bot Date: Thu, 3 Feb 2022 17:45:34 +0100 Subject: [PATCH 28/42] commit changelog --- scripts/release/process-release.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/release/process-release.js b/scripts/release/process-release.js index 0385752b1a9..4a4f8a0a5db 100755 --- a/scripts/release/process-release.js +++ b/scripts/release/process-release.js @@ -107,7 +107,8 @@ new Set([...Object.keys(versionsToRelease), ...langsToUpdateRepo]).forEach( run('git config user.name "api-client-bot"'); run('git config user.email "bot@algolia.com"'); run('git add openapitools.json'); -execa.sync('git', ['commit', '-m', 'chore: update versions']); +run('git add doc/changelogs/*'); +execa.sync('git', ['commit', '-m', 'chore: update versions and changelogs']); run(`git push origin ${MAIN_BRANCH}`); Object.keys(versionsToRelease).forEach((lang) => { From f09b6227d027e07bce59d1bc030f77ff5c6bef2b Mon Sep 17 00:00:00 2001 From: api-client-bot Date: Thu, 3 Feb 2022 17:47:12 +0100 Subject: [PATCH 29/42] Revert "chore: update versions" This reverts commit cdd385c3f4f46815da2e64d9ed459ad03eef2946. --- openapitools.json | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/openapitools.json b/openapitools.json index e550ac3ab73..4c4eba0dba3 100644 --- a/openapitools.json +++ b/openapitools.json @@ -18,7 +18,8 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/client-search", - "packageVersion": "5.1.0", + "packageVersion": "5.0.0", + "packageName": "@algolia/client-search", "isSearchHost": true } @@ -38,7 +39,8 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/recommend", - "packageVersion": "5.1.0", + "packageVersion": "5.0.0", + "packageName": "@algolia/recommend", "isSearchHost": true } @@ -57,7 +59,8 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/client-personalization", - "packageVersion": "5.1.0", + "packageVersion": "5.0.0", + "packageName": "@algolia/client-personalization", "hasRegionalHost": true, "isEuHost": true, @@ -78,7 +81,8 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/client-analytics", - "packageVersion": "5.1.0", + "packageVersion": "5.0.0", + "packageName": "@algolia/client-analytics", "hasRegionalHost": true, "isDeHost": true, @@ -100,7 +104,8 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/client-insights", - "packageVersion": "5.1.0", + "packageVersion": "5.0.0", + "packageName": "@algolia/client-insights", "host": "insights" } @@ -119,7 +124,8 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/client-abtesting", - "packageVersion": "5.1.0", + "packageVersion": "5.0.0", + "packageName": "@algolia/client-abtesting", "hasRegionalHost": true, "isDeHost": true, @@ -140,7 +146,8 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/client-query-suggestions", - "packageVersion": "5.1.0", + "packageVersion": "5.0.0", + "packageName": "@algolia/client-query-suggestions", "hasRegionalHost": true, "isEuHost": true, @@ -161,7 +168,8 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/client-sources", - "packageVersion": "5.1.0", + "packageVersion": "0.0.1", + "packageName": "@algolia/client-sources", "hasRegionalHost": true, "isDeHost": true, @@ -187,9 +195,10 @@ "sourceFolder": "algoliasearch-core", "java8": true, "dateLibrary": "java8", + "packageName": "algoliasearch-client-java-2" } } } } -} \ No newline at end of file +} From acb84929d111b63af07febe3e8dd9b3b88102661 Mon Sep 17 00:00:00 2001 From: api-client-bot Date: Wed, 9 Feb 2022 14:26:09 +0100 Subject: [PATCH 30/42] clean up --- scripts/release/common.js | 27 +++++- scripts/release/create-release-issue.js | 104 +++++++++++------------- scripts/release/process-release.js | 17 ++-- 3 files changed, 77 insertions(+), 71 deletions(-) diff --git a/scripts/release/common.js b/scripts/release/common.js index 469c430947c..f54016dbe95 100644 --- a/scripts/release/common.js +++ b/scripts/release/common.js @@ -1,8 +1,29 @@ -// eslint-disable-next-line import/no-commonjs +/* eslint-disable no-console */ +/* eslint-disable @typescript-eslint/no-var-requires */ +/* eslint-disable import/no-commonjs */ +const execa = require('execa'); // https://github.com/sindresorhus/execa/tree/v5.1.1 + +function run(command, errorMessage = undefined) { + let result; + try { + result = execa.commandSync(command); + } catch (err) { + if (errorMessage) { + console.error(`[ERROR] ${errorMessage}`); + // eslint-disable-next-line no-process-exit + process.exit(err.exitCode); + } else { + throw err; + } + } + return result.stdout; +} + module.exports = { RELEASED_TAG: 'released', MAIN_BRANCH: 'main', - OWNER: 'eunjae-lee', // TODO: change this later + OWNER: 'algolia', REPO: 'api-clients-automation', - LANGS: new Set(['javascript', 'php', 'java']), + LANGS: ['javascript', 'php', 'java'], + run, }; diff --git a/scripts/release/create-release-issue.js b/scripts/release/create-release-issue.js index 0cfe061b98f..0c794faeb8b 100755 --- a/scripts/release/create-release-issue.js +++ b/scripts/release/create-release-issue.js @@ -1,34 +1,24 @@ #!/usr/bin/env node /* eslint-disable no-console */ -/* eslint-disable no-process-exit */ /* eslint-disable import/no-commonjs */ /* eslint-disable @typescript-eslint/no-var-requires */ const fs = require('fs'); const { Octokit } = require('@octokit/rest'); const dotenv = require('dotenv'); -const execa = require('execa'); // https://github.com/sindresorhus/execa/tree/v5.1.1 const semver = require('semver'); -const { RELEASED_TAG, MAIN_BRANCH, OWNER, REPO, LANGS } = require('./common'); +const { + RELEASED_TAG, + MAIN_BRANCH, + OWNER, + REPO, + LANGS, + run, +} = require('./common'); dotenv.config(); -function run(command, errorMessage = undefined) { - let result; - try { - result = execa.commandSync(command); - } catch (err) { - if (errorMessage) { - console.error(`[ERROR] ${errorMessage}`); - process.exit(err.exitCode); - } else { - throw err; - } - } - return result.stdout; -} - function readVersions() { const versions = {}; @@ -68,19 +58,18 @@ run( // Reading versions from `openapitools.json` const versions = readVersions(); -const langs = Object.keys(versions); // ["javascript", "php", "java", ...] -// Reading commits since last release console.log('Pulling from origin...'); run(`git pull origin ${MAIN_BRANCH}`); console.log('Pushing to origin...'); run(`git push origin ${MAIN_BRANCH}`); -const header = [`## Summary`].join('\n'); +const header = `## Summary`; -const skippedCommits = []; -const wronglyScopedCommits = []; +const commitsWithoutScope = []; +const commitsWithNonLanguageScope = []; +// Reading commits since last release const latestCommits = run(`git log --oneline ${RELEASED_TAG}..${MAIN_BRANCH}`) .split('\n') .filter(Boolean) @@ -90,24 +79,22 @@ const latestCommits = run(`git log --oneline ${RELEASED_TAG}..${MAIN_BRANCH}`) let type = message.slice(0, message.indexOf(':')); const matchResult = type.match(/(.+)\((.+)\)/); if (!matchResult) { - skippedCommits.push(commit); - // console.warn(`Skipping commit ${hash} due to lack of language scope:`); - // console.warn(` > ${message}`); + commitsWithoutScope.push(commit); return undefined; } message = message.slice(message.indexOf(':') + 2); type = matchResult[1]; const lang = matchResult[2]; - if (!LANGS.has(lang)) { - wronglyScopedCommits.push(commit); + if (!LANGS.includes(lang)) { + commitsWithNonLanguageScope.push(commit); return undefined; } return { hash, - type, // e.g. `fix` - lang, // e.g. `javascript` + type, // `fix` | `feat` | `chore` | ... + lang, // `javascript` | `php` | `java` | ... message, raw: commit, }; @@ -115,13 +102,15 @@ const latestCommits = run(`git log --oneline ${RELEASED_TAG}..${MAIN_BRANCH}`) .filter(Boolean); console.log('[INFO] Skipping these commits due to lack of language scope:'); -console.log(skippedCommits.map((commit) => ` ${commit}`).join('\n')); +console.log(commitsWithoutScope.map((commit) => ` ${commit}`).join('\n')); console.log(''); console.log('[INFO] Skipping these commits due to wrong scopes:'); -console.log(wronglyScopedCommits.map((commit) => ` ${commit}`).join('\n')); +console.log( + commitsWithNonLanguageScope.map((commit) => ` ${commit}`).join('\n') +); -langs.forEach((lang) => { +LANGS.forEach((lang) => { const commits = latestCommits.filter( (lastestCommit) => lastestCommit.lang === lang ); @@ -156,41 +145,40 @@ langs.forEach((lang) => { } }); -const versionChangeHeader = [`## Version Changes`].join('\n'); +const versionChangeHeader = `## Version Changes`; -const versionChanges = langs - .map((lang) => { - const { current, next, noCommit, skipRelease, langName } = versions[lang]; +const versionChanges = LANGS.map((lang) => { + const { current, next, noCommit, skipRelease, langName } = versions[lang]; - if (noCommit) { - return `- ~${langName}: v${current} (no commit)~`; - } + if (noCommit) { + return `- ~${langName}: v${current} (no commit)~`; + } - if (!current) { - return `- ~${langName}: (current version not found)~`; - } + if (!current) { + return `- ~${langName}: (current version not found)~`; + } - const checked = skipRelease ? ' ' : 'x'; - return [ - `- [${checked}] ${langName}: v${current} -> v${next}`, - skipRelease && - ` - No \`feat\` or \`fix\` commit, thus unchecked by default.`, - ` - **Checked** → Update version, update ${langName} repository, and release the library.`, - ` - **Unchecked** → Update ${langName} repository.`, - ` - **Line removed** → Do nothing.`, - ] - .filter(Boolean) - .join('\n'); - }) - .join('\n'); + const checked = skipRelease ? ' ' : 'x'; + return [ + `- [${checked}] ${langName}: v${current} -> v${next}`, + skipRelease && + ` - No \`feat\` or \`fix\` commit, thus unchecked by default.`, + ` - **Checked** → Update version, update ${langName} repository, and release the library.`, + ` - **Unchecked** → Update ${langName} repository.`, + ` - **Line removed** → Do nothing.`, + ] + .filter(Boolean) + .join('\n'); +}).join('\n'); const changelogHeader = [ `## CHANGELOG`, `Update the following lines. Once merged, it will be reflected to \`docs/changelogs/*.\``, ].join('\n'); -const changelogs = langs - .filter((lang) => !versions[lang].noCommit && versions[lang].current) +const changelogs = LANGS.filter( + (lang) => !versions[lang].noCommit && versions[lang].current +) .flatMap((lang) => { if (versions[lang].noCommit) { return []; diff --git a/scripts/release/process-release.js b/scripts/release/process-release.js index 4a4f8a0a5db..3e83fc171fb 100755 --- a/scripts/release/process-release.js +++ b/scripts/release/process-release.js @@ -12,15 +12,7 @@ dotenv.config(); const execa = require('execa'); -const { MAIN_BRANCH, OWNER, REPO } = require('./common'); - -function run(command) { - const result = execa.commandSync(command); - if (result.exitCode !== 0) { - throw new Error(result.stderr); - } - return result.stdout; -} +const { MAIN_BRANCH, OWNER, REPO, run } = require('./common'); function getMarkdownSection(markdown, title) { const levelIndicator = title.split(' ')[0]; // e.g. `##` @@ -73,8 +65,9 @@ const langsToUpdateRepo = getMarkdownSection(issueBody, '## Version Changes') const result = line.match(/- \[ \] (.+): v(.+) -> v(.+)/); return result?.[1]; }) - .filter(Boolean); + .filter(Boolean); // e.g. ['javascript', 'php'] +// update versions in `openapitools.json` const json = JSON.parse(fs.readFileSync('openapitools.json').toString()); Object.keys(json['generator-cli'].generators).forEach((client) => { const lang = client.split('-')[0]; @@ -86,6 +79,7 @@ Object.keys(json['generator-cli'].generators).forEach((client) => { }); fs.writeFileSync('openapitools.json', JSON.stringify(json, null, 2)); +// update changelogs new Set([...Object.keys(versionsToRelease), ...langsToUpdateRepo]).forEach( (lang) => { const filePath = `doc/changelogs/${lang}.md`; @@ -104,6 +98,7 @@ new Set([...Object.keys(versionsToRelease), ...langsToUpdateRepo]).forEach( } ); +// commit openapitools and changelogs run('git config user.name "api-client-bot"'); run('git config user.email "bot@algolia.com"'); run('git add openapitools.json'); @@ -111,11 +106,13 @@ run('git add doc/changelogs/*'); execa.sync('git', ['commit', '-m', 'chore: update versions and changelogs']); run(`git push origin ${MAIN_BRANCH}`); +// generate clients to release Object.keys(versionsToRelease).forEach((lang) => { console.log(`Generating ${lang} client(s)...`); run(`yarn generate ${lang}`).pipe(process.stdout); }); +// generate clients to just update the repos langsToUpdateRepo.forEach((lang) => { console.log(`Generating ${lang} client(s)...`); run(`yarn generate ${lang}`).pipe(process.stdout); From f1f8f7cefbab8e1def6bb49274dcd318af3eb04e Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Fri, 11 Feb 2022 12:02:48 +0100 Subject: [PATCH 31/42] Update scripts/release/process-release.js MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Clément Vannicatte <20689156+shortcuts@users.noreply.github.com> --- scripts/release/process-release.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release/process-release.js b/scripts/release/process-release.js index 3e83fc171fb..7bfdc9f1705 100755 --- a/scripts/release/process-release.js +++ b/scripts/release/process-release.js @@ -99,7 +99,7 @@ new Set([...Object.keys(versionsToRelease), ...langsToUpdateRepo]).forEach( ); // commit openapitools and changelogs -run('git config user.name "api-client-bot"'); +run('git config user.name "api-clients-bot"'); run('git config user.email "bot@algolia.com"'); run('git add openapitools.json'); run('git add doc/changelogs/*'); From 6a34b36e31c3610dc4ff080564b51a03825221bc Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Fri, 11 Feb 2022 16:50:42 +0100 Subject: [PATCH 32/42] chore: clean up common --- config.json | 8 ++++++++ scripts/release/common.js | 20 +++++++++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 config.json diff --git a/config.json b/config.json new file mode 100644 index 00000000000..2442cae402a --- /dev/null +++ b/config.json @@ -0,0 +1,8 @@ +{ + "release": { + "releasedTag": "released", + "mainBranch": "main", + "owner": "algolia", + "repo": "api-clients-automation" + } +} diff --git a/scripts/release/common.js b/scripts/release/common.js index f54016dbe95..0fac6bf10b5 100644 --- a/scripts/release/common.js +++ b/scripts/release/common.js @@ -2,6 +2,8 @@ /* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable import/no-commonjs */ const execa = require('execa'); // https://github.com/sindresorhus/execa/tree/v5.1.1 +const config = require('../../config.json'); +const openapitools = require('../../openapitools.json'); function run(command, errorMessage = undefined) { let result; @@ -19,11 +21,19 @@ function run(command, errorMessage = undefined) { return result.stdout; } +const LANGS = [ + ...new Set( + Object.keys(openapitools['generator-cli'].generators).map( + (key) => key.split('-')[0] + ) + ), +]; + module.exports = { - RELEASED_TAG: 'released', - MAIN_BRANCH: 'main', - OWNER: 'algolia', - REPO: 'api-clients-automation', - LANGS: ['javascript', 'php', 'java'], + RELEASED_TAG: config.release.releasedTag, + MAIN_BRANCH: config.release.mainBranch, + OWNER: config.release.owner, + REPO: config.release.repo, + LANGS, run, }; From 3d258895d9e05981c530d55fdec6f4fe6a2c424d Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Fri, 11 Feb 2022 16:51:02 +0100 Subject: [PATCH 33/42] chore: throw instead of exit --- scripts/release/common.js | 7 ++----- scripts/release/create-release-issue.js | 7 +++---- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/scripts/release/common.js b/scripts/release/common.js index 0fac6bf10b5..6debbec78b7 100644 --- a/scripts/release/common.js +++ b/scripts/release/common.js @@ -1,19 +1,16 @@ -/* eslint-disable no-console */ /* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable import/no-commonjs */ const execa = require('execa'); // https://github.com/sindresorhus/execa/tree/v5.1.1 const config = require('../../config.json'); const openapitools = require('../../openapitools.json'); -function run(command, errorMessage = undefined) { +function run(command, { errorMessage = undefined } = {}) { let result; try { result = execa.commandSync(command); } catch (err) { if (errorMessage) { - console.error(`[ERROR] ${errorMessage}`); - // eslint-disable-next-line no-process-exit - process.exit(err.exitCode); + throw new Error(`[ERROR] ${errorMessage}`); } else { throw err; } diff --git a/scripts/release/create-release-issue.js b/scripts/release/create-release-issue.js index 0c794faeb8b..317827cd94e 100755 --- a/scripts/release/create-release-issue.js +++ b/scripts/release/create-release-issue.js @@ -51,10 +51,9 @@ if (run('git status --porcelain')) { ); } -run( - `git rev-parse --verify refs/tags/${RELEASED_TAG}`, - '`released` tag is missing in this repository.' -); +run(`git rev-parse --verify refs/tags/${RELEASED_TAG}`, { + errorMessage: '`released` tag is missing in this repository.', +}); // Reading versions from `openapitools.json` const versions = readVersions(); From ed5a9f5ecae8468f6a44d8597f7e2bf4ec3caaa7 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Fri, 11 Feb 2022 16:51:20 +0100 Subject: [PATCH 34/42] chore: return early when env var does not exist --- scripts/release/create-release-issue.js | 4 ++++ scripts/release/process-release.js | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/scripts/release/create-release-issue.js b/scripts/release/create-release-issue.js index 317827cd94e..74c8f1ac47b 100755 --- a/scripts/release/create-release-issue.js +++ b/scripts/release/create-release-issue.js @@ -39,6 +39,10 @@ function readVersions() { return versions; } +if (!process.env.GITHUB_TOKEN) { + throw new Error('Environment variable `GITHUB_TOKEN` does not exist.'); +} + if (run('git rev-parse --abbrev-ref HEAD') !== MAIN_BRANCH) { throw new Error( `You can run this script only from \`${MAIN_BRANCH}\` branch.` diff --git a/scripts/release/process-release.js b/scripts/release/process-release.js index 7bfdc9f1705..43618021ef4 100755 --- a/scripts/release/process-release.js +++ b/scripts/release/process-release.js @@ -27,6 +27,14 @@ function getMarkdownSection(markdown, title) { return lines.slice(0, endIndex).join('\n'); } +if (!process.env.GITHUB_TOKEN) { + throw new Error('Environment variable `GITHUB_TOKEN` does not exist.'); +} + +if (!process.env.EVENT_NUMBER) { + throw new Error('Environment variable `EVENT_NUMBER` does not exist.'); +} + const issueBody = JSON.parse( execa.sync('curl', [ '-H', From 7971ac98d212d552165c15c9822d3df189b82e59 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Tue, 15 Feb 2022 10:57:25 +0100 Subject: [PATCH 35/42] chore: clean up texts --- scripts/release/create-release-issue.js | 38 +++++++------------------ scripts/release/process-release.js | 16 +++++++---- scripts/release/text.js | 28 ++++++++++++++++++ 3 files changed, 49 insertions(+), 33 deletions(-) create mode 100644 scripts/release/text.js diff --git a/scripts/release/create-release-issue.js b/scripts/release/create-release-issue.js index 74c8f1ac47b..fad497c8c0d 100755 --- a/scripts/release/create-release-issue.js +++ b/scripts/release/create-release-issue.js @@ -19,6 +19,8 @@ const { dotenv.config(); +const TEXT = require('./text'); + function readVersions() { const versions = {}; @@ -68,8 +70,6 @@ run(`git pull origin ${MAIN_BRANCH}`); console.log('Pushing to origin...'); run(`git push origin ${MAIN_BRANCH}`); -const header = `## Summary`; - const commitsWithoutScope = []; const commitsWithNonLanguageScope = []; // Reading commits since last release @@ -148,37 +148,26 @@ LANGS.forEach((lang) => { } }); -const versionChangeHeader = `## Version Changes`; - const versionChanges = LANGS.map((lang) => { const { current, next, noCommit, skipRelease, langName } = versions[lang]; if (noCommit) { - return `- ~${langName}: v${current} (no commit)~`; + return `- ~${langName}: v${current} (${TEXT.noCommit})~`; } if (!current) { - return `- ~${langName}: (current version not found)~`; + return `- ~${langName}: (${TEXT.currentVersionNotFound})~`; } const checked = skipRelease ? ' ' : 'x'; return [ `- [${checked}] ${langName}: v${current} -> v${next}`, - skipRelease && - ` - No \`feat\` or \`fix\` commit, thus unchecked by default.`, - ` - **Checked** → Update version, update ${langName} repository, and release the library.`, - ` - **Unchecked** → Update ${langName} repository.`, - ` - **Line removed** → Do nothing.`, + skipRelease && TEXT.descriptionForSkippedLang(langName), ] .filter(Boolean) .join('\n'); }).join('\n'); -const changelogHeader = [ - `## CHANGELOG`, - `Update the following lines. Once merged, it will be reflected to \`docs/changelogs/*.\``, -].join('\n'); - const changelogs = LANGS.filter( (lang) => !versions[lang].noCommit && versions[lang].current ) @@ -196,20 +185,15 @@ const changelogs = LANGS.filter( }) .join('\n'); -const approval = [ - `## Confirmation`, - `To proceed this release, check the box below and close the issue.`, - `To skip this release, just close the issue.`, - `- [ ] Approved`, -].join('\n'); - const body = [ - header, - versionChangeHeader, + TEXT.header, + TEXT.versionChangeHeader, versionChanges, - changelogHeader, + TEXT.changelogHeader, + TEXT.changelogDescription, changelogs, - approval, + TEXT.approvalHeader, + TEXT.approval, ].join('\n\n'); const octokit = new Octokit({ diff --git a/scripts/release/process-release.js b/scripts/release/process-release.js index 43618021ef4..c22366a0cb4 100755 --- a/scripts/release/process-release.js +++ b/scripts/release/process-release.js @@ -13,6 +13,7 @@ dotenv.config(); const execa = require('execa'); const { MAIN_BRANCH, OWNER, REPO, run } = require('./common'); +const TEXT = require('./text'); function getMarkdownSection(markdown, title) { const levelIndicator = title.split(' ')[0]; // e.g. `##` @@ -44,16 +45,16 @@ const issueBody = JSON.parse( ).body; if ( - !getMarkdownSection(issueBody, '## Confirmation') + !getMarkdownSection(issueBody, TEXT.approvalHeader) .split('\n') - .find((line) => line.startsWith('- [x] Approved')) + .find((line) => line.startsWith(`- [x] ${TEXT.approved}`)) ) { console.log('The issue was not approved.'); process.exit(1); } const versionsToRelease = {}; -getMarkdownSection(issueBody, '## Version Changes') +getMarkdownSection(issueBody, TEXT.versionChangeHeader) .split('\n') .forEach((line) => { const result = line.match(/- \[x\] (.+): v(.+) -> v(.+)/); @@ -67,7 +68,10 @@ getMarkdownSection(issueBody, '## Version Changes') }; }); -const langsToUpdateRepo = getMarkdownSection(issueBody, '## Version Changes') +const langsToUpdateRepo = getMarkdownSection( + issueBody, + TEXT.versionChangeHeader +) .split('\n') .map((line) => { const result = line.match(/- \[ \] (.+): v(.+) -> v(.+)/); @@ -95,7 +99,7 @@ new Set([...Object.keys(versionsToRelease), ...langsToUpdateRepo]).forEach( ? `## ${versionsToRelease[lang].next}` : `## ${new Date().toISOString().split('T')[0]}`; const newChangelog = getMarkdownSection( - getMarkdownSection(issueBody, '## CHANGELOG'), + getMarkdownSection(issueBody, TEXT.changelogHeader), `### ${lang}` ); const existingContent = fs.readFileSync(filePath).toString(); @@ -111,7 +115,7 @@ run('git config user.name "api-clients-bot"'); run('git config user.email "bot@algolia.com"'); run('git add openapitools.json'); run('git add doc/changelogs/*'); -execa.sync('git', ['commit', '-m', 'chore: update versions and changelogs']); +execa.sync('git', ['commit', '-m', TEXT.commitMessage]); run(`git push origin ${MAIN_BRANCH}`); // generate clients to release diff --git a/scripts/release/text.js b/scripts/release/text.js new file mode 100644 index 00000000000..e8247b084ad --- /dev/null +++ b/scripts/release/text.js @@ -0,0 +1,28 @@ +// eslint-disable-next-line import/no-commonjs +module.exports = { + header: `## Summary`, + + versionChangeHeader: `## Version Changes`, + noCommit: `no commit`, + currentVersionNotFound: `current version not found`, + descriptionForSkippedLang: (langName) => + [ + ` - No \`feat\` or \`fix\` commit, thus unchecked by default.`, + ` - **Checked** → Update version, update ${langName} repository, and release the library.`, + ` - **Unchecked** → Update ${langName} repository.`, + ` - **Line removed** → Do nothing.`, + ].join('\n'), + + changelogHeader: `## CHANGELOG`, + changelogDescription: `Update the following lines. Once merged, it will be reflected to \`docs/changelogs/*.\``, + + approvalHeader: `## Approval`, + approved: `Approved`, + approval: [ + `To proceed this release, check the box below and close the issue.`, + `To skip this release, just close the issue.`, + `- [ ] ${this.approved}`, + ].join('\n'), + + commitMessage: `chore: update versions and changelogs`, +}; From 5ce225fb364ffe243153d3296bfdd9231cd38a75 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Wed, 16 Feb 2022 11:56:06 +0100 Subject: [PATCH 36/42] chore: convert to TS --- package.json | 5 +- scripts/package.json | 7 ++- scripts/release/common.js | 36 ------------- scripts/release/common.ts | 38 ++++++++++++++ ...lease-issue.js => create-release-issue.ts} | 52 +++++++++++-------- ...{process-release.js => process-release.ts} | 28 +++++----- scripts/release/{text.js => text.ts} | 11 ++-- scripts/tsconfig.json | 2 +- yarn.lock | 18 +++++-- 9 files changed, 108 insertions(+), 89 deletions(-) delete mode 100644 scripts/release/common.js create mode 100644 scripts/release/common.ts rename scripts/release/{create-release-issue.js => create-release-issue.ts} (88%) rename scripts/release/{process-release.js => process-release.ts} (85%) rename scripts/release/{text.js => text.ts} (83%) diff --git a/package.json b/package.json index 4a03f5528a1..eace6bbc665 100644 --- a/package.json +++ b/package.json @@ -28,10 +28,9 @@ "specs:fix": "eslint --ext=yml specs/ --fix", "specs:lint": "eslint --ext=yml specs/$0", "github-actions:lint": "eslint --ext=yml .github/", - "release": "./scripts/release/create-release-issue.js" + "release": "yarn workspace scripts release" }, "devDependencies": { - "@octokit/rest": "18.12.0", "@openapitools/openapi-generator-cli": "2.4.26", "@redocly/openapi-cli": "1.0.0-beta.79", "@typescript-eslint/eslint-plugin": "5.5.0", @@ -48,12 +47,10 @@ "eslint-plugin-prettier": "4.0.0", "eslint-plugin-unused-imports": "2.0.0", "eslint-plugin-yml": "0.12.0", - "execa": "5.1.1", "json": "11.0.0", "mustache": "4.2.0", "prettier": "2.5.1", "prettier-plugin-java": "1.6.0", - "semver": "7.3.5", "typescript": "4.5.4" }, "engines": { diff --git a/scripts/package.json b/scripts/package.json index 61fcdc1a560..b8c032c284e 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -3,12 +3,17 @@ "version": "1.0.0", "scripts": { "build": "tsc", - "setHostsOptions": "yarn build && node dist/setHostsOptions.js" + "release": "yarn build && node dist/scripts/release/create-release-issue.js", + "setHostsOptions": "yarn build && node dist/scripts/pre-gen/setHostsOptions.js" }, "devDependencies": { + "@octokit/rest": "^18.12.0", "@types/js-yaml": "4.0.5", "@types/node": "16.11.11", + "dotenv": "^16.0.0", + "execa": "5.1.1", "js-yaml": "4.1.0", + "semver": "^7.3.5", "typescript": "4.5.4" } } diff --git a/scripts/release/common.js b/scripts/release/common.js deleted file mode 100644 index 6debbec78b7..00000000000 --- a/scripts/release/common.js +++ /dev/null @@ -1,36 +0,0 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ -/* eslint-disable import/no-commonjs */ -const execa = require('execa'); // https://github.com/sindresorhus/execa/tree/v5.1.1 -const config = require('../../config.json'); -const openapitools = require('../../openapitools.json'); - -function run(command, { errorMessage = undefined } = {}) { - let result; - try { - result = execa.commandSync(command); - } catch (err) { - if (errorMessage) { - throw new Error(`[ERROR] ${errorMessage}`); - } else { - throw err; - } - } - return result.stdout; -} - -const LANGS = [ - ...new Set( - Object.keys(openapitools['generator-cli'].generators).map( - (key) => key.split('-')[0] - ) - ), -]; - -module.exports = { - RELEASED_TAG: config.release.releasedTag, - MAIN_BRANCH: config.release.mainBranch, - OWNER: config.release.owner, - REPO: config.release.repo, - LANGS, - run, -}; diff --git a/scripts/release/common.ts b/scripts/release/common.ts new file mode 100644 index 00000000000..2e0b47a666f --- /dev/null +++ b/scripts/release/common.ts @@ -0,0 +1,38 @@ +import execa from 'execa'; // https://github.com/sindresorhus/execa/tree/v5.1.1 + +import config from '../../config.json'; +import openapitools from '../../openapitools.json'; + +export const RELEASED_TAG = config.release.releasedTag; +export const MAIN_BRANCH = config.release.mainBranch; +export const OWNER = config.release.owner; +export const REPO = config.release.repo; + +type Run = ( + command: string, + options?: Partial<{ + errorMessage: string; + }> +) => execa.ExecaReturnBase['stdout']; + +export const run: Run = (command, { errorMessage = undefined } = {}) => { + let result: execa.ExecaSyncReturnValue; + try { + result = execa.commandSync(command); + } catch (err) { + if (errorMessage) { + throw new Error(`[ERROR] ${errorMessage}`); + } else { + throw err; + } + } + return result.stdout; +}; + +export const LANGS = [ + ...new Set( + Object.keys(openapitools['generator-cli'].generators).map( + (key) => key.split('-')[0] + ) + ), +]; diff --git a/scripts/release/create-release-issue.js b/scripts/release/create-release-issue.ts similarity index 88% rename from scripts/release/create-release-issue.js rename to scripts/release/create-release-issue.ts index fad497c8c0d..91eeb6c54fa 100755 --- a/scripts/release/create-release-issue.js +++ b/scripts/release/create-release-issue.ts @@ -1,27 +1,29 @@ #!/usr/bin/env node /* eslint-disable no-console */ -/* eslint-disable import/no-commonjs */ -/* eslint-disable @typescript-eslint/no-var-requires */ -const fs = require('fs'); - -const { Octokit } = require('@octokit/rest'); -const dotenv = require('dotenv'); -const semver = require('semver'); - -const { - RELEASED_TAG, - MAIN_BRANCH, - OWNER, - REPO, - LANGS, - run, -} = require('./common'); +import fs from 'fs'; + +import { Octokit } from '@octokit/rest'; +import dotenv from 'dotenv'; +import semver from 'semver'; + +import { RELEASED_TAG, MAIN_BRANCH, OWNER, REPO, LANGS, run } from './common'; +import TEXT from './text'; dotenv.config(); -const TEXT = require('./text'); +type Version = { + current: string; + langName: string; + next?: string; + noCommit?: boolean; + skipRelease?: boolean; +}; -function readVersions() { +type Versions = { + [lang: string]: Version; +}; + +function readVersions(): Versions { const versions = {}; const generators = JSON.parse( @@ -70,9 +72,17 @@ run(`git pull origin ${MAIN_BRANCH}`); console.log('Pushing to origin...'); run(`git push origin ${MAIN_BRANCH}`); -const commitsWithoutScope = []; -const commitsWithNonLanguageScope = []; +const commitsWithoutScope: string[] = []; +const commitsWithNonLanguageScope: string[] = []; + // Reading commits since last release +type LatestCommit = { + hash: string; + type: string; + lang: string; + message: string; + raw: string; +}; const latestCommits = run(`git log --oneline ${RELEASED_TAG}..${MAIN_BRANCH}`) .split('\n') .filter(Boolean) @@ -102,7 +112,7 @@ const latestCommits = run(`git log --oneline ${RELEASED_TAG}..${MAIN_BRANCH}`) raw: commit, }; }) - .filter(Boolean); + .filter(Boolean) as LatestCommit[]; console.log('[INFO] Skipping these commits due to lack of language scope:'); console.log(commitsWithoutScope.map((commit) => ` ${commit}`).join('\n')); diff --git a/scripts/release/process-release.js b/scripts/release/process-release.ts similarity index 85% rename from scripts/release/process-release.js rename to scripts/release/process-release.ts index c22366a0cb4..32726c80f58 100755 --- a/scripts/release/process-release.js +++ b/scripts/release/process-release.ts @@ -1,21 +1,16 @@ #!/usr/bin/env node /* eslint-disable no-console */ -/* eslint-disable no-process-exit */ -/* eslint-disable import/no-commonjs */ -/* eslint-disable @typescript-eslint/no-var-requires */ -const fs = require('fs'); +import fs from 'fs'; -// eslint-disable-next-line import/order -const dotenv = require('dotenv'); +import dotenv from 'dotenv'; +import execa from 'execa'; -dotenv.config(); - -const execa = require('execa'); +import { MAIN_BRANCH, OWNER, REPO, run } from './common'; +import TEXT from './text'; -const { MAIN_BRANCH, OWNER, REPO, run } = require('./common'); -const TEXT = require('./text'); +dotenv.config(); -function getMarkdownSection(markdown, title) { +function getMarkdownSection(markdown: string, title: string): string { const levelIndicator = title.split(' ')[0]; // e.g. `##` const lines = markdown.slice(markdown.indexOf(title)).split('\n'); let endIndex = lines.length; @@ -49,8 +44,7 @@ if ( .split('\n') .find((line) => line.startsWith(`- [x] ${TEXT.approved}`)) ) { - console.log('The issue was not approved.'); - process.exit(1); + throw new Error('The issue was not approved.'); } const versionsToRelease = {}; @@ -95,8 +89,8 @@ fs.writeFileSync('openapitools.json', JSON.stringify(json, null, 2)); new Set([...Object.keys(versionsToRelease), ...langsToUpdateRepo]).forEach( (lang) => { const filePath = `doc/changelogs/${lang}.md`; - const header = versionsToRelease[lang] - ? `## ${versionsToRelease[lang].next}` + const header = versionsToRelease[lang!] + ? `## ${versionsToRelease[lang!].next}` : `## ${new Date().toISOString().split('T')[0]}`; const newChangelog = getMarkdownSection( getMarkdownSection(issueBody, TEXT.changelogHeader), @@ -121,11 +115,13 @@ run(`git push origin ${MAIN_BRANCH}`); // generate clients to release Object.keys(versionsToRelease).forEach((lang) => { console.log(`Generating ${lang} client(s)...`); + // @ts-expect-error the library `execa` is not typed correctly run(`yarn generate ${lang}`).pipe(process.stdout); }); // generate clients to just update the repos langsToUpdateRepo.forEach((lang) => { console.log(`Generating ${lang} client(s)...`); + // @ts-expect-error the library `execa` is not typed correctly run(`yarn generate ${lang}`).pipe(process.stdout); }); diff --git a/scripts/release/text.js b/scripts/release/text.ts similarity index 83% rename from scripts/release/text.js rename to scripts/release/text.ts index e8247b084ad..9dfccb3ec5f 100644 --- a/scripts/release/text.js +++ b/scripts/release/text.ts @@ -1,11 +1,12 @@ -// eslint-disable-next-line import/no-commonjs -module.exports = { +const APPROVED = `Approved`; + +export default { header: `## Summary`, versionChangeHeader: `## Version Changes`, noCommit: `no commit`, currentVersionNotFound: `current version not found`, - descriptionForSkippedLang: (langName) => + descriptionForSkippedLang: (langName: string): string => [ ` - No \`feat\` or \`fix\` commit, thus unchecked by default.`, ` - **Checked** → Update version, update ${langName} repository, and release the library.`, @@ -17,11 +18,11 @@ module.exports = { changelogDescription: `Update the following lines. Once merged, it will be reflected to \`docs/changelogs/*.\``, approvalHeader: `## Approval`, - approved: `Approved`, + approved: APPROVED, approval: [ `To proceed this release, check the box below and close the issue.`, `To skip this release, just close the issue.`, - `- [ ] ${this.approved}`, + `- [ ] ${APPROVED}`, ].join('\n'), commitMessage: `chore: update versions and changelogs`, diff --git a/scripts/tsconfig.json b/scripts/tsconfig.json index b3bc49dad52..20c3f4903a6 100644 --- a/scripts/tsconfig.json +++ b/scripts/tsconfig.json @@ -4,6 +4,6 @@ "typeRoots": ["../node_modules/@types"], "outDir": "dist" }, - "include": ["pre-gen/setHostsOptions.ts"], + "include": ["pre-gen/setHostsOptions.ts", "release/*"], "exclude": ["dist", "*.json"] } diff --git a/yarn.lock b/yarn.lock index d6a37669aa3..f2334b8579d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9,7 +9,6 @@ __metadata: version: 0.0.0-use.local resolution: "@algolia/api-client-automation@workspace:." dependencies: - "@octokit/rest": 18.12.0 "@openapitools/openapi-generator-cli": 2.4.26 "@redocly/openapi-cli": 1.0.0-beta.79 "@typescript-eslint/eslint-plugin": 5.5.0 @@ -26,12 +25,10 @@ __metadata: eslint-plugin-prettier: 4.0.0 eslint-plugin-unused-imports: 2.0.0 eslint-plugin-yml: 0.12.0 - execa: 5.1.1 json: 11.0.0 mustache: 4.2.0 prettier: 2.5.1 prettier-plugin-java: 1.6.0 - semver: 7.3.5 typescript: 4.5.4 languageName: unknown linkType: soft @@ -1094,7 +1091,7 @@ __metadata: languageName: node linkType: hard -"@octokit/rest@npm:18.12.0": +"@octokit/rest@npm:^18.12.0": version: 18.12.0 resolution: "@octokit/rest@npm:18.12.0" dependencies: @@ -2558,6 +2555,13 @@ __metadata: languageName: node linkType: hard +"dotenv@npm:^16.0.0": + version: 16.0.0 + resolution: "dotenv@npm:16.0.0" + checksum: 664cebb51f0a9a1d1b930f51f0271e72e26d62feaecc9dc03df39453dd494b4e724809ca480fb3ec3213382b1ed3f791aaeb83569a137f9329ce58efd4853dbf + languageName: node + linkType: hard + "easy-table@npm:1.1.0": version: 1.1.0 resolution: "easy-table@npm:1.1.0" @@ -5806,14 +5810,18 @@ __metadata: version: 0.0.0-use.local resolution: "scripts@workspace:scripts" dependencies: + "@octokit/rest": ^18.12.0 "@types/js-yaml": 4.0.5 "@types/node": 16.11.11 + dotenv: ^16.0.0 + execa: 5.1.1 js-yaml: 4.1.0 + semver: ^7.3.5 typescript: 4.5.4 languageName: unknown linkType: soft -"semver@npm:7.3.5, semver@npm:7.x, semver@npm:^7.2.1, semver@npm:^7.3.2, semver@npm:^7.3.5": +"semver@npm:7.x, semver@npm:^7.2.1, semver@npm:^7.3.2, semver@npm:^7.3.5": version: 7.3.5 resolution: "semver@npm:7.3.5" dependencies: From f6c367b56994a6f1a8137dc1850b2876834648d9 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Wed, 16 Feb 2022 12:00:38 +0100 Subject: [PATCH 37/42] chore: import instead of read json --- scripts/release/create-release-issue.ts | 8 +++----- scripts/release/process-release.ts | 9 +++++---- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/scripts/release/create-release-issue.ts b/scripts/release/create-release-issue.ts index 91eeb6c54fa..0385429480f 100755 --- a/scripts/release/create-release-issue.ts +++ b/scripts/release/create-release-issue.ts @@ -1,11 +1,11 @@ #!/usr/bin/env node /* eslint-disable no-console */ -import fs from 'fs'; - import { Octokit } from '@octokit/rest'; import dotenv from 'dotenv'; import semver from 'semver'; +import openapitools from '../../openapitools.json'; + import { RELEASED_TAG, MAIN_BRANCH, OWNER, REPO, LANGS, run } from './common'; import TEXT from './text'; @@ -26,9 +26,7 @@ type Versions = { function readVersions(): Versions { const versions = {}; - const generators = JSON.parse( - fs.readFileSync('openapitools.json').toString() - )['generator-cli'].generators; + const generators = openapitools['generator-cli'].generators; Object.keys(generators).forEach((generator) => { const lang = generator.split('-')[0]; diff --git a/scripts/release/process-release.ts b/scripts/release/process-release.ts index 32726c80f58..a3c21c9cbb1 100755 --- a/scripts/release/process-release.ts +++ b/scripts/release/process-release.ts @@ -5,6 +5,8 @@ import fs from 'fs'; import dotenv from 'dotenv'; import execa from 'execa'; +import openapitools from '../../openapitools.json'; + import { MAIN_BRANCH, OWNER, REPO, run } from './common'; import TEXT from './text'; @@ -74,16 +76,15 @@ const langsToUpdateRepo = getMarkdownSection( .filter(Boolean); // e.g. ['javascript', 'php'] // update versions in `openapitools.json` -const json = JSON.parse(fs.readFileSync('openapitools.json').toString()); -Object.keys(json['generator-cli'].generators).forEach((client) => { +Object.keys(openapitools['generator-cli'].generators).forEach((client) => { const lang = client.split('-')[0]; if (versionsToRelease[lang]) { - json['generator-cli'].generators[ + openapitools['generator-cli'].generators[ client ].additionalProperties.packageVersion = versionsToRelease[lang].next; } }); -fs.writeFileSync('openapitools.json', JSON.stringify(json, null, 2)); +fs.writeFileSync('openapitools.json', JSON.stringify(openapitools, null, 2)); // update changelogs new Set([...Object.keys(versionsToRelease), ...langsToUpdateRepo]).forEach( From ba9017da385f0cda65e1fcba50a0f390d330ac01 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Wed, 16 Feb 2022 12:04:44 +0100 Subject: [PATCH 38/42] chore: remove unused dotenv from the root level --- package.json | 1 - yarn.lock | 15 --------------- 2 files changed, 16 deletions(-) diff --git a/package.json b/package.json index ea4a0518b0a..d7d49ba08eb 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,6 @@ "@typescript-eslint/eslint-plugin": "5.5.0", "@typescript-eslint/parser": "5.5.0", "babel-eslint": "10.1.0", - "dotenv": "14.3.2", "eslint": "8.6.0", "eslint-config-algolia": "20.0.0", "eslint-config-prettier": "8.3.0", diff --git a/yarn.lock b/yarn.lock index b797dd4ee6e..983a1886cb2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14,7 +14,6 @@ __metadata: "@typescript-eslint/eslint-plugin": 5.5.0 "@typescript-eslint/parser": 5.5.0 babel-eslint: 10.1.0 - dotenv: 14.3.2 eslint: 8.6.0 eslint-config-algolia: 20.0.0 eslint-config-prettier: 8.3.0 @@ -2633,20 +2632,6 @@ __metadata: languageName: node linkType: hard -"dotenv@npm:11.0.0": - version: 11.0.0 - resolution: "dotenv@npm:11.0.0" - checksum: 48df9e85ea1d41b3096afc1990b9b1bd966deb6c9e056cd43f14e755f3ef1e5d477c3b05afc7ca651e31320c26a9b7dc375bc3313777352c51e6a2f539ea1ffc - languageName: node - linkType: hard - -"dotenv@npm:14.3.2": - version: 14.3.2 - resolution: "dotenv@npm:14.3.2" - checksum: 86c06758915d6facc35275f4a7fafc16705b6f3b44befaa8abca91367991efc8ff8db5437d3cc14778231d19fb97610fe82d60f8a53ba723cdb69fe4171439aa - languageName: node - linkType: hard - "dotenv@npm:^16.0.0": version: 16.0.0 resolution: "dotenv@npm:16.0.0" From 1d83f15c30cb6b1d36ada9e8705b07ee90bc5fd4 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Thu, 17 Feb 2022 10:49:55 +0100 Subject: [PATCH 39/42] chore: rename config.json to release.config.json --- config.json | 8 -------- release.config.json | 6 ++++++ scripts/release/common.ts | 10 +++++----- 3 files changed, 11 insertions(+), 13 deletions(-) delete mode 100644 config.json create mode 100644 release.config.json diff --git a/config.json b/config.json deleted file mode 100644 index 2442cae402a..00000000000 --- a/config.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "release": { - "releasedTag": "released", - "mainBranch": "main", - "owner": "algolia", - "repo": "api-clients-automation" - } -} diff --git a/release.config.json b/release.config.json new file mode 100644 index 00000000000..c37c9064e67 --- /dev/null +++ b/release.config.json @@ -0,0 +1,6 @@ +{ + "releasedTag": "released", + "mainBranch": "main", + "owner": "algolia", + "repo": "api-clients-automation" +} diff --git a/scripts/release/common.ts b/scripts/release/common.ts index 2e0b47a666f..248b94e4228 100644 --- a/scripts/release/common.ts +++ b/scripts/release/common.ts @@ -1,12 +1,12 @@ import execa from 'execa'; // https://github.com/sindresorhus/execa/tree/v5.1.1 -import config from '../../config.json'; import openapitools from '../../openapitools.json'; +import config from '../../release.config.json'; -export const RELEASED_TAG = config.release.releasedTag; -export const MAIN_BRANCH = config.release.mainBranch; -export const OWNER = config.release.owner; -export const REPO = config.release.repo; +export const RELEASED_TAG = config.releasedTag; +export const MAIN_BRANCH = config.mainBranch; +export const OWNER = config.owner; +export const REPO = config.repo; type Run = ( command: string, From 47a2307c41b3bad1195943daf628cfe27f9cd43e Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Thu, 17 Feb 2022 10:51:12 +0100 Subject: [PATCH 40/42] chore: pin devDependencies --- scripts/package.json | 6 +++--- yarn.lock | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/scripts/package.json b/scripts/package.json index b8c032c284e..46c9110d790 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -7,13 +7,13 @@ "setHostsOptions": "yarn build && node dist/scripts/pre-gen/setHostsOptions.js" }, "devDependencies": { - "@octokit/rest": "^18.12.0", + "@octokit/rest": "18.12.0", "@types/js-yaml": "4.0.5", "@types/node": "16.11.11", - "dotenv": "^16.0.0", + "dotenv": "16.0.0", "execa": "5.1.1", "js-yaml": "4.1.0", - "semver": "^7.3.5", + "semver": "7.3.5", "typescript": "4.5.4" } } diff --git a/yarn.lock b/yarn.lock index 983a1886cb2..69fff3a224b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1118,7 +1118,7 @@ __metadata: languageName: node linkType: hard -"@octokit/rest@npm:^18.12.0": +"@octokit/rest@npm:18.12.0": version: 18.12.0 resolution: "@octokit/rest@npm:18.12.0" dependencies: @@ -2632,7 +2632,7 @@ __metadata: languageName: node linkType: hard -"dotenv@npm:^16.0.0": +"dotenv@npm:16.0.0": version: 16.0.0 resolution: "dotenv@npm:16.0.0" checksum: 664cebb51f0a9a1d1b930f51f0271e72e26d62feaecc9dc03df39453dd494b4e724809ca480fb3ec3213382b1ed3f791aaeb83569a137f9329ce58efd4853dbf @@ -5882,18 +5882,18 @@ __metadata: version: 0.0.0-use.local resolution: "scripts@workspace:scripts" dependencies: - "@octokit/rest": ^18.12.0 + "@octokit/rest": 18.12.0 "@types/js-yaml": 4.0.5 "@types/node": 16.11.11 - dotenv: ^16.0.0 + dotenv: 16.0.0 execa: 5.1.1 js-yaml: 4.1.0 - semver: ^7.3.5 + semver: 7.3.5 typescript: 4.5.4 languageName: unknown linkType: soft -"semver@npm:7.x, semver@npm:^7.2.1, semver@npm:^7.3.2, semver@npm:^7.3.5": +"semver@npm:7.3.5, semver@npm:7.x, semver@npm:^7.2.1, semver@npm:^7.3.2, semver@npm:^7.3.5": version: 7.3.5 resolution: "semver@npm:7.3.5" dependencies: From b9e765dd4522e66f9582919a5c262bf9be7073f4 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Thu, 17 Feb 2022 10:53:00 +0100 Subject: [PATCH 41/42] chore: remove shebang --- scripts/release/create-release-issue.ts | 1 - scripts/release/process-release.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/scripts/release/create-release-issue.ts b/scripts/release/create-release-issue.ts index 0385429480f..b0aa454aded 100755 --- a/scripts/release/create-release-issue.ts +++ b/scripts/release/create-release-issue.ts @@ -1,4 +1,3 @@ -#!/usr/bin/env node /* eslint-disable no-console */ import { Octokit } from '@octokit/rest'; import dotenv from 'dotenv'; diff --git a/scripts/release/process-release.ts b/scripts/release/process-release.ts index a3c21c9cbb1..669c115c56e 100755 --- a/scripts/release/process-release.ts +++ b/scripts/release/process-release.ts @@ -1,4 +1,3 @@ -#!/usr/bin/env node /* eslint-disable no-console */ import fs from 'fs'; From 5c1fdc68388a737a52cff3d45841b9b9b1cedfd8 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Thu, 17 Feb 2022 10:58:39 +0100 Subject: [PATCH 42/42] chore: use trim instead of arbitrary number --- scripts/release/create-release-issue.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release/create-release-issue.ts b/scripts/release/create-release-issue.ts index b0aa454aded..1e316d72a27 100755 --- a/scripts/release/create-release-issue.ts +++ b/scripts/release/create-release-issue.ts @@ -92,7 +92,7 @@ const latestCommits = run(`git log --oneline ${RELEASED_TAG}..${MAIN_BRANCH}`) commitsWithoutScope.push(commit); return undefined; } - message = message.slice(message.indexOf(':') + 2); + message = message.slice(message.indexOf(':') + 1).trim(); type = matchResult[1]; const lang = matchResult[2];