1#!/usr/bin/env node 2/** 3 * Copyright (c) Meta Platforms, Inc. and affiliates. 4 * 5 * This source code is licensed under the MIT license found in the 6 * LICENSE file in the root directory of this source tree. 7 * 8 * @format 9 */ 10 11'use strict'; 12 13/** 14 * This script walks a releaser through bumping the version for a release 15 * It will commit the appropriate tags to trigger the CircleCI jobs. 16 */ 17const {exit} = require('shelljs'); 18const yargs = require('yargs'); 19const inquirer = require('inquirer'); 20const request = require('request'); 21 22const { 23 parseVersion, 24 isReleaseBranch, 25 getBranchName, 26} = require('./version-utils'); 27 28let argv = yargs 29 .option('r', { 30 alias: 'remote', 31 default: 'origin', 32 }) 33 .option('t', { 34 alias: 'token', 35 describe: 36 'Your CircleCI personal API token. See https://circleci.com/docs/2.0/managing-api-tokens/#creating-a-personal-api-token to set one', 37 required: true, 38 }) 39 .option('v', { 40 alias: 'to-version', 41 describe: 'Version you aim to release, ex. 0.67.0-rc.1, 0.66.3', 42 required: true, 43 }) 44 .check(() => { 45 const branch = getBranchName(); 46 exitIfNotOnReleaseBranch(branch); 47 return true; 48 }).argv; 49 50function exitIfNotOnReleaseBranch(branch) { 51 if (!isReleaseBranch(branch)) { 52 console.log( 53 'This script must be run in a react-native git repository checkout and on a release branch', 54 ); 55 exit(1); 56 } 57} 58 59function triggerReleaseWorkflow(options) { 60 return new Promise((resolve, reject) => { 61 request(options, function (error, response, body) { 62 if (error) { 63 reject(error); 64 } else { 65 resolve(body); 66 } 67 }); 68 }); 69} 70 71async function main() { 72 const branch = getBranchName(); 73 const token = argv.token; 74 const releaseVersion = argv.toVersion; 75 76 const {pushed} = await inquirer.prompt({ 77 type: 'confirm', 78 name: 'pushed', 79 message: `This script will trigger a release with whatever changes are on the remote branch: ${branch}. \nMake sure you have pushed any updates remotely.`, 80 }); 81 82 if (!pushed) { 83 console.log(`Please run 'git push ${argv.remote} ${branch}'`); 84 exit(1); 85 return; 86 } 87 88 let latest = false; 89 const {version, prerelease} = parseVersion(releaseVersion); 90 if (!prerelease) { 91 const {setLatest} = await inquirer.prompt({ 92 type: 'confirm', 93 name: 'setLatest', 94 message: `Do you want to set ${version} as "latest" release on npm?`, 95 }); 96 latest = setLatest; 97 } 98 99 const npmTag = latest ? 'latest' : !prerelease ? branch : 'next'; 100 const {confirmRelease} = await inquirer.prompt({ 101 type: 'confirm', 102 name: 'confirmRelease', 103 message: `Releasing version "${version}" with npm tag "${npmTag}". Is this correct?`, 104 }); 105 106 if (!confirmRelease) { 107 console.log('Aborting.'); 108 return; 109 } 110 111 const parameters = { 112 release_version: version, 113 release_latest: latest, 114 run_package_release_workflow_only: true, 115 }; 116 117 const options = { 118 method: 'POST', 119 url: 'https://circleci.com/api/v2/project/github/facebook/react-native/pipeline', 120 headers: { 121 'Circle-Token': token, 122 'content-type': 'application/json', 123 }, 124 body: { 125 branch, 126 parameters, 127 }, 128 json: true, 129 }; 130 131 // See response: https://circleci.com/docs/api/v2/#operation/triggerPipeline 132 const body = await triggerReleaseWorkflow(options); 133 console.log( 134 `Monitor your release workflow: https://app.circleci.com/pipelines/github/facebook/react-native/${body.number}`, 135 ); 136 137 // TODO 138 // - Output the release changelog to paste into Github releases 139 // - Link to release discussions to update 140 // - Verify RN-diff publish is through 141} 142 143main().then(() => { 144 exit(0); 145}); 146