1/**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @format
8 */
9
10'use strict';
11
12const {exec, echo, exit, test, env, pushd, popd} = require('shelljs');
13const {saveFiles} = require('./scm-utils');
14const {createHermesPrebuiltArtifactsTarball} = require('./hermes/hermes-utils');
15
16// TODO: we should probably remove this because of this? https://github.com/facebook/react-native/pull/34846
17function saveFilesToRestore(tmpPublishingFolder) {
18  const filesToSaveAndRestore = [
19    'template/Gemfile',
20    'template/_ruby-version',
21    'template/package.json',
22    '.ruby-version',
23    'Gemfile.lock',
24    'Gemfile',
25    'package.json',
26    'ReactAndroid/gradle.properties',
27    'Libraries/Core/ReactNativeVersion.js',
28    'React/Base/RCTVersion.m',
29    'ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.java',
30    'ReactCommon/cxxreact/ReactNativeVersion.h',
31  ];
32
33  saveFiles(filesToSaveAndRestore, tmpPublishingFolder);
34}
35
36function generateAndroidArtifacts(releaseVersion, tmpPublishingFolder) {
37  // -------- Generating Android Artifacts
38  echo('Generating Android artifacts inside /tmp/maven-local');
39  if (exec('./gradlew publishAllToMavenTempLocal').code) {
40    echo('Could not generate artifacts');
41    exit(1);
42  }
43
44  echo('Generated artifacts for Maven');
45
46  let artifacts = [
47    '.module',
48    '.pom',
49    '-debug.aar',
50    '-release.aar',
51    '-debug-sources.jar',
52    '-release-sources.jar',
53  ].map(suffix => {
54    return `react-android-${releaseVersion}${suffix}`;
55  });
56
57  artifacts.forEach(name => {
58    if (
59      !test(
60        '-e',
61        `/tmp/maven-local/com/facebook/react/react-android/${releaseVersion}/${name}`,
62      )
63    ) {
64      echo(
65        `Failing as expected file: \n\
66      /tmp/maven-local/com/facebook/react/react-android/${releaseVersion}/${name}\n\
67      was not correctly generated.`,
68      );
69      exit(1);
70    }
71  });
72}
73
74function publishAndroidArtifactsToMaven(releaseVersion, isNightly) {
75  // -------- Publish every artifact to Maven Central
76  // The GPG key is base64 encoded on CircleCI and then decoded here
77  let buff = Buffer.from(env.ORG_GRADLE_PROJECT_SIGNING_KEY_ENCODED, 'base64');
78  env.ORG_GRADLE_PROJECT_SIGNING_KEY = buff.toString('ascii');
79
80  // We want to gate ourselves against accidentally publishing a 1.x or a 1000.x on
81  // maven central which will break the semver for our artifacts.
82  if (!isNightly && releaseVersion.startsWith('0.')) {
83    // -------- For stable releases, we also need to close and release the staging repository.
84    if (
85      exec(
86        './gradlew publishAllToSonatype closeAndReleaseSonatypeStagingRepository -PisNightly=' +
87          isNightly,
88      ).code
89    ) {
90      echo(
91        'Failed to close and release the staging repository on Sonatype (Maven Central)',
92      );
93      exit(1);
94    }
95  } else {
96    // -------- For nightly releases, we only need to publish the snapshot to Sonatype snapshot repo.
97    if (exec('./gradlew publishAllToSonatype -PisNightly=' + isNightly).code) {
98      echo('Failed to publish artifacts to Sonatype (Maven Central)');
99      exit(1);
100    }
101  }
102
103  echo('Published artifacts to Maven Central');
104}
105
106function generateiOSArtifacts(
107  jsiFolder,
108  hermesCoreSourceFolder,
109  buildType,
110  targetFolder,
111) {
112  pushd(`${hermesCoreSourceFolder}`);
113
114  //Need to generate hermesc
115  exec(
116    `${hermesCoreSourceFolder}/utils/build-hermesc-xcode.sh ${hermesCoreSourceFolder}/build_host_hermesc`,
117  );
118
119  //Generating iOS Artifacts
120  exec(
121    `JSI_PATH=${jsiFolder} BUILD_TYPE=${buildType} ${hermesCoreSourceFolder}/utils/build-mac-framework.sh`,
122  );
123
124  exec(
125    `JSI_PATH=${jsiFolder} BUILD_TYPE=${buildType} ${hermesCoreSourceFolder}/utils/build-ios-framework.sh`,
126  );
127
128  popd();
129
130  const tarballOutputPath = createHermesPrebuiltArtifactsTarball(
131    hermesCoreSourceFolder,
132    buildType,
133    targetFolder,
134    true, // this is excludeDebugSymbols, we keep it as the default
135  );
136
137  return tarballOutputPath;
138}
139
140function failIfTagExists(version, buildType) {
141  // When dry-run in stable branch, the tag already exists.
142  // We are bypassing the tag-existence check when in a dry-run to have the CI pass
143  if (buildType === 'dry-run') {
144    return;
145  }
146
147  if (checkIfTagExists(version)) {
148    echo(`Tag v${version} already exists.`);
149    echo('You may want to rollback the last commit');
150    echo('git reset --hard HEAD~1');
151    exit(1);
152  }
153}
154
155function checkIfTagExists(version) {
156  const {code, stdout} = exec('git tag -l', {silent: true});
157  if (code !== 0) {
158    throw new Error('Failed to retrieve the list of tags');
159  }
160  const tags = new Set(stdout.split('\n'));
161  return tags.has(`v${version}`);
162}
163
164module.exports = {
165  generateAndroidArtifacts,
166  generateiOSArtifacts,
167  publishAndroidArtifactsToMaven,
168  saveFilesToRestore,
169  failIfTagExists,
170};
171