publish-to-npm.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. const temp = require('temp')
  2. const fs = require('fs')
  3. const path = require('path')
  4. const childProcess = require('child_process')
  5. const { getCurrentBranch } = require('./lib/utils.js')
  6. const request = require('request')
  7. const semver = require('semver')
  8. const rootPackageJson = require('../package.json')
  9. const octokit = require('@octokit/rest')({
  10. headers: { 'User-Agent': 'electron-npm-publisher' }
  11. })
  12. if (!process.env.ELECTRON_NPM_OTP) {
  13. console.error('Please set ELECTRON_NPM_OTP')
  14. process.exit(1)
  15. }
  16. let tempDir
  17. temp.track() // track and cleanup files at exit
  18. const files = [
  19. 'cli.js',
  20. 'index.js',
  21. 'install.js',
  22. 'package.json',
  23. 'README.md',
  24. 'LICENSE'
  25. ]
  26. const jsonFields = [
  27. 'name',
  28. 'version',
  29. 'repository',
  30. 'description',
  31. 'license',
  32. 'author',
  33. 'keywords'
  34. ]
  35. let npmTag = ''
  36. new Promise((resolve, reject) => {
  37. temp.mkdir('electron-npm', (err, dirPath) => {
  38. if (err) {
  39. reject(err)
  40. } else {
  41. resolve(dirPath)
  42. }
  43. })
  44. })
  45. .then((dirPath) => {
  46. tempDir = dirPath
  47. // copy files from `/npm` to temp directory
  48. files.forEach((name) => {
  49. const noThirdSegment = name === 'README.md' || name === 'LICENSE'
  50. fs.writeFileSync(
  51. path.join(tempDir, name),
  52. fs.readFileSync(path.join(__dirname, '..', noThirdSegment ? '' : 'npm', name))
  53. )
  54. })
  55. // copy from root package.json to temp/package.json
  56. const packageJson = require(path.join(tempDir, 'package.json'))
  57. jsonFields.forEach((fieldName) => {
  58. packageJson[fieldName] = rootPackageJson[fieldName]
  59. })
  60. fs.writeFileSync(
  61. path.join(tempDir, 'package.json'),
  62. JSON.stringify(packageJson, null, 2)
  63. )
  64. return octokit.repos.listReleases({
  65. owner: 'electron',
  66. repo: rootPackageJson.version.indexOf('nightly') > 0 ? 'nightlies' : 'electron'
  67. })
  68. })
  69. .then((releases) => {
  70. // download electron.d.ts from release
  71. const release = releases.data.find(
  72. (release) => release.tag_name === `v${rootPackageJson.version}`
  73. )
  74. if (!release) {
  75. throw new Error(`cannot find release with tag v${rootPackageJson.version}`)
  76. }
  77. return release
  78. })
  79. .then((release) => {
  80. const tsdAsset = release.assets.find((asset) => asset.name === 'electron.d.ts')
  81. if (!tsdAsset) {
  82. throw new Error(`cannot find electron.d.ts from v${rootPackageJson.version} release assets`)
  83. }
  84. return new Promise((resolve, reject) => {
  85. request.get({
  86. url: tsdAsset.url,
  87. headers: {
  88. 'accept': 'application/octet-stream',
  89. 'user-agent': 'electron-npm-publisher'
  90. }
  91. }, (err, response, body) => {
  92. if (err || response.statusCode !== 200) {
  93. reject(err || new Error('Cannot download electron.d.ts'))
  94. } else {
  95. fs.writeFileSync(path.join(tempDir, 'electron.d.ts'), body)
  96. resolve(release)
  97. }
  98. })
  99. })
  100. })
  101. .then(async (release) => {
  102. const currentBranch = await getCurrentBranch()
  103. if (release.tag_name.indexOf('nightly') > 0) {
  104. if (currentBranch === 'master') {
  105. // Nightlies get published to their own module, so master nightlies should be tagged as latest
  106. npmTag = 'latest'
  107. } else {
  108. npmTag = `nightly-${currentBranch}`
  109. }
  110. const currentJson = JSON.parse(fs.readFileSync(path.join(tempDir, 'package.json'), 'utf8'))
  111. currentJson.name = 'electron-nightly'
  112. rootPackageJson.name = 'electron-nightly'
  113. fs.writeFileSync(
  114. path.join(tempDir, 'package.json'),
  115. JSON.stringify(currentJson, null, 2)
  116. )
  117. } else {
  118. if (currentBranch === 'master') {
  119. // This should never happen, master releases should be nightly releases
  120. // this is here just-in-case
  121. npmTag = 'master'
  122. } else if (!release.prerelease) {
  123. // Tag the release with a `2-0-x` style tag
  124. npmTag = currentBranch
  125. } else {
  126. // Tag the release with a `beta-3-0-x` style tag
  127. npmTag = `beta-${currentBranch}`
  128. }
  129. }
  130. })
  131. .then(() => childProcess.execSync('npm pack', { cwd: tempDir }))
  132. .then(() => {
  133. // test that the package can install electron prebuilt from github release
  134. const tarballPath = path.join(tempDir, `${rootPackageJson.name}-${rootPackageJson.version}.tgz`)
  135. return new Promise((resolve, reject) => {
  136. childProcess.execSync(`npm install ${tarballPath} --force --silent`, {
  137. env: Object.assign({}, process.env, { electron_config_cache: tempDir }),
  138. cwd: tempDir
  139. })
  140. resolve(tarballPath)
  141. })
  142. })
  143. .then((tarballPath) => childProcess.execSync(`npm publish ${tarballPath} --tag ${npmTag} --otp=${process.env.ELECTRON_NPM_OTP}`))
  144. .then(() => {
  145. const currentTags = JSON.parse(childProcess.execSync('npm show electron dist-tags --json').toString())
  146. const localVersion = rootPackageJson.version
  147. const parsedLocalVersion = semver.parse(localVersion)
  148. if (rootPackageJson.name === 'electron') {
  149. // We should only customly add dist tags for non-nightly releases where the package name is still
  150. // "electron"
  151. if (parsedLocalVersion.prerelease.length === 0 &&
  152. semver.gt(localVersion, currentTags.latest)) {
  153. childProcess.execSync(`npm dist-tag add electron@${localVersion} latest --otp=${process.env.ELECTRON_NPM_OTP}`)
  154. }
  155. if (parsedLocalVersion.prerelease[0] === 'beta' &&
  156. semver.gt(localVersion, currentTags.beta)) {
  157. childProcess.execSync(`npm dist-tag add electron@${localVersion} beta --otp=${process.env.ELECTRON_NPM_OTP}`)
  158. }
  159. }
  160. })
  161. .catch((err) => {
  162. console.error(`Error: ${err}`)
  163. process.exit(1)
  164. })