diff --git a/dev/release-v6.ts b/dev/release-v6.ts new file mode 100755 index 000000000000..d8cfe4ca8d23 --- /dev/null +++ b/dev/release-v6.ts @@ -0,0 +1,132 @@ +/* eslint-disable camelcase */ +/** + * Merges all the to be released commits into the v6 branch and pushes it to the remote. + * The push will then trigger the release process via the GitHub Action workflow. + * + * Main branch must be up-to-date. To be executed on the target branch. + * + * Usage: + * DRY_RUN= GITHUB_TOKEN= node_modules/.bin/ts-node dev/release-v6.ts + */ + +import { Octokit } from '@octokit/rest'; +import { Endpoints } from '@octokit/types'; +import { execSync } from 'child_process'; + +type Card = + Endpoints['GET /projects/columns/cards/{card_id}']['response']['data']; +type PullRequest = + Endpoints['GET /repos/{owner}/{repo}/pulls/{pull_number}']['response']['data']; +type CardCommit = { + card: Card; + commit: PullRequest; +}; + +const OWNER = 'sequelize'; +const REPO = 'sequelize'; +const TO_BE_RELEASED_COLUMN_ID = 17352881; +const RELEASING_COLUMN_ID = 17444349; + +(async () => { + const token = process.env.GITHUB_TOKEN; + + if (!token) { + console.error('GITHUB_TOKEN variable is not set'); + process.exit(1); + } + + const github = new Octokit({ + auth: token + }); + const commits = await getCommitsFromProject(github); + + await Promise.all(commits.map(commit => mergeCommit(github, commit))); +})(); + +// Helpers + +async function getCommitsFromProject(github: Octokit): Promise { + const cards = await github.rest.projects.listCards({ + column_id: TO_BE_RELEASED_COLUMN_ID + }); + + const commits = await Promise.all( + cards.data.filter(isIssueCard).map(async (card: Card) => ({ + card, + commit: await cardToMergedCommit(github, card) + })) + ); + + const filtered = commits.filter(({ commit }) => + Boolean(commit) + ) as CardCommit[]; + + return filtered.sort(sortCommits); +} + +function isIssueCard(card: Card) { + return card.content_url?.includes('/issues/'); +} + +async function cardToMergedCommit( + github: Octokit, + card: Card +): Promise { + const issueNumber = card.content_url?.split('/').pop(); + const { data: pullRequest } = await github.pulls.get({ + owner: OWNER, + repo: REPO, + pull_number: Number(issueNumber) + }); + + if (!pullRequest?.merged) { + return; + } + + return pullRequest; +} + +function sortCommits(a: CardCommit, b: CardCommit) { + const aDate = new Date(a.commit.merged_at || ''); + const bDate = new Date(b.commit.merged_at || ''); + + return aDate.getTime() - bDate.getTime(); +} + +async function mergeCommit(github: Octokit, { card, commit }: CardCommit) { + mergeCommitTeaser(commit); + + if (commit.merge_commit_sha) { + await gitMerge(commit.merge_commit_sha); + await moveCard(github, card, RELEASING_COLUMN_ID); + } +} + +function mergeCommitTeaser(commit: PullRequest) { + console.info(); + console.info('Merging commit:', commit.title); + console.info('- Commit SHA:', commit.merge_commit_sha); + console.info('- Commit URL:', commit.html_url); +} + +async function moveCard(github: Octokit, card: Card, to: number) { + if (process.env.DRY_RUN === 'false') { + const a = await github.rest.projects.moveCard({ + card_id: card.id, + position: 'bottom', + column_id: to + }); + + console.log(a); + } +} + +async function gitMerge(sha: string) { + const gitCommand = `git cherry-pick ${sha}`; + + console.info('- Git command:', gitCommand); + + if (process.env.DRY_RUN === 'false') { + execSync(gitCommand, { stdio: 'inherit' }); + } +} diff --git a/package.json b/package.json index 587743e241f0..cf7dee1efffe 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,8 @@ "devDependencies": { "@commitlint/cli": "^15.0.0", "@commitlint/config-angular": "^15.0.0", + "@octokit/rest": "^18.12.0", + "@octokit/types": "^6.34.0", "@types/chai": "^4.3.0", "@types/mocha": "^9.0.0", "@types/node": "^16.11.17", @@ -88,6 +90,7 @@ "fast-glob": "^3.2.7", "fs-jetpack": "^4.3.0", "husky": "^7.0.4", + "ibm_db": "^2.8.1", "js-combinatorics": "^0.6.1", "lcov-result-merger": "^3.1.0", "lint-staged": "^12.1.4", @@ -95,7 +98,6 @@ "markdownlint-cli": "^0.30.0", "mocha": "^7.2.0", "module-alias": "^2.2.2", - "ibm_db": "^2.8.1", "mysql2": "^2.3.3", "node-hook": "^1.0.0", "nyc": "^15.1.0", diff --git a/yarn.lock b/yarn.lock index d05da190649c..68a181e4ea09 100644 --- a/yarn.lock +++ b/yarn.lock @@ -807,7 +807,7 @@ node-fetch "^2.6.1" universal-user-agent "^6.0.0" -"@octokit/rest@^18.0.0": +"@octokit/rest@^18.0.0", "@octokit/rest@^18.12.0": version "18.12.0" resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.12.0.tgz#f06bc4952fc87130308d810ca9d00e79f6988881" integrity sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==