prepareReleaseMaterials.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. // Prepare release materials like mail, release note
  20. const commander = require('commander');
  21. const fse = require('fs-extra');
  22. const pathTool = require('path');
  23. const https = require('https');
  24. commander
  25. .usage('[options]')
  26. .description([
  27. 'Generate source release'
  28. ].join('\n'))
  29. .option(
  30. '--rcversion <version>',
  31. 'Release version'
  32. )
  33. .option(
  34. '--commit <commit>',
  35. 'Hash of commit'
  36. )
  37. .option(
  38. '--repo <repo>',
  39. 'Repo'
  40. )
  41. .option(
  42. '--out <out>',
  43. 'Out directory. Default to be tmp/release-mail'
  44. )
  45. .parse(process.argv);
  46. const outDir = pathTool.resolve(process.cwd(), commander.out || 'tmp/release-materials');
  47. const releaseCommit = commander.commit;
  48. if (!releaseCommit) {
  49. throw new Error('Release commit is required');
  50. }
  51. const repo = commander.repo || 'apache/echarts';
  52. let rcVersion = commander.rcversion + '';
  53. if (rcVersion.startsWith('v')) { // tag may have v prefix, v5.1.0
  54. rcVersion = rcVersion.substr(1);
  55. }
  56. if (rcVersion.indexOf('-rc.') < 0) {
  57. throw new Error('Only rc version is accepeted.');
  58. }
  59. const parts = /(\d+)\.(\d+)\.(\d+)\-rc\.(\d+)/.exec(rcVersion);
  60. if (!parts) {
  61. throw new Error(`Invalid version number ${rcVersion}`);
  62. }
  63. const major = +parts[1];
  64. const minor = +parts[2];
  65. const patch = +parts[3];
  66. const rc = +parts[4];
  67. const stableVersion = `${major}.${minor}.${patch}`;
  68. const releaseFullName = `Apache ECharts ${stableVersion} (release candidate ${rc})`;
  69. console.log('[Release Repo] ' + repo);
  70. console.log('[Release Verion] ' + rcVersion);
  71. console.log('[Release Commit] ' + releaseCommit);
  72. console.log('[Release Name] ' + releaseFullName);
  73. const voteTpl = fse.readFileSync(pathTool.join(__dirname, './template/vote-release.tpl'), 'utf-8');
  74. const voteResultTpl = fse.readFileSync(pathTool.join(__dirname, './template/vote-result.tpl'), 'utf-8');
  75. const announceTpl = fse.readFileSync(pathTool.join(__dirname, './template/announce-release.tpl'), 'utf-8');
  76. const voteUntil = new Date(+new Date() + (72 + 12) * 3600 * 1000); // 3.5 day.
  77. fse.ensureDirSync(outDir);
  78. fse.writeFileSync(
  79. pathTool.resolve(outDir, 'vote.txt'),
  80. voteTpl.replace(/{{ECHARTS_RELEASE_VERSION}}/g, rcVersion)
  81. .replace(/{{ECHARTS_RELEASE_VERSION_FULL_NAME}}/g, releaseFullName)
  82. .replace(/{{ECHARTS_RELEASE_COMMIT}}/g, releaseCommit)
  83. .replace(/{{VOTE_UNTIL}}/g, voteUntil.toISOString()),
  84. 'utf-8'
  85. );
  86. fse.ensureDirSync(outDir);
  87. fse.writeFileSync(
  88. pathTool.resolve(outDir, 'vote-result.txt'),
  89. voteResultTpl.replace(/{{ECHARTS_RELEASE_VERSION}}/g, rcVersion)
  90. .replace(/{{ECHARTS_RELEASE_VERSION_FULL_NAME}}/g, releaseFullName),
  91. 'utf-8'
  92. );
  93. fse.writeFileSync(
  94. pathTool.resolve(outDir, 'announce.txt'),
  95. announceTpl.replace(/{{ECHARTS_RELEASE_VERSION}}/g, stableVersion)
  96. .replace(/{{ECHARTS_RELEASE_COMMIT}}/g, releaseCommit),
  97. 'utf-8'
  98. );
  99. // Fetch RELEASE_NOTE
  100. https.get({
  101. hostname: 'api.github.com',
  102. path: `/repos/${repo}/releases`,
  103. headers: {
  104. 'User-Agent': 'NodeJS'
  105. }
  106. }, function (res) {
  107. console.log(`https://api.github.com/repos/${repo}/releases`);
  108. if (res.statusCode !== 200) {
  109. console.error(`Failed to fetch releases ${res.statusCode}`);
  110. res.resume();
  111. return;
  112. }
  113. res.setEncoding('utf8');
  114. let rawData = '';
  115. res.on('data', (chunk) => {
  116. rawData += chunk;
  117. });
  118. res.on('end', () => {
  119. let releaseNote = '';
  120. const releases = JSON.parse(rawData);
  121. const found = releases.find(release => release.name === rcVersion);
  122. if (!found) {
  123. throw 'Can\'t found release';
  124. }
  125. else {
  126. releaseNote = found.body.trim();
  127. if (!releaseNote) {
  128. throw 'Release description is empty';
  129. }
  130. }
  131. const firstLine = releaseNote.split('\n')[0];
  132. if (firstLine.indexOf(stableVersion) < 0) {
  133. // Add version if release note is not start with version.
  134. }
  135. releaseNote = `## ${stableVersion}\n\n${releaseNote}`;
  136. fse.writeFileSync(
  137. pathTool.resolve(outDir, 'RELEASE_NOTE.txt'),
  138. releaseNote,
  139. 'utf-8'
  140. );
  141. });
  142. }).on('error', (e) => {
  143. throw e;
  144. });