commit-and-open-pr.js 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import { spawnSync } from 'node:child_process'
  2. import { fileURLToPath } from 'node:url'
  3. import prompts from 'prompts'
  4. import { REPO_NAME, REPO_OWNER, TARGET_BRANCH } from './config.js'
  5. function runProcessOrThrow (...args) {
  6. const cp = spawnSync(...args)
  7. if (cp.status) {
  8. console.log(cp.stdout.toString())
  9. console.error(cp.stderr.toString())
  10. throw new Error(`Non-zero status: ${cp.status}. ${args}`)
  11. }
  12. return cp
  13. }
  14. function getContentFromProcessSync (...args) {
  15. return runProcessOrThrow(...args).stdout.toString().trim()
  16. }
  17. export default async function commit (spawnOptions, STABLE_HEAD, ...files) {
  18. console.log(`Now is the time to do manual edits to ${files.join(',')}.`)
  19. await prompts({
  20. type: 'toggle',
  21. name: 'value',
  22. message: 'Ready to commit?',
  23. initial: true,
  24. active: 'yes',
  25. inactive: 'yes',
  26. })
  27. spawnSync('git', ['add', ...files.map(url => fileURLToPath(url))], spawnOptions)
  28. spawnSync('git', ['commit', '-n', '-m', 'Prepare next release'], { ...spawnOptions, stdio: 'inherit' })
  29. // Reverting to the remote head before starting the merge. We keep the git sha
  30. // in a variable to cherry-pick it later.
  31. const releaseSha = getContentFromProcessSync('git', ['rev-parse', 'HEAD'], spawnOptions)
  32. runProcessOrThrow('git', ['reset', 'HEAD^', '--hard'])
  33. console.log('Attempting to merge changes from stable branch...')
  34. {
  35. // eslint-disable-next-line no-shadow
  36. const { status, stdout, stderr } = spawnSync(
  37. 'git',
  38. [
  39. 'merge',
  40. '--no-edit',
  41. '-m',
  42. 'Merge stable branch',
  43. STABLE_HEAD,
  44. ],
  45. spawnOptions,
  46. )
  47. if (status) {
  48. console.log(stdout.toString())
  49. console.error(stderr.toString())
  50. await prompts({
  51. type: 'toggle',
  52. name: 'value',
  53. message: 'Fix the conflicts, and stage the files. Ready?',
  54. initial: true,
  55. active: 'yes',
  56. inactive: 'yes',
  57. })
  58. // eslint-disable-next-line no-shadow
  59. const { status } = spawnSync(
  60. 'git',
  61. [
  62. 'merge',
  63. '--continue',
  64. ],
  65. { ...spawnOptions, stdio: 'inherit' },
  66. )
  67. if (status) {
  68. throw new Error('Merge has failed')
  69. }
  70. }
  71. }
  72. const mergeSha = getContentFromProcessSync('git', ['rev-parse', 'HEAD'], spawnOptions)
  73. runProcessOrThrow('git', ['cherry-pick', releaseSha], spawnOptions)
  74. const sha = getContentFromProcessSync('git', ['rev-parse', 'HEAD'], spawnOptions)
  75. const getRemoteCommamnd = `git remote -v | grep '${REPO_OWNER}/${REPO_NAME}' | awk '($3 == "(push)") { print $1; exit }'`
  76. const remote = spawnSync('/bin/sh', ['-c', getRemoteCommamnd]).stdout.toString().trim()
  77. || `git@github.com:${REPO_OWNER}/${REPO_NAME}.git`
  78. console.log(`Please run \`git push ${remote} ${sha}:refs/heads/release-beta\`.`)
  79. console.log(`An automation will kick off and open a release candidate PR
  80. on the GitHub repository. Do not merge it manually! Review the PR (you may need to close and
  81. re-open so the CI and test will run on it). If everything looks good, run
  82. \`git push ${mergeSha}:refs/heads/${TARGET_BRANCH}\`, and approve the PR —
  83. this will publish updated packages to npm, then the PR will be merged.`)
  84. }