diff --git a/.github/actions/javascript/authorChecklist/index.js b/.github/actions/javascript/authorChecklist/index.js index 337fe7398fb3..1dace19d0a01 100644 --- a/.github/actions/javascript/authorChecklist/index.js +++ b/.github/actions/javascript/authorChecklist/index.js @@ -17073,13 +17073,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -17099,6 +17097,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -17454,12 +17461,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; diff --git a/.github/actions/javascript/awaitStagingDeploys/index.js b/.github/actions/javascript/awaitStagingDeploys/index.js index 0e0168fdb7ae..c5ba4d9ca936 100644 --- a/.github/actions/javascript/awaitStagingDeploys/index.js +++ b/.github/actions/javascript/awaitStagingDeploys/index.js @@ -12314,13 +12314,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -12340,6 +12338,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -12695,12 +12702,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; diff --git a/.github/actions/javascript/checkDeployBlockers/index.js b/.github/actions/javascript/checkDeployBlockers/index.js index 842deb1cbb5d..0817a8130adc 100644 --- a/.github/actions/javascript/checkDeployBlockers/index.js +++ b/.github/actions/javascript/checkDeployBlockers/index.js @@ -11597,13 +11597,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -11623,6 +11621,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -11978,12 +11985,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; diff --git a/.github/actions/javascript/createOrUpdateStagingDeploy/index.js b/.github/actions/javascript/createOrUpdateStagingDeploy/index.js index 127fb1fe3dca..12b3165c1ead 100644 --- a/.github/actions/javascript/createOrUpdateStagingDeploy/index.js +++ b/.github/actions/javascript/createOrUpdateStagingDeploy/index.js @@ -14567,13 +14567,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -14593,6 +14591,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -14948,12 +14955,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; diff --git a/.github/actions/javascript/getArtifactInfo/index.js b/.github/actions/javascript/getArtifactInfo/index.js index 77f61f491fec..9a7a0ae62e53 100644 --- a/.github/actions/javascript/getArtifactInfo/index.js +++ b/.github/actions/javascript/getArtifactInfo/index.js @@ -11558,13 +11558,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -11584,6 +11582,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -11939,12 +11946,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; diff --git a/.github/actions/javascript/getDeployPullRequestList/index.js b/.github/actions/javascript/getDeployPullRequestList/index.js index 8f9f9deea896..f63cd2a14f5b 100644 --- a/.github/actions/javascript/getDeployPullRequestList/index.js +++ b/.github/actions/javascript/getDeployPullRequestList/index.js @@ -11831,13 +11831,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -11857,6 +11855,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -12212,12 +12219,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; diff --git a/.github/actions/javascript/getPullRequestDetails/index.js b/.github/actions/javascript/getPullRequestDetails/index.js index 14814367e3cd..7cb768941711 100644 --- a/.github/actions/javascript/getPullRequestDetails/index.js +++ b/.github/actions/javascript/getPullRequestDetails/index.js @@ -11660,13 +11660,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -11686,6 +11684,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -12041,12 +12048,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; diff --git a/.github/actions/javascript/getReleaseBody/index.js b/.github/actions/javascript/getReleaseBody/index.js index 6c746e26a4a4..f6ba78030927 100644 --- a/.github/actions/javascript/getReleaseBody/index.js +++ b/.github/actions/javascript/getReleaseBody/index.js @@ -11604,13 +11604,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -11630,6 +11628,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -11985,12 +11992,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; diff --git a/.github/actions/javascript/isStagingDeployLocked/index.js b/.github/actions/javascript/isStagingDeployLocked/index.js index f71b89dc051c..29c010f086c3 100644 --- a/.github/actions/javascript/isStagingDeployLocked/index.js +++ b/.github/actions/javascript/isStagingDeployLocked/index.js @@ -11558,13 +11558,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -11584,6 +11582,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -11939,12 +11946,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; diff --git a/.github/actions/javascript/markPullRequestsAsDeployed/index.js b/.github/actions/javascript/markPullRequestsAsDeployed/index.js index 804d3ea610f3..1256b6425640 100644 --- a/.github/actions/javascript/markPullRequestsAsDeployed/index.js +++ b/.github/actions/javascript/markPullRequestsAsDeployed/index.js @@ -11755,13 +11755,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -11781,6 +11779,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -12136,12 +12143,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; diff --git a/.github/actions/javascript/postTestBuildComment/index.js b/.github/actions/javascript/postTestBuildComment/index.js index 0b8eb29f1750..fef09bc25c56 100644 --- a/.github/actions/javascript/postTestBuildComment/index.js +++ b/.github/actions/javascript/postTestBuildComment/index.js @@ -11657,13 +11657,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -11683,6 +11681,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -12038,12 +12045,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; diff --git a/.github/actions/javascript/reopenIssueWithComment/index.js b/.github/actions/javascript/reopenIssueWithComment/index.js index d4341ce37dc4..b211f301eb67 100644 --- a/.github/actions/javascript/reopenIssueWithComment/index.js +++ b/.github/actions/javascript/reopenIssueWithComment/index.js @@ -11568,13 +11568,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -11594,6 +11592,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -11949,12 +11956,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; diff --git a/.github/actions/javascript/reviewerChecklist/index.js b/.github/actions/javascript/reviewerChecklist/index.js index cc1c0b5a581b..b53863ef0c26 100644 --- a/.github/actions/javascript/reviewerChecklist/index.js +++ b/.github/actions/javascript/reviewerChecklist/index.js @@ -11660,13 +11660,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -11686,6 +11684,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -12041,12 +12048,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; diff --git a/.github/actions/javascript/verifySignedCommits/index.js b/.github/actions/javascript/verifySignedCommits/index.js index aea35331b1d0..e3507f897933 100644 --- a/.github/actions/javascript/verifySignedCommits/index.js +++ b/.github/actions/javascript/verifySignedCommits/index.js @@ -11600,13 +11600,11 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); class GithubUtils { static internalOctokit; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token) { const Octokit = utils_1.GitHub.plugin(plugin_throttling_1.throttling, plugin_paginate_rest_1.paginateRest); - const token = core.getInput('GITHUB_TOKEN', { required: true }); // Save a copy of octokit used in this class this.internalOctokit = new Octokit((0, utils_1.getOctokitOptions)(token, { throttle: { @@ -11626,6 +11624,15 @@ class GithubUtils { }, })); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', { required: true }); + this.initOctokitWithToken(token); + } /** * Either give an existing instance of Octokit rest or create a new one * @@ -11981,12 +11988,31 @@ class GithubUtils { .then((events) => events.filter((event) => event.event === 'closed')) .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName) { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName) { + return this.octokit.actions + .listArtifactsForRepo({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - per_page: 100, - }).then((artifacts) => artifacts.find((artifact) => artifact.name === artefactName)); + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId) { + return this.octokit.actions + .downloadArtifact({ + owner: CONST_1.default.GITHUB_OWNER, + repo: CONST_1.default.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } exports["default"] = GithubUtils; diff --git a/.github/libs/GithubUtils.ts b/.github/libs/GithubUtils.ts index f445fc368559..73553cb46bff 100644 --- a/.github/libs/GithubUtils.ts +++ b/.github/libs/GithubUtils.ts @@ -65,13 +65,11 @@ class GithubUtils { static internalOctokit: InternalOctokit | undefined; /** - * Initialize internal octokit - * - * @private + * Initialize internal octokit. + * NOTE: When using GithubUtils in CI, you don't need to call this manually. */ - static initOctokit() { + static initOctokitWithToken(token: string) { const Octokit = GitHub.plugin(throttling, paginateRest); - const token = core.getInput('GITHUB_TOKEN', {required: true}); // Save a copy of octokit used in this class this.internalOctokit = new Octokit( @@ -96,6 +94,16 @@ class GithubUtils { ); } + /** + * Default initialize method assuming running in CI, getting the token from an input. + * + * @private + */ + static initOctokit() { + const token = core.getInput('GITHUB_TOKEN', {required: true}); + this.initOctokitWithToken(token); + } + /** * Either give an existing instance of Octokit rest or create a new one * @@ -521,12 +529,32 @@ class GithubUtils { .then((closedEvents) => closedEvents.at(-1)?.actor?.login ?? ''); } - static getArtifactByName(artefactName: string): Promise { - return this.paginate(this.octokit.actions.listArtifactsForRepo, { - owner: CONST.GITHUB_OWNER, - repo: CONST.APP_REPO, - per_page: 100, - }).then((artifacts: OctokitArtifact[]) => artifacts.find((artifact) => artifact.name === artefactName)); + /** + * Returns a single artifact by name. If none is found, it returns undefined. + */ + static getArtifactByName(artifactName: string): Promise { + return this.octokit.actions + .listArtifactsForRepo({ + owner: CONST.GITHUB_OWNER, + repo: CONST.APP_REPO, + per_page: 1, + name: artifactName, + }) + .then((response) => response.data.artifacts[0]); + } + + /** + * Given an artifact ID, returns the download URL to a zip file containing the artifact. + */ + static getArtifactDownloadURL(artifactId: number): Promise { + return this.octokit.actions + .downloadArtifact({ + owner: CONST.GITHUB_OWNER, + repo: CONST.APP_REPO, + artifact_id: artifactId, + archive_format: 'zip', + }) + .then((response) => response.url); } } diff --git a/.gitignore b/.gitignore index dcbec8a96e46..aa6aad4cc429 100644 --- a/.gitignore +++ b/.gitignore @@ -130,3 +130,6 @@ config/webpack/*.pem .expo dist/ web-build/ + +# Storage location for downloaded app source maps (see scripts/symbolicate-profile.ts) +.sourcemaps/ diff --git a/package-lock.json b/package-lock.json index 0c7c6d2a11ce..68697dae2cb0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -242,6 +242,7 @@ "time-analytics-webpack-plugin": "^0.1.17", "ts-jest": "^29.1.2", "ts-node": "^10.9.2", + "tsconfig-paths": "^4.2.0", "type-fest": "^4.10.2", "typescript": "^5.4.5", "wait-port": "^0.2.9", @@ -11104,29 +11105,6 @@ "node": ">=14.14" } }, - "node_modules/@storybook/preset-react-webpack/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@storybook/preset-react-webpack/node_modules/tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", - "dev": true, - "dependencies": { - "json5": "^2.2.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/@storybook/preview": { "version": "8.0.6", "resolved": "https://registry.npmjs.org/@storybook/preview/-/preview-8.0.6.tgz", @@ -12475,8 +12453,9 @@ }, "node_modules/@types/json5": { "version": "0.0.29", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true }, "node_modules/@types/keyv": { "version": "3.1.4", @@ -20017,6 +19996,18 @@ "node": ">=0.10.0" } }, + "node_modules/eslint-plugin-import/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, "node_modules/eslint-plugin-import/node_modules/semver": { "version": "6.3.1", "dev": true, @@ -20025,6 +20016,27 @@ "semver": "bin/semver.js" } }, + "node_modules/eslint-plugin-import/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, "node_modules/eslint-plugin-jest": { "version": "24.7.0", "dev": true, @@ -36386,25 +36398,17 @@ "license": "Apache-2.0" }, "node_modules/tsconfig-paths": { - "version": "3.15.0", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", "dev": true, - "license": "MIT", "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", + "json5": "^2.2.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.0" }, - "bin": { - "json5": "lib/cli.js" + "engines": { + "node": ">=6" } }, "node_modules/tsconfig-paths/node_modules/strip-bom": { diff --git a/package.json b/package.json index 313d9c169a61..c2223839384a 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "symbolicate:ios": "npx metro-symbolicate main.jsbundle.map", "symbolicate-release:ios": "scripts/release-profile.ts --platform=ios", "symbolicate-release:android": "scripts/release-profile.ts --platform=android", + "symbolicate-profile": "scripts/symbolicate-profile.ts", "test:e2e": "ts-node tests/e2e/testRunner.ts --config ./config.local.ts", "test:e2e:dev": "ts-node tests/e2e/testRunner.ts --config ./config.dev.ts", "gh-actions-unused-styles": "./.github/scripts/findUnusedKeys.sh", @@ -294,6 +295,7 @@ "time-analytics-webpack-plugin": "^0.1.17", "ts-jest": "^29.1.2", "ts-node": "^10.9.2", + "tsconfig-paths": "^4.2.0", "type-fest": "^4.10.2", "typescript": "^5.4.5", "wait-port": "^0.2.9", diff --git a/scripts/.eslintrc.js b/scripts/.eslintrc.js new file mode 100644 index 000000000000..d6d39822b737 --- /dev/null +++ b/scripts/.eslintrc.js @@ -0,0 +1,10 @@ +module.exports = { + rules: { + // For all these Node.js scripts, we do not want to disable `console` statements + 'no-console': 'off', + + '@lwc/lwc/no-async-await': 'off', + 'no-await-in-loop': 'off', + 'no-restricted-syntax': ['error', 'ForInStatement', 'LabeledStatement', 'WithStatement'], + }, +}; diff --git a/scripts/release-profile.ts b/scripts/release-profile.ts index 8ec0979f9f9e..cfc7e2cb8838 100755 --- a/scripts/release-profile.ts +++ b/scripts/release-profile.ts @@ -3,21 +3,7 @@ /* eslint-disable no-console */ import {execSync} from 'child_process'; import fs from 'fs'; - -type ArgsMap = Record; - -// Function to parse command-line arguments into a key-value object -function parseCommandLineArguments(): ArgsMap { - const args = process.argv.slice(2); // Skip node and script paths - const argsMap: ArgsMap = {}; - args.forEach((arg) => { - const [key, value] = arg.split('='); - if (key.startsWith('--')) { - argsMap[key.substring(2)] = value; - } - }); - return argsMap; -} +import parseCommandLineArguments from './utils/parseCommandLineArguments'; // Function to find .cpuprofile files in the current directory function findCpuProfileFiles() { diff --git a/scripts/symbolicate-profile.ts b/scripts/symbolicate-profile.ts new file mode 100755 index 000000000000..a100c05029dd --- /dev/null +++ b/scripts/symbolicate-profile.ts @@ -0,0 +1,174 @@ +#!/usr/bin/env ts-node + +/* eslint-disable @typescript-eslint/naming-convention */ + +/** + * This script helps to symbolicate a .cpuprofile file that was obtained from a specific (staging) app version (usually provided by a user using the app). + * + * @abstract + * + * 1. When creating a new deployment in our github actions, we upload the source map for android and iOS as artifacts. + * 2. The profiles created by the app on the user's device have the app version encoded in the filename. + * 3. This script takes in a .cpuprofile file, reads the app version from the filename, and downloads the corresponding source map from the artifacts using github's API. + * 4. It then uses the source map to symbolicate the .cpuprofile file using the `react-native-release-profiler` cli. + * + * @note For downloading an artifact a github token is required. + */ +import {execSync} from 'child_process'; +import fs from 'fs'; +import https from 'https'; +import path from 'path'; +import GithubUtils from '@github/libs/GithubUtils'; +import * as Logger from './utils/Logger'; +import parseCommandLineArguments from './utils/parseCommandLineArguments'; + +const argsMap = parseCommandLineArguments(); + +/* ============== INPUT VALIDATION ============== */ + +if (Object.keys(argsMap).length === 0 || argsMap.help !== undefined) { + Logger.log('Symbolicates a .cpuprofile file obtained from a specific app version by downloading the source map from the github action runs.'); + Logger.log('Usage: npm run symbolicate-profile -- --profile= --platform='); + Logger.log('Options:'); + Logger.log(' --profile= The .cpuprofile file to symbolicate'); + Logger.log(' --platform= The platform for which the source map was uploaded'); + Logger.log(' --gh-token Token to use for requests send to the GitHub API. By default tries to pick up from the environment variable GITHUB_TOKEN'); + Logger.log(' --help Display this help message'); + process.exit(0); +} + +if (argsMap.profile === undefined) { + Logger.error('Please specify the .cpuprofile file to symbolicate using --profile='); + process.exit(1); +} +if (!fs.existsSync(argsMap.profile)) { + Logger.error(`File ${argsMap.profile} does not exist.`); + process.exit(1); +} + +if (argsMap.platform === undefined) { + Logger.error('Please specify the platform using --platform=ios or --platform=android'); + process.exit(1); +} + +const githubToken = argsMap.ghToken ?? process.env.GITHUB_TOKEN; +if (githubToken === undefined) { + Logger.error('No GitHub token provided. Either set a GITHUB_TOKEN environment variable or pass it using --gh-token'); + process.exit(1); +} + +GithubUtils.initOctokitWithToken(githubToken); + +/* ============= EXTRACT APP VERSION ============= */ + +// Formatted as "Profile_trace_for_1.4.81-9.cpuprofile" +const appVersionRegex = /\d+\.\d+\.\d+(-\d+)?/; +const appVersion = argsMap.profile.match(appVersionRegex)?.[0]; +if (appVersion === undefined) { + Logger.error('Could not extract the app version from the profile filename.'); + process.exit(1); +} +Logger.info(`Found app version ${appVersion} in the profile filename`); + +/* ============== UTILITY FUNCTIONS ============== */ + +async function getWorkflowRunArtifact() { + const artifactName = `${argsMap.platform}-sourcemap-${appVersion}`; + Logger.info(`Fetching sourcemap artifact with name "${artifactName}"`); + const artifact = await GithubUtils.getArtifactByName(artifactName); + if (artifact === undefined) { + throw new Error(`Could not find the artifact ${artifactName}! Are you sure the deploy step succeeded?`); + } + return artifact.id; +} + +const sourcemapDir = path.resolve(__dirname, '../.sourcemaps'); + +function downloadFile(url: string) { + Logger.log(`Downloading file from URL: ${url}`); + if (!fs.existsSync(sourcemapDir)) { + Logger.info(`Creating download directory ${sourcemapDir}`); + fs.mkdirSync(sourcemapDir); + } + + const destination = path.join(sourcemapDir, `${argsMap.platform}-sourcemap-${appVersion}.zip`); + const file = fs.createWriteStream(destination); + return new Promise((resolve, reject) => { + https + .get(url, (response) => { + response.pipe(file); + file.on('finish', () => { + file.close(); + Logger.success(`Downloaded file to ${destination}`); + resolve(destination); + }); + }) + .on('error', (error) => { + fs.unlink(destination, () => { + reject(error); + }); + }); + }); +} + +function unpackZipFile(zipPath: string) { + Logger.info(`Unpacking file ${zipPath}`); + const command = `unzip -o ${zipPath} -d ${sourcemapDir}`; + execSync(command, {stdio: 'inherit'}); + Logger.info(`Deleting zip file ${zipPath}`); + return new Promise((resolve, reject) => { + fs.unlink(zipPath, (error) => (error ? reject(error) : resolve())); + }); +} + +const localSourceMapPath = path.join(sourcemapDir, `${appVersion}-${argsMap.platform}.map`); +function renameDownloadedSourcemapFile() { + const androidName = 'index.android.bundle.map'; + const iosName = 'main.jsbundle.map'; + const downloadSourcemapPath = path.join(sourcemapDir, argsMap.platform === 'ios' ? iosName : androidName); + + if (!fs.existsSync(downloadSourcemapPath)) { + Logger.error(`Could not find the sourcemap file ${downloadSourcemapPath}`); + process.exit(1); + } + + Logger.info(`Renaming sourcemap file to ${localSourceMapPath}`); + fs.renameSync(downloadSourcemapPath, localSourceMapPath); +} + +// Symbolicate using the downloaded source map +function symbolicateProfile() { + const command = `npx react-native-release-profiler --local ${argsMap.profile} --sourcemap-path ${localSourceMapPath}`; + execSync(command, {stdio: 'inherit'}); +} + +async function fetchAndProcessArtifact() { + const artifactId = await getWorkflowRunArtifact(); + const downloadUrl = await GithubUtils.getArtifactDownloadURL(artifactId); + const zipPath = await downloadFile(downloadUrl); + await unpackZipFile(zipPath); + renameDownloadedSourcemapFile(); +} + +/* ============== MAIN SCRIPT ============== */ + +async function runAsyncScript() { + // Step: check if source map locally already exists (if so we can skip the download) + if (fs.existsSync(localSourceMapPath)) { + Logger.success(`Found local source map at ${localSourceMapPath}`); + Logger.info('Skipping download step'); + } else { + // Step: Download the source map for the app version and then symbolicate the profile: + try { + await fetchAndProcessArtifact(); + } catch (error) { + Logger.error(error); + process.exit(1); + } + } + + // Finally, symbolicate the profile + symbolicateProfile(); +} + +runAsyncScript(); diff --git a/scripts/tsconfig.json b/scripts/tsconfig.json new file mode 100644 index 000000000000..2d548a3aa2ce --- /dev/null +++ b/scripts/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "../tsconfig.json", + "ts-node": { + "require": ["tsconfig-paths/register"] + } +} diff --git a/scripts/utils/Logger.ts b/scripts/utils/Logger.ts new file mode 100644 index 000000000000..a851f11ff74f --- /dev/null +++ b/scripts/utils/Logger.ts @@ -0,0 +1,37 @@ +const COLOR_DIM = '\x1b[2m'; +const COLOR_RESET = '\x1b[0m'; +const COLOR_YELLOW = '\x1b[33m'; +const COLOR_RED = '\x1b[31m'; +const COLOR_GREEN = '\x1b[32m'; + +const log = (...args: unknown[]) => { + console.debug(...args); +}; + +const info = (...args: unknown[]) => { + log('▶️', ...args); +}; + +const success = (...args: unknown[]) => { + const lines = ['✅', COLOR_GREEN, ...args, COLOR_RESET]; + log(...lines); +}; + +const warn = (...args: unknown[]) => { + const lines = ['⚠️', COLOR_YELLOW, ...args, COLOR_RESET]; + log(...lines); +}; + +const note = (...args: unknown[]) => { + const lines = [COLOR_DIM, ...args, COLOR_RESET]; + log(...lines); +}; + +const error = (...args: unknown[]) => { + const lines = ['🔴', COLOR_RED, ...args, COLOR_RESET]; + log(...lines); +}; + +const formatLink = (name: string | number, url: string) => `\x1b]8;;${url}\x1b\\${name}\x1b]8;;\x1b\\`; + +export {log, info, warn, note, error, success, formatLink}; diff --git a/scripts/utils/parseCommandLineArguments.ts b/scripts/utils/parseCommandLineArguments.ts new file mode 100644 index 000000000000..9bb1d340335e --- /dev/null +++ b/scripts/utils/parseCommandLineArguments.ts @@ -0,0 +1,19 @@ +type ArgsMap = Record; + +// Function to parse command-line arguments into a key-value object +export default function parseCommandLineArguments(): ArgsMap { + const args = process.argv.slice(2); // Skip node and script paths + const argsMap: ArgsMap = {}; + args.forEach((arg) => { + const [key, value] = arg.split('='); + if (key.startsWith('--')) { + const name = key.substring(2); + argsMap[name] = value; + // User may provide a help arg without any value + if (name.toLowerCase() === 'help' && !value) { + argsMap[name] = 'true'; + } + } + }); + return argsMap; +} diff --git a/src/components/ProfilingToolMenu/BaseProfilingToolMenu.tsx b/src/components/ProfilingToolMenu/BaseProfilingToolMenu.tsx index 6ab1761fda62..5593ad627e92 100644 --- a/src/components/ProfilingToolMenu/BaseProfilingToolMenu.tsx +++ b/src/components/ProfilingToolMenu/BaseProfilingToolMenu.tsx @@ -44,6 +44,7 @@ function formatBytes(bytes: number, decimals = 2) { return `${parseFloat((bytes / k ** i).toFixed(dm))} ${sizes[i]}`; } +// WARNING: When changing this name make sure that the "scripts/symbolicate-profile.ts" script is still working! const newFileName = `Profile_trace_for_${pkg.version}.cpuprofile`; function BaseProfilingToolMenu({isProfilingInProgress = false, pathToBeUsed, displayPath}: BaseProfilingToolMenuProps) {