diff --git a/.github/workflows/release-candidate.yml b/.github/workflows/release-candidate.yml index 6ee9cce32..4d587a556 100644 --- a/.github/workflows/release-candidate.yml +++ b/.github/workflows/release-candidate.yml @@ -1,22 +1,26 @@ -name: Release beta candidate +name: Release candidate on: push: - branches: release-beta + branches: release env: - BETA_BRANCH: 4.x YARN_ENABLE_GLOBAL_CACHE: false jobs: - prepare-beta-release: + prepare-release: name: Prepare release candidate Pull Request runs-on: ubuntu-latest steps: - name: Checkout sources uses: actions/checkout@v4 with: - branch: release-beta - fetch-depth: 3 # the prepare commit, the merge commit, and the base ones. + branch: release + - name: Rebase + run: | + git fetch origin HEAD --depth=1 + git config --global user.email "actions@github.com" + git config --global user.name "GitHub Actions" + git rebase FETCH_HEAD - name: Get yarn cache directory path id: yarn-cache-dir-path run: @@ -39,13 +43,15 @@ jobs: # https://docs.cypress.io/guides/references/advanced-installation#Skipping-installation CYPRESS_INSTALL_BINARY: 0 - name: Bump candidate packages version - run: - corepack yarn version apply --all --prerelease=beta.%n --json | jq -s - > releases.json + run: corepack yarn version apply --all --json | jq -s > releases.json - name: Prepare changelog run: corepack yarn workspace @uppy-dev/release update-changelogs releases.json | xargs git add + - name: Update contributors table + run: + corepack yarn contributors:save && corepack yarn remark -foq README.md + && corepack yarn prettier -w README.md && git add README.md - name: Update CDN URLs run: corepack yarn workspace @uppy-dev/release update-version-URLs | xargs @@ -62,15 +68,13 @@ jobs: echo "This is a release candidate for the following packages:" >> commitMessage echo >> commitMessage jq -r 'map("- `"+.ident+"`: "+.oldVersion+" -> "+.newVersion) | join("\n") ' < releases.json >> commitMessage - git config --global user.email "actions@github.com" - git config --global user.name "GitHub Actions" git commit -n --amend --file commitMessage - name: Open Pull Request id: pr_opening run: | git push origin HEAD:release-candidate gh api repos/${{ github.repository }}/pulls \ - -F base="${{ env.BETA_BRANCH }}" \ + -F base="$(gh api /repos/${{ github.repository }} | jq -r .default_branch)" \ -F head="release-candidate" \ -F title="$(head -1 commitMessage)" \ -F body="$(git --no-pager diff HEAD^ -- CHANGELOG.md | awk '{ if( substr($0,0,1) == "+" && $1 != "+##" && $1 != "+Released:" && $1 != "+++" ) { print substr($0,2) } }')" \ diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 336fa4e25..1ba7b1366 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -57,7 +57,7 @@ jobs: - name: Publish to the npm registry run: corepack yarn workspaces foreach --all --no-private npm publish - --access public --tag next --tolerate-republish + --access public --tolerate-republish env: YARN_NPM_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Merge PR @@ -85,7 +85,6 @@ jobs: run: gh release create uppy@${{ steps.uppyVersion.outputs.version }} -t "Uppy ${{ steps.uppyVersion.outputs.version }}" -F CHANGELOG.diff.md - --prerelease env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload `uppy` to CDN @@ -113,10 +112,9 @@ jobs: }}/git/refs/heads/release-candidate || echo "Already deleted" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Remove release-beta branch + - name: Remove release branch run: - gh api -X DELETE repos/${{ github.repository - }}/git/refs/heads/release-beta + gh api -X DELETE repos/${{ github.repository }}/git/refs/heads/release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Disable Release workflow diff --git a/private/release/choose-semverness.js b/private/release/choose-semverness.js index f1cff8886..8a2172544 100755 --- a/private/release/choose-semverness.js +++ b/private/release/choose-semverness.js @@ -3,6 +3,7 @@ import { createWriteStream, mkdirSync } from 'node:fs' import { spawnSync } from 'node:child_process' +import prompts from 'prompts' import { TARGET_BRANCH } from './config.js' function maxSemverness (a, b) { @@ -18,7 +19,6 @@ function maxSemverness (a, b) { export default async function pickSemverness ( spawnOptions, LAST_RELEASE_COMMIT, - STABLE_BRANCH_MERGE_BASE_RANGE, releaseFileUrl, packagesList, ) { @@ -45,26 +45,7 @@ export default async function pickSemverness ( spawnOptions, ) if (stdout.length === 0) { - // eslint-disable-next-line no-shadow - 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)}: major\n`) - uppySemverness = 'major' - } + console.log(`No commits since last release for ${name}, skipping.`) continue } console.log('\n') @@ -79,7 +60,19 @@ export default async function pickSemverness ( )}.`, ) - const response = { value: 'major' } + const response = await prompts({ + type: 'select', + name: 'value', + message: `What should be the semverness of next ${name} release?`, + choices: [ + { title: 'Pre-release', value: 'prerelease' }, + { title: 'Skip this package', value: '' }, + { title: 'Patch', value: 'patch' }, + { title: 'Minor', value: 'minor' }, + { title: 'Major', value: 'major' }, + ], + initial: 2, + }) if (!response.value) { console.log('Skipping.') diff --git a/private/release/commit-and-open-pr.js b/private/release/commit-and-open-pr.js index ad2613cb4..44943a2ba 100644 --- a/private/release/commit-and-open-pr.js +++ b/private/release/commit-and-open-pr.js @@ -1,25 +1,9 @@ import { spawnSync } from 'node:child_process' import { fileURLToPath } from 'node:url' import prompts from 'prompts' -import { REPO_NAME, REPO_OWNER, TARGET_BRANCH } from './config.js' +import { REPO_OWNER, REPO_NAME } from './config.js' -function runProcessOrThrow (...args) { - const cp = spawnSync(...args) - - if (cp.status) { - console.log(cp.stdout.toString()) - console.error(cp.stderr.toString()) - throw new Error(`Non-zero status: ${cp.status}. ${args}`) - } - - return cp -} - -function getContentFromProcessSync (...args) { - return runProcessOrThrow(...args).stdout.toString().trim() -} - -export default async function commit (spawnOptions, STABLE_HEAD, ...files) { +export default async function commit (spawnOptions, ...files) { console.log(`Now is the time to do manual edits to ${files.join(',')}.`) await prompts({ type: 'toggle', @@ -32,67 +16,14 @@ export default async function commit (spawnOptions, STABLE_HEAD, ...files) { spawnSync('git', ['add', ...files.map(url => fileURLToPath(url))], spawnOptions) spawnSync('git', ['commit', '-n', '-m', 'Prepare next release'], { ...spawnOptions, stdio: 'inherit' }) - - // Reverting to the remote head before starting the merge. We keep the git sha - // in a variable to cherry-pick it later. - const releaseSha = getContentFromProcessSync('git', ['rev-parse', 'HEAD'], spawnOptions) - runProcessOrThrow('git', ['reset', 'HEAD^', '--hard']) - - console.log('Attempting to merge changes from stable branch...') - { - // eslint-disable-next-line no-shadow - const { status, stdout, stderr } = spawnSync( - 'git', - [ - 'merge', - '--no-edit', - '-m', - 'Merge stable branch', - STABLE_HEAD, - ], - spawnOptions, - ) - if (status) { - console.log(stdout.toString()) - console.error(stderr.toString()) - - await prompts({ - type: 'toggle', - name: 'value', - message: 'Fix the conflicts, and stage the files. Ready?', - initial: true, - 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 = getContentFromProcessSync('git', ['rev-parse', 'HEAD'], spawnOptions) - runProcessOrThrow('git', ['cherry-pick', releaseSha], spawnOptions) - const sha = getContentFromProcessSync('git', ['rev-parse', 'HEAD'], 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` - console.log(`Please run \`git push ${remote} ${sha}:refs/heads/release-beta\`.`) + console.log(`Please run \`git push ${remote} ${sha}:refs/heads/release\`.`) console.log(`An automation will kick off and open a release candidate PR on the GitHub repository. Do not merge it manually! Review the PR (you may need to close and - re-open so the CI and test will run on it). If everything looks good, run - \`git push ${mergeSha}:refs/heads/${TARGET_BRANCH}\`, and approve the PR — + re-open so the CI and test will run on it). If everything looks good, approve the PR — this will publish updated packages to npm, then the PR will be merged.`) } diff --git a/private/release/config.js b/private/release/config.js index 92231642a..88ab626e5 100644 --- a/private/release/config.js +++ b/private/release/config.js @@ -1,4 +1,3 @@ export const REPO_OWNER = 'transloadit' export const REPO_NAME = 'uppy' -export const TARGET_BRANCH = '4.x' -export const STABLE_BRANCH = 'main' +export const TARGET_BRANCH = 'main' diff --git a/private/release/getUpToDateRefsFromGitHub.js b/private/release/getUpToDateRefsFromGitHub.js index 059d40168..6a6f94204 100644 --- a/private/release/getUpToDateRefsFromGitHub.js +++ b/private/release/getUpToDateRefsFromGitHub.js @@ -1,6 +1,6 @@ import { spawnSync } from 'node:child_process' import prompts from 'prompts' -import { TARGET_BRANCH, REPO_NAME, REPO_OWNER, STABLE_BRANCH } from './config.js' +import { TARGET_BRANCH, REPO_NAME, REPO_OWNER } from './config.js' async function apiCall (endpoint, errorMessage) { const response = await fetch( @@ -36,15 +36,6 @@ 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() } @@ -111,5 +102,5 @@ export async function validateGitStatus (spawnOptions) { } } - return [await latestRelease, LOCAL_HEAD, ...getStableBranchMergeBase(REMOTE_HEAD)] + return [await latestRelease, LOCAL_HEAD] } diff --git a/private/release/interactive.js b/private/release/interactive.js index 6b1c8be27..c62af916c 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, MERGE_BASE, STABLE_HEAD] = await validateGitStatus(spawnOptions) +const [LAST_RELEASE_COMMIT, LOCAL_HEAD] = await validateGitStatus(spawnOptions) try { console.log('Local git repository is ready, starting release process...') - await pickSemverness(spawnOptions, LAST_RELEASE_COMMIT, MERGE_BASE, deferredReleaseFile, process.env.PACKAGES.split(' ')) + await pickSemverness(spawnOptions, LAST_RELEASE_COMMIT, 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, STABLE_HEAD, deferredReleaseFile, temporaryChangeLog) + await commit(spawnOptions, deferredReleaseFile, temporaryChangeLog) } finally { console.log('Rewinding git history...') await rewindGitHistory(spawnOptions, LOCAL_HEAD)