From 1c7c3e0a9ab96fb3f2e2793be84bd6ed19cfb7a6 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 2 Jun 2022 19:56:50 +0200 Subject: [PATCH 1/4] meta: fix release process for beta branch --- .github/workflows/release.yml | 4 +- private/release/commit-and-open-pr.js | 47 +++++++++++++++++++- private/release/config.js | 1 + private/release/getUpToDateRefsFromGitHub.js | 8 ++-- 4 files changed, 53 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 049e00d396..bf4e8ee2af 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -84,8 +84,8 @@ jobs: run: gh api -X DELETE repos/${{ github.repository }}/git/refs/heads/release-candidate || echo "Already deleted" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Remove release branch - run: gh api -X DELETE repos/${{ github.repository }}/git/refs/heads/release + - name: Remove release-beta branch + run: gh api -X DELETE repos/${{ github.repository }}/git/refs/heads/release-beta env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Disable Release workflow diff --git a/private/release/commit-and-open-pr.js b/private/release/commit-and-open-pr.js index 7cf9de1414..dcb9c3177d 100644 --- a/private/release/commit-and-open-pr.js +++ b/private/release/commit-and-open-pr.js @@ -1,7 +1,7 @@ import { spawnSync } from 'node:child_process' import { fileURLToPath } from 'node:url' import prompts from 'prompts' -import { REPO_OWNER, REPO_NAME } from './config.js' +import { STABLE_BRANCH, REPO_NAME, REPO_OWNER } from './config.js' export default async function commit (spawnOptions, ...files) { console.log(`Now is the time to do manual edits to ${files.join(',')}.`) @@ -15,8 +15,53 @@ export default async function commit (spawnOptions, ...files) { }) spawnSync('git', ['add', ...files.map(url => fileURLToPath(url))], spawnOptions) + const remoteHeadSha = spawnSync('git', ['rev-parse', 'HEAD'], spawnOptions).stdout.toString().trim() spawnSync('git', ['commit', '-n', '-m', 'Prepare next release'], { ...spawnOptions, stdio: 'inherit' }) + const releaseSha = spawnSync('git', ['rev-parse', 'HEAD'], spawnOptions).stdout.toString().trim() + + console.log('Attempting to merge changes from default branch...') + { + // eslint-disable-next-line no-shadow + const { status, stdout, stderr } = spawnSync( + 'git', + [ + 'fetch', + `https://github.com/${REPO_OWNER}/${REPO_NAME}.git`, + STABLE_BRANCH, + ], + spawnOptions, + ) + + if (status) { + console.log(stdout.toString()) + console.error(stderr.toString()) + throw new Error('Failed to fetch, please ensure manually that your local repository is up to date') + } + } + + { + // eslint-disable-next-line no-shadow + const { status, stdout, stderr } = spawnSync( + 'git', + [ + 'merge', + 'FETCH_HEAD', + ], + spawnOptions, + ) + if (status) { + console.log(stdout.toString()) + console.error(stderr.toString()) + throw new Error('Failed to fetch, please ensure manually that your local repository is up to date') + } + } + const mergeSha = spawnSync('git', ['rev-parse', 'HEAD'], spawnOptions).stdout.toString().trim() + + spawnSync('git', ['reset', remoteHeadSha, '--hard'], spawnOptions) + spawnSync('git', ['cherry-pick', mergeSha, '--hard'], spawnOptions) + spawnSync('git', ['cherry-pick', releaseSha, '--hard'], spawnOptions) const sha = spawnSync('git', ['rev-parse', 'HEAD'], spawnOptions).stdout.toString().trim() + const getRemoteCommamnd = `git remote -v | grep '${REPO_OWNER}/${REPO_NAME}' | awk '($3 == "(push)") { print $1; exit }'` const remote = spawnSync('/bin/sh', ['-c', getRemoteCommamnd]).stdout.toString().trim() || `git@github.com:${REPO_OWNER}/${REPO_NAME}.git` diff --git a/private/release/config.js b/private/release/config.js index b6a6c7ec50..21d9798166 100644 --- a/private/release/config.js +++ b/private/release/config.js @@ -1,3 +1,4 @@ export const REPO_OWNER = 'transloadit' export const REPO_NAME = 'uppy' export const TARGET_BRANCH = '3.x' +export const STABLE_BRANCH = 'main' diff --git a/private/release/getUpToDateRefsFromGitHub.js b/private/release/getUpToDateRefsFromGitHub.js index e67d3cb130..e72d676cbe 100644 --- a/private/release/getUpToDateRefsFromGitHub.js +++ b/private/release/getUpToDateRefsFromGitHub.js @@ -25,10 +25,10 @@ export async function getRemoteHEAD () { } async function getLatestReleaseSHA () { - const { tag_name } = await apiCall( - `/releases/latest`, - 'Cannot get latest release from GitHub, check your internet connection.', - ) + const response = await fetch(`https://raw.githubusercontent.com/${REPO_OWNER}/${REPO_NAME}/${TARGET_BRANCH}/packages/uppy/package.json`) + if (!response.ok) throw new Error(`Network call failed: ${response.status} ${response.statusText}`) + const { version } = await response.json() + const tag_name = `uppy@${version}` console.log(`Last release was ${tag_name}.`) return ( await apiCall( From 12791377108d6283c54424dbc4c1614fd7517cbc Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Tue, 7 Jun 2022 19:35:32 +0200 Subject: [PATCH 2/4] Acknowledge merging of the stable branch --- private/release/choose-semverness.js | 27 +++++++++++++-- private/release/commit-and-open-pr.js | 36 +++++++------------- private/release/getUpToDateRefsFromGitHub.js | 13 +++++-- private/release/interactive.js | 6 ++-- 4 files changed, 51 insertions(+), 31 deletions(-) diff --git a/private/release/choose-semverness.js b/private/release/choose-semverness.js index 3a7654c1f4..1c7d94cfd8 100755 --- a/private/release/choose-semverness.js +++ b/private/release/choose-semverness.js @@ -4,6 +4,7 @@ import { createWriteStream, mkdirSync, readFileSync } from 'node:fs' import { spawnSync } from 'node:child_process' import prompts from 'prompts' +import { TARGET_BRANCH } from './config.js' const ROOT = new URL('../../', import.meta.url) const PACKAGES_FOLDER = new URL('./packages/', ROOT) @@ -26,6 +27,7 @@ function maxSemverness (a, b) { export default async function pickSemverness ( spawnOptions, LAST_RELEASE_COMMIT, + STABLE_BRANCH_MERGE_BASE_RANGE, releaseFileUrl, packagesList, ) { @@ -55,7 +57,28 @@ export default async function pickSemverness ( spawnOptions, ) if (stdout.length === 0) { - console.log(`No commits since last release for ${name}, skipping.`) + const { stdout } = spawnSync( + 'git', + [ + '--no-pager', + 'log', + '--format=- %s', + STABLE_BRANCH_MERGE_BASE_RANGE, + '--', + location, + ], + spawnOptions, + ) + if (stdout.length === 0) { + console.log(`No commits since last release for ${name}, skipping.`) + } else { + console.log(`Some commits have landed on the stable branch since last release for ${name}.`) + releaseFile.write(` ${JSON.stringify(name)}: prerelease\n`) + uppySemverness = maxSemverness(uppySemverness, 'prerelease') + if (robodogDeps.includes(name)) { + robodogSemverness = maxSemverness(robodogSemverness, 'prerelease') + } + } continue } console.log('\n') @@ -65,7 +88,7 @@ export default async function pickSemverness ( `\nHere are the commits that landed on ${name} since previous release:\n${stdout}\n`, ) console.log( - `Check the web UI at https://github.com/transloadit/uppy/tree/main/${encodeURI( + `Check the web UI at https://github.com/transloadit/uppy/tree/${TARGET_BRANCH}/${encodeURI( location, )}.`, ) diff --git a/private/release/commit-and-open-pr.js b/private/release/commit-and-open-pr.js index dcb9c3177d..b946fd40b4 100644 --- a/private/release/commit-and-open-pr.js +++ b/private/release/commit-and-open-pr.js @@ -1,9 +1,9 @@ import { spawnSync } from 'node:child_process' import { fileURLToPath } from 'node:url' import prompts from 'prompts' -import { STABLE_BRANCH, REPO_NAME, REPO_OWNER } from './config.js' +import { REPO_NAME, REPO_OWNER } from './config.js' -export default async function commit (spawnOptions, ...files) { +export default async function commit (spawnOptions, STABLE_HEAD, ...files) { console.log(`Now is the time to do manual edits to ${files.join(',')}.`) await prompts({ type: 'toggle', @@ -19,40 +19,28 @@ export default async function commit (spawnOptions, ...files) { spawnSync('git', ['commit', '-n', '-m', 'Prepare next release'], { ...spawnOptions, stdio: 'inherit' }) const releaseSha = spawnSync('git', ['rev-parse', 'HEAD'], spawnOptions).stdout.toString().trim() - console.log('Attempting to merge changes from default branch...') - { - // eslint-disable-next-line no-shadow - const { status, stdout, stderr } = spawnSync( - 'git', - [ - 'fetch', - `https://github.com/${REPO_OWNER}/${REPO_NAME}.git`, - STABLE_BRANCH, - ], - spawnOptions, - ) - - if (status) { - console.log(stdout.toString()) - console.error(stderr.toString()) - throw new Error('Failed to fetch, please ensure manually that your local repository is up to date') - } - } - + console.log('Attempting to merge changes from stable branch...') { // eslint-disable-next-line no-shadow const { status, stdout, stderr } = spawnSync( 'git', [ 'merge', - 'FETCH_HEAD', + STABLE_HEAD, ], spawnOptions, ) if (status) { console.log(stdout.toString()) console.error(stderr.toString()) - throw new Error('Failed to fetch, please ensure manually that your local repository is up to date') + await prompts({ + type: 'toggle', + name: 'value', + message: 'Fix the conflict before continuing. Ready?', + initial: true, + active: 'yes', + inactive: 'yes', + }) } } const mergeSha = spawnSync('git', ['rev-parse', 'HEAD'], spawnOptions).stdout.toString().trim() diff --git a/private/release/getUpToDateRefsFromGitHub.js b/private/release/getUpToDateRefsFromGitHub.js index e72d676cbe..7989568649 100644 --- a/private/release/getUpToDateRefsFromGitHub.js +++ b/private/release/getUpToDateRefsFromGitHub.js @@ -2,7 +2,7 @@ import fetch from 'node-fetch' import { spawnSync } from 'node:child_process' import prompts from 'prompts' -import { TARGET_BRANCH, REPO_NAME, REPO_OWNER } from './config.js' +import { TARGET_BRANCH, REPO_NAME, REPO_OWNER, STABLE_BRANCH } from './config.js' async function apiCall (endpoint, errorMessage) { const response = await fetch( @@ -38,6 +38,15 @@ async function getLatestReleaseSHA () { ).object.sha } +function getStableBranchMergeBase (REMOTE_HEAD) { + spawnSync('git', ['fetch', `https://github.com/${REPO_OWNER}/${REPO_NAME}.git`, STABLE_BRANCH]) + const STABLE_HEAD = spawnSync('git', ['rev-parse', 'FETCH_HEAD']).stdout.toString().trim() + return [[ + spawnSync('git', ['merge-base', REMOTE_HEAD, 'FETCH_HEAD']).stdout.toString().trim(), + STABLE_HEAD, + ].join('..'), STABLE_HEAD] +} + async function getLocalHEAD () { return spawnSync('git', ['rev-parse', 'HEAD']).stdout.toString().trim() } @@ -104,5 +113,5 @@ export async function validateGitStatus (spawnOptions) { } } - return [await latestRelease, LOCAL_HEAD] + return [await latestRelease, LOCAL_HEAD, ...getStableBranchMergeBase(REMOTE_HEAD)] } diff --git a/private/release/interactive.js b/private/release/interactive.js index c62af916c0..6b1c8be272 100755 --- a/private/release/interactive.js +++ b/private/release/interactive.js @@ -14,14 +14,14 @@ const deferredReleaseFile = new URL('./.yarn/versions/next.yml', ROOT) const temporaryChangeLog = new URL('./CHANGELOG.next.md', ROOT) console.log('Validating local repo status and get previous release info...') -const [LAST_RELEASE_COMMIT, LOCAL_HEAD] = await validateGitStatus(spawnOptions) +const [LAST_RELEASE_COMMIT, LOCAL_HEAD, MERGE_BASE, STABLE_HEAD] = await validateGitStatus(spawnOptions) try { console.log('Local git repository is ready, starting release process...') - await pickSemverness(spawnOptions, LAST_RELEASE_COMMIT, deferredReleaseFile, process.env.PACKAGES.split(' ')) + await pickSemverness(spawnOptions, LAST_RELEASE_COMMIT, MERGE_BASE, deferredReleaseFile, process.env.PACKAGES.split(' ')) console.log('Working on the changelog...') await formatChangeLog(spawnOptions, LAST_RELEASE_COMMIT, temporaryChangeLog) console.log('Final step...') - await commit(spawnOptions, deferredReleaseFile, temporaryChangeLog) + await commit(spawnOptions, STABLE_HEAD, deferredReleaseFile, temporaryChangeLog) } finally { console.log('Rewinding git history...') await rewindGitHistory(spawnOptions, LOCAL_HEAD) From 12da329bc4110f53b701c1b079b4296d10a37051 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Tue, 7 Jun 2022 20:08:15 +0200 Subject: [PATCH 3/4] auto-fix conflicts --- private/release/autoFixConflicts.js | 56 +++++++++++++++++++++++++++ private/release/commit-and-open-pr.js | 18 +++++++++ 2 files changed, 74 insertions(+) create mode 100755 private/release/autoFixConflicts.js diff --git a/private/release/autoFixConflicts.js b/private/release/autoFixConflicts.js new file mode 100755 index 0000000000..0cb29a580f --- /dev/null +++ b/private/release/autoFixConflicts.js @@ -0,0 +1,56 @@ +#!/usr/bin/env node + +// Usage: autoFixConflicts.js | sh + +import { createInterface as readLines } from 'node:readline' +import { spawn } from 'node:child_process' + +const VERSION_URL = /(?<=https:\/\/\S+\/v)\d+\.\d+\.\d+(?:-(?:alpha|beta)(?:[.-]\d+)?)?(?=\/)/ + +const gitStatus = spawn('git', ['status', '--porcelain']) + +for await (const line of readLines(gitStatus.stdout)) { + // eslint-disable-next-line no-continue + if (!line.startsWith('UU ')) continue + + const file = line.slice(3) + if (file === 'yarn.lock') { + console.log('corepack yarn install') + console.log('git add yarn.lock') + // eslint-disable-next-line no-continue + continue + } + + if (file.endsWith('/package.json')) { + console.log(`git checkout --ours ${file}`) + console.log(`git add ${file}`) + // eslint-disable-next-line no-continue + continue + } + + const gitDiff = spawn('git', ['--no-pager', 'diff', '--', file]) + let conflictHasStarted = false + let containsCDNChanges = true + let currentConflictContainsCDNChanges = false + + // eslint-disable-next-line no-shadow + for await (const line of readLines(gitDiff.stdout)) { + if (conflictHasStarted) { + if (line.startsWith('++>>>>>>>')) { + conflictHasStarted = false + containsCDNChanges &&= currentConflictContainsCDNChanges + currentConflictContainsCDNChanges = false + } else { + currentConflictContainsCDNChanges ||= VERSION_URL.test(line) + } + } else if (line === '++<<<<<<< HEAD') { + conflictHasStarted = true + } + } + if (containsCDNChanges) { + console.log(`git checkout --ours ${file}`) + console.log(`git add ${file}`) + // eslint-disable-next-line no-continue + continue + } +} diff --git a/private/release/commit-and-open-pr.js b/private/release/commit-and-open-pr.js index b946fd40b4..d7325c9e06 100644 --- a/private/release/commit-and-open-pr.js +++ b/private/release/commit-and-open-pr.js @@ -26,6 +26,9 @@ export default async function commit (spawnOptions, STABLE_HEAD, ...files) { 'git', [ 'merge', + '--no-edit', + '-m', + 'Merge stable branch', STABLE_HEAD, ], spawnOptions, @@ -33,6 +36,7 @@ export default async function commit (spawnOptions, STABLE_HEAD, ...files) { if (status) { console.log(stdout.toString()) console.error(stderr.toString()) + await prompts({ type: 'toggle', name: 'value', @@ -41,6 +45,20 @@ export default async function commit (spawnOptions, STABLE_HEAD, ...files) { active: 'yes', inactive: 'yes', }) + + // eslint-disable-next-line no-shadow + const { status } = spawnSync( + 'git', + [ + 'merge', + '--continue', + ], + { ...spawnOptions, stdio: 'inherit' }, + ) + + if (status) { + throw new Error('Merge has failed') + } } } const mergeSha = spawnSync('git', ['rev-parse', 'HEAD'], spawnOptions).stdout.toString().trim() From 9eda867be137d41463f18fc32a1dcd704a697509 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 9 Jun 2022 18:46:15 +0200 Subject: [PATCH 4/4] Revert changes that have already landed on `main` Refs: 5a09823f6d725974a657e8c9e6438fa508d5965b --- private/release/choose-semverness.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/private/release/choose-semverness.js b/private/release/choose-semverness.js index 1c7d94cfd8..965d20526a 100755 --- a/private/release/choose-semverness.js +++ b/private/release/choose-semverness.js @@ -4,7 +4,6 @@ import { createWriteStream, mkdirSync, readFileSync } from 'node:fs' import { spawnSync } from 'node:child_process' import prompts from 'prompts' -import { TARGET_BRANCH } from './config.js' const ROOT = new URL('../../', import.meta.url) const PACKAGES_FOLDER = new URL('./packages/', ROOT) @@ -88,7 +87,7 @@ export default async function pickSemverness ( `\nHere are the commits that landed on ${name} since previous release:\n${stdout}\n`, ) console.log( - `Check the web UI at https://github.com/transloadit/uppy/tree/${TARGET_BRANCH}/${encodeURI( + `Check the web UI at https://github.com/transloadit/uppy/tree/main/${encodeURI( location, )}.`, )