publish-to-npm.js 5.4 KB

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