release-artifact-cleanup.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. #!/usr/bin/env node
  2. if (!process.env.CI) require('dotenv-safe').load()
  3. require('colors')
  4. const pass = '\u2713'.green
  5. const fail = '\u2717'.red
  6. const args = require('minimist')(process.argv.slice(2), {
  7. string: ['tag', 'releaseID'],
  8. default: { releaseID: '' }
  9. })
  10. const { execSync } = require('child_process')
  11. const { GitProcess } = require('dugite')
  12. const GitHub = require('github')
  13. const path = require('path')
  14. const github = new GitHub()
  15. const gitDir = path.resolve(__dirname, '..')
  16. github.authenticate({
  17. type: 'token',
  18. token: process.env.ELECTRON_GITHUB_TOKEN
  19. })
  20. function getLastBumpCommit (tag) {
  21. const data = execSync(`git log -n1 --grep "Bump ${tag}" --format='format:{"hash": "%H", "message": "%s"}'`).toString()
  22. return JSON.parse(data)
  23. }
  24. async function getCurrentBranch (gitDir) {
  25. const gitArgs = ['rev-parse', '--abbrev-ref', 'HEAD']
  26. const branchDetails = await GitProcess.exec(gitArgs, gitDir)
  27. if (branchDetails.exitCode === 0) {
  28. return branchDetails.stdout.trim()
  29. }
  30. const error = GitProcess.parseError(branchDetails.stderr)
  31. console.error(`${fail} couldn't get current branch: `, error)
  32. process.exit(1)
  33. }
  34. async function revertBumpCommit (tag) {
  35. const branch = await getCurrentBranch()
  36. const commitToRevert = getLastBumpCommit(tag).hash
  37. await GitProcess.exec(['revert', commitToRevert], gitDir)
  38. const pushDetails = await GitProcess.exec(['push', 'origin', `HEAD:${branch}`, '--follow-tags'], gitDir)
  39. if (pushDetails.exitCode === 0) {
  40. console.log(`${pass} successfully reverted release commit.`)
  41. } else {
  42. const error = GitProcess.parseError(pushDetails.stderr)
  43. console.error(`${fail} could not push release commit: `, error)
  44. process.exit(1)
  45. }
  46. }
  47. async function deleteDraft (releaseId, targetRepo) {
  48. try {
  49. const result = await github.repos.getRelease({
  50. owner: 'electron',
  51. repo: targetRepo,
  52. id: parseInt(releaseId, 10)
  53. })
  54. console.log(result)
  55. if (!result.data.draft) {
  56. console.log(`${fail} published releases cannot be deleted.`)
  57. return false
  58. } else {
  59. await github.repos.deleteRelease({
  60. owner: 'electron',
  61. repo: targetRepo,
  62. release_id: result.data.id
  63. })
  64. }
  65. console.log(`${pass} successfully deleted draft with id ${releaseId} from ${targetRepo}`)
  66. return true
  67. } catch (err) {
  68. console.error(`${fail} couldn't delete draft with id ${releaseId} from ${targetRepo}: `, err)
  69. return false
  70. }
  71. }
  72. async function deleteTag (tag, targetRepo) {
  73. try {
  74. await github.gitdata.deleteReference({
  75. owner: 'electron',
  76. repo: targetRepo,
  77. ref: `tags/${tag}`
  78. })
  79. console.log(`${pass} successfully deleted tag ${tag} from ${targetRepo}`)
  80. } catch (err) {
  81. console.log(`${fail} couldn't delete tag ${tag} from ${targetRepo}: `, err)
  82. }
  83. }
  84. async function cleanReleaseArtifacts () {
  85. const releaseId = args.releaseID.length > 0 ? args.releaseID : null
  86. const isNightly = args.tag.includes('nightly')
  87. // try to revert commit regardless of tag and draft deletion status
  88. await revertBumpCommit(args.tag)
  89. if (releaseId) {
  90. if (isNightly) {
  91. const deletedNightlyDraft = await deleteDraft(releaseId, 'nightlies')
  92. // don't delete tag unless draft deleted successfully
  93. if (deletedNightlyDraft) {
  94. await Promise.all([
  95. deleteTag(args.tag, 'electron'),
  96. deleteTag(args.tag, 'nightlies')
  97. ])
  98. }
  99. } else {
  100. const deletedElectronDraft = await deleteDraft(releaseId, 'electron')
  101. // don't delete tag unless draft deleted successfully
  102. if (deletedElectronDraft) {
  103. await deleteTag(args.tag, 'electron')
  104. }
  105. }
  106. } else {
  107. await Promise.all([
  108. deleteTag(args.tag, 'electron'),
  109. deleteTag(args.tag, 'nightlies')
  110. ])
  111. }
  112. console.log(`${pass} failed release artifact cleanup complete`)
  113. }
  114. cleanReleaseArtifacts()