Skip to content

Commit 6670d8c

Browse files
Merge branch 'Expensify:main' into fix-cancellation-text
2 parents e44bcd7 + f2b8304 commit 6670d8c

File tree

489 files changed

+25541
-9218
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

489 files changed

+25541
-9218
lines changed

.github/actions/composite/announceFailedWorkflowInSlack/action.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ inputs:
1313
runs:
1414
using: composite
1515
steps:
16-
- uses: 8398a7/action-slack@v3
16+
- uses: 8398a7/action-slack@1750b5085f3ec60384090fb7c52965ef822e869e
1717
name: Job failed Slack notification
1818
with:
1919
status: custom

.github/actions/composite/setupNode/action.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ runs:
2323
shell: bash
2424
run: jq 'del(.version, .packages[""].version)' package-lock.json > normalized-package-lock.json
2525

26-
- uses: actions/setup-node@v4
26+
- uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e #v4
2727
with:
2828
node-version-file: '.nvmrc'
2929
cache: npm

.github/actions/javascript/authorChecklist/index.js

+102
Original file line numberDiff line numberDiff line change
@@ -6748,6 +6748,79 @@ exports.throttling = throttling;
67486748
//# sourceMappingURL=index.js.map
67496749

67506750

6751+
/***/ }),
6752+
6753+
/***/ 537:
6754+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
6755+
6756+
"use strict";
6757+
6758+
6759+
Object.defineProperty(exports, "__esModule", ({ value: true }));
6760+
6761+
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6762+
6763+
var deprecation = __nccwpck_require__(8932);
6764+
var once = _interopDefault(__nccwpck_require__(1223));
6765+
6766+
const logOnceCode = once(deprecation => console.warn(deprecation));
6767+
const logOnceHeaders = once(deprecation => console.warn(deprecation));
6768+
/**
6769+
* Error with extra properties to help with debugging
6770+
*/
6771+
class RequestError extends Error {
6772+
constructor(message, statusCode, options) {
6773+
super(message);
6774+
// Maintains proper stack trace (only available on V8)
6775+
/* istanbul ignore next */
6776+
if (Error.captureStackTrace) {
6777+
Error.captureStackTrace(this, this.constructor);
6778+
}
6779+
this.name = "HttpError";
6780+
this.status = statusCode;
6781+
let headers;
6782+
if ("headers" in options && typeof options.headers !== "undefined") {
6783+
headers = options.headers;
6784+
}
6785+
if ("response" in options) {
6786+
this.response = options.response;
6787+
headers = options.response.headers;
6788+
}
6789+
// redact request credentials without mutating original request options
6790+
const requestCopy = Object.assign({}, options.request);
6791+
if (options.request.headers.authorization) {
6792+
requestCopy.headers = Object.assign({}, options.request.headers, {
6793+
authorization: options.request.headers.authorization.replace(/ .*$/, " [REDACTED]")
6794+
});
6795+
}
6796+
requestCopy.url = requestCopy.url
6797+
// client_id & client_secret can be passed as URL query parameters to increase rate limit
6798+
// see https://developer.github.com/v3/#increasing-the-unauthenticated-rate-limit-for-oauth-applications
6799+
.replace(/\bclient_secret=\w+/g, "client_secret=[REDACTED]")
6800+
// OAuth tokens can be passed as URL query parameters, although it is not recommended
6801+
// see https://developer.github.com/v3/#oauth2-token-sent-in-a-header
6802+
.replace(/\baccess_token=\w+/g, "access_token=[REDACTED]");
6803+
this.request = requestCopy;
6804+
// deprecations
6805+
Object.defineProperty(this, "code", {
6806+
get() {
6807+
logOnceCode(new deprecation.Deprecation("[@octokit/request-error] `error.code` is deprecated, use `error.status`."));
6808+
return statusCode;
6809+
}
6810+
});
6811+
Object.defineProperty(this, "headers", {
6812+
get() {
6813+
logOnceHeaders(new deprecation.Deprecation("[@octokit/request-error] `error.headers` is deprecated, use `error.response.headers`."));
6814+
return headers || {};
6815+
}
6816+
});
6817+
}
6818+
}
6819+
6820+
exports.RequestError = RequestError;
6821+
//# sourceMappingURL=index.js.map
6822+
6823+
67516824
/***/ }),
67526825

67536826
/***/ 3682:
@@ -15536,6 +15609,7 @@ const core = __importStar(__nccwpck_require__(2186));
1553615609
const utils_1 = __nccwpck_require__(3030);
1553715610
const plugin_paginate_rest_1 = __nccwpck_require__(4193);
1553815611
const plugin_throttling_1 = __nccwpck_require__(9968);
15612+
const request_error_1 = __nccwpck_require__(537);
1553915613
const EmptyObject_1 = __nccwpck_require__(8227);
1554015614
const arrayDifference_1 = __importDefault(__nccwpck_require__(7034));
1554115615
const CONST_1 = __importDefault(__nccwpck_require__(9873));
@@ -15958,6 +16032,34 @@ class GithubUtils {
1595816032
})
1595916033
.then((response) => response.url);
1596016034
}
16035+
/**
16036+
* Get commits between two tags via the GitHub API
16037+
*/
16038+
static async getCommitHistoryBetweenTags(fromTag, toTag) {
16039+
console.log('Getting pull requests merged between the following tags:', fromTag, toTag);
16040+
try {
16041+
const { data: comparison } = await this.octokit.repos.compareCommits({
16042+
owner: CONST_1.default.GITHUB_OWNER,
16043+
repo: CONST_1.default.APP_REPO,
16044+
base: fromTag,
16045+
head: toTag,
16046+
});
16047+
// Map API response to our CommitType format
16048+
return comparison.commits.map((commit) => ({
16049+
commit: commit.sha,
16050+
subject: commit.commit.message,
16051+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
16052+
authorName: commit.commit.author?.name || 'Unknown',
16053+
}));
16054+
}
16055+
catch (error) {
16056+
if (error instanceof request_error_1.RequestError && error.status === 404) {
16057+
console.error(`❓❓ Failed to compare commits with the GitHub API. The base tag ('${fromTag}') or head tag ('${toTag}') likely doesn't exist on the remote repository. If this is the case, create or push them. 💡💡`);
16058+
}
16059+
// Re-throw the error after logging
16060+
throw error;
16061+
}
16062+
}
1596116063
}
1596216064
exports["default"] = GithubUtils;
1596316065

.github/actions/javascript/awaitStagingDeploys/index.js

+102
Original file line numberDiff line numberDiff line change
@@ -4730,6 +4730,79 @@ exports.throttling = throttling;
47304730
//# sourceMappingURL=index.js.map
47314731

47324732

4733+
/***/ }),
4734+
4735+
/***/ 537:
4736+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
4737+
4738+
"use strict";
4739+
4740+
4741+
Object.defineProperty(exports, "__esModule", ({ value: true }));
4742+
4743+
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
4744+
4745+
var deprecation = __nccwpck_require__(8932);
4746+
var once = _interopDefault(__nccwpck_require__(1223));
4747+
4748+
const logOnceCode = once(deprecation => console.warn(deprecation));
4749+
const logOnceHeaders = once(deprecation => console.warn(deprecation));
4750+
/**
4751+
* Error with extra properties to help with debugging
4752+
*/
4753+
class RequestError extends Error {
4754+
constructor(message, statusCode, options) {
4755+
super(message);
4756+
// Maintains proper stack trace (only available on V8)
4757+
/* istanbul ignore next */
4758+
if (Error.captureStackTrace) {
4759+
Error.captureStackTrace(this, this.constructor);
4760+
}
4761+
this.name = "HttpError";
4762+
this.status = statusCode;
4763+
let headers;
4764+
if ("headers" in options && typeof options.headers !== "undefined") {
4765+
headers = options.headers;
4766+
}
4767+
if ("response" in options) {
4768+
this.response = options.response;
4769+
headers = options.response.headers;
4770+
}
4771+
// redact request credentials without mutating original request options
4772+
const requestCopy = Object.assign({}, options.request);
4773+
if (options.request.headers.authorization) {
4774+
requestCopy.headers = Object.assign({}, options.request.headers, {
4775+
authorization: options.request.headers.authorization.replace(/ .*$/, " [REDACTED]")
4776+
});
4777+
}
4778+
requestCopy.url = requestCopy.url
4779+
// client_id & client_secret can be passed as URL query parameters to increase rate limit
4780+
// see https://developer.github.com/v3/#increasing-the-unauthenticated-rate-limit-for-oauth-applications
4781+
.replace(/\bclient_secret=\w+/g, "client_secret=[REDACTED]")
4782+
// OAuth tokens can be passed as URL query parameters, although it is not recommended
4783+
// see https://developer.github.com/v3/#oauth2-token-sent-in-a-header
4784+
.replace(/\baccess_token=\w+/g, "access_token=[REDACTED]");
4785+
this.request = requestCopy;
4786+
// deprecations
4787+
Object.defineProperty(this, "code", {
4788+
get() {
4789+
logOnceCode(new deprecation.Deprecation("[@octokit/request-error] `error.code` is deprecated, use `error.status`."));
4790+
return statusCode;
4791+
}
4792+
});
4793+
Object.defineProperty(this, "headers", {
4794+
get() {
4795+
logOnceHeaders(new deprecation.Deprecation("[@octokit/request-error] `error.headers` is deprecated, use `error.response.headers`."));
4796+
return headers || {};
4797+
}
4798+
});
4799+
}
4800+
}
4801+
4802+
exports.RequestError = RequestError;
4803+
//# sourceMappingURL=index.js.map
4804+
4805+
47334806
/***/ }),
47344807

47354808
/***/ 3682:
@@ -12329,6 +12402,7 @@ const core = __importStar(__nccwpck_require__(2186));
1232912402
const utils_1 = __nccwpck_require__(3030);
1233012403
const plugin_paginate_rest_1 = __nccwpck_require__(4193);
1233112404
const plugin_throttling_1 = __nccwpck_require__(9968);
12405+
const request_error_1 = __nccwpck_require__(537);
1233212406
const EmptyObject_1 = __nccwpck_require__(8227);
1233312407
const arrayDifference_1 = __importDefault(__nccwpck_require__(7034));
1233412408
const CONST_1 = __importDefault(__nccwpck_require__(9873));
@@ -12751,6 +12825,34 @@ class GithubUtils {
1275112825
})
1275212826
.then((response) => response.url);
1275312827
}
12828+
/**
12829+
* Get commits between two tags via the GitHub API
12830+
*/
12831+
static async getCommitHistoryBetweenTags(fromTag, toTag) {
12832+
console.log('Getting pull requests merged between the following tags:', fromTag, toTag);
12833+
try {
12834+
const { data: comparison } = await this.octokit.repos.compareCommits({
12835+
owner: CONST_1.default.GITHUB_OWNER,
12836+
repo: CONST_1.default.APP_REPO,
12837+
base: fromTag,
12838+
head: toTag,
12839+
});
12840+
// Map API response to our CommitType format
12841+
return comparison.commits.map((commit) => ({
12842+
commit: commit.sha,
12843+
subject: commit.commit.message,
12844+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
12845+
authorName: commit.commit.author?.name || 'Unknown',
12846+
}));
12847+
}
12848+
catch (error) {
12849+
if (error instanceof request_error_1.RequestError && error.status === 404) {
12850+
console.error(`❓❓ Failed to compare commits with the GitHub API. The base tag ('${fromTag}') or head tag ('${toTag}') likely doesn't exist on the remote repository. If this is the case, create or push them. 💡💡`);
12851+
}
12852+
// Re-throw the error after logging
12853+
throw error;
12854+
}
12855+
}
1275412856
}
1275512857
exports["default"] = GithubUtils;
1275612858

Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
1-
name: 'Bump npm version'
2-
description: 'Increase the application version (JS and native), based on git tags'
1+
name: Bump npm version
2+
description: Increase the application version (JS and native), based on git tags
33
inputs:
4-
GITHUB_TOKEN:
5-
description: Auth token for New Expensify Github
6-
required: true
74
SEMVER_LEVEL:
85
description: Semantic Versioning Level
96
required: true
107
outputs:
118
NEW_VERSION:
129
description: The new semver version of the application, updated in the JS and native layers.
1310
runs:
14-
using: 'node20'
15-
main: './index.js'
11+
using: node20
12+
main: ./index.js
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,26 @@
11
import * as core from '@actions/core';
2-
import {exec as originalExec} from 'child_process';
3-
import fs from 'fs';
4-
import type {PackageJson} from 'type-fest';
5-
import {promisify} from 'util';
6-
import {generateAndroidVersionCode, updateAndroidVersion, updateiOSVersion} from '@github/libs/nativeVersionUpdater';
2+
import bumpVersion from '@scripts/bumpVersion';
73
import * as versionUpdater from '@github/libs/versionUpdater';
8-
import type {SemverLevel} from '@github/libs/versionUpdater';
94

10-
const exec = promisify(originalExec);
11-
12-
/**
13-
* Update the native app versions.
14-
*/
15-
function updateNativeVersions(version: string) {
16-
console.log(`Updating native versions to ${version}`);
17-
18-
// Update Android
19-
const androidVersionCode = generateAndroidVersionCode(version);
20-
updateAndroidVersion(version, androidVersionCode)
21-
.then(() => {
22-
console.log('Successfully updated Android!');
23-
})
24-
.catch((err: string | Error) => {
25-
console.error('Error updating Android');
26-
core.setFailed(err);
27-
});
28-
29-
// Update iOS
5+
async function run() {
306
try {
31-
const cfBundleVersion = updateiOSVersion(version);
32-
if (typeof cfBundleVersion === 'string' && cfBundleVersion.split('.').length === 4) {
33-
core.setOutput('NEW_IOS_VERSION', cfBundleVersion);
34-
console.log('Successfully updated iOS!');
35-
} else {
36-
core.setFailed(`Failed to set NEW_IOS_VERSION. CFBundleVersion: ${cfBundleVersion}`);
7+
const semverLevel = core.getInput('SEMVER_LEVEL', {required: true});
8+
if (!versionUpdater.isValidSemverLevel(semverLevel)) {
9+
throw new Error(`Invalid SEMVER_LEVEL ${semverLevel}`);
3710
}
38-
} catch (err) {
39-
console.error('Error updating iOS');
40-
if (err instanceof Error) {
41-
core.setFailed(err);
11+
const newVersion = await bumpVersion(semverLevel);
12+
core.setOutput('NEW_VERSION', newVersion);
13+
} catch (e) {
14+
if (e instanceof Error) {
15+
core.setFailed(e);
16+
return;
4217
}
18+
core.setFailed('An unknown error occurred.');
4319
}
4420
}
4521

46-
let semanticVersionLevel = core.getInput('SEMVER_LEVEL', {required: true});
47-
if (!semanticVersionLevel || !versionUpdater.isValidSemverLevel(semanticVersionLevel)) {
48-
semanticVersionLevel = versionUpdater.SEMANTIC_VERSION_LEVELS.BUILD;
49-
console.log(`Invalid input for 'SEMVER_LEVEL': ${semanticVersionLevel}`, `Defaulting to: ${semanticVersionLevel}`);
22+
if (require.main === module) {
23+
run();
5024
}
5125

52-
const {version: previousVersion} = JSON.parse(fs.readFileSync('./package.json').toString()) as PackageJson;
53-
if (!previousVersion) {
54-
core.setFailed('Error: Could not read package.json');
55-
}
56-
57-
const newVersion = versionUpdater.incrementVersion(previousVersion ?? '', semanticVersionLevel as SemverLevel);
58-
console.log(`Previous version: ${previousVersion}`, `New version: ${newVersion}`);
59-
60-
updateNativeVersions(newVersion);
61-
62-
console.log(`Setting npm version to ${newVersion}`);
63-
exec(`npm --no-git-tag-version version ${newVersion} -m "Update version to ${newVersion}"`)
64-
.then(({stdout}) => {
65-
// NPM and native versions successfully updated, output new version
66-
console.log(stdout);
67-
core.setOutput('NEW_VERSION', newVersion);
68-
})
69-
.catch(({stdout, stderr}) => {
70-
// Log errors and retry
71-
console.log(stdout);
72-
console.error(stderr);
73-
core.setFailed('An error occurred in the `npm version` command');
74-
});
26+
export default run;

0 commit comments

Comments
 (0)