publish-to-npm.js 5.6 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, ELECTRON_DIR } = require('../lib/utils');
  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(ELECTRON_DIR, 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. });