Skip to content

Commit 8954d23

Browse files
committed
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into feat/70827
2 parents 5fbfa69 + af62054 commit 8954d23

433 files changed

Lines changed: 5960 additions & 2325 deletions

File tree

Some content is hidden

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

.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ module.exports = {
154154
},
155155
rules: {
156156
// TypeScript specific rules
157+
'@lwc/lwc/no-async-await': 'off',
157158
'@typescript-eslint/prefer-enum-initializers': 'error',
158159
'@typescript-eslint/no-var-requires': 'off',
159160
'@typescript-eslint/no-non-null-assertion': 'error',

.github/.eslintrc.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ module.exports = {
22
rules: {
33
// For all these Node.js scripts, we do not want to disable `console` statements
44
'no-console': 'off',
5-
6-
'@lwc/lwc/no-async-await': 'off',
75
'no-await-in-loop': 'off',
86
'no-restricted-syntax': ['error', 'ForInStatement', 'LabeledStatement', 'WithStatement'],
97
'no-continue': 'off',

.github/CODEOWNERS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@
44
# PRs that touch the front end style or assets, get an additional review from the Design team
55
src/styles/ @Expensify/design @Expensify/pullerbear
66
assets/ @Expensify/design @Expensify/pullerbear
7+
8+
# Philosophy docs are in their early stages and need to be reviewed by Tim to ensure they have consistent formatting and organization
9+
contributingGuides/philosophies @tgolen

.github/actions/javascript/getPullRequestIncrementalChanges/index.js

Lines changed: 149 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12528,14 +12528,26 @@ function isEmptyObject(obj) {
1252812528
/***/ }),
1252912529

1253012530
/***/ 7037:
12531-
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
12531+
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
1253212532

1253312533
"use strict";
1253412534

12535+
var __importDefault = (this && this.__importDefault) || function (mod) {
12536+
return (mod && mod.__esModule) ? mod : { "default": mod };
12537+
};
1253512538
Object.defineProperty(exports, "__esModule", ({ value: true }));
12539+
exports.GIT_ERRORS = void 0;
12540+
const github_1 = __nccwpck_require__(5438);
1253612541
const child_process_1 = __nccwpck_require__(2081);
1253712542
const util_1 = __nccwpck_require__(3837);
12543+
const GithubUtils_1 = __importDefault(__nccwpck_require__(9296));
12544+
const Logger_1 = __nccwpck_require__(8891);
1253812545
const exec = (0, util_1.promisify)(child_process_1.exec);
12546+
const IS_CI = process.env.CI === 'true';
12547+
const GIT_ERRORS = {
12548+
FAILED_TO_FETCH_FROM_REMOTE: 'Failed to fetch from remote',
12549+
};
12550+
exports.GIT_ERRORS = GIT_ERRORS;
1253912551
/**
1254012552
* Utility class for git operations.
1254112553
*/
@@ -12774,10 +12786,146 @@ class Git {
1277412786
throw new Error(`Failed to fetch git reference ${ref}: ${error instanceof Error ? error.message : String(error)}`);
1277512787
}
1277612788
}
12789+
static getMainBaseCommitHash(remote) {
12790+
// Fetch the main branch from the specified remote to ensure it's available
12791+
try {
12792+
(0, child_process_1.execSync)(`git fetch ${remote} main --no-tags --depth=1 -q`, { encoding: 'utf8' });
12793+
}
12794+
catch (error) {
12795+
throw new Error(GIT_ERRORS.FAILED_TO_FETCH_FROM_REMOTE);
12796+
}
12797+
// In CI, use a simpler approach - just use the remote main branch directly
12798+
// This avoids issues with shallow clones and merge-base calculations
12799+
if (IS_CI) {
12800+
try {
12801+
const mergeBaseHash = (0, child_process_1.execSync)(`git rev-parse ${remote}/main`, { encoding: 'utf8' }).trim();
12802+
// Validate the output is a proper SHA hash
12803+
if (!mergeBaseHash || !/^[a-fA-F0-9]{40}$/.test(mergeBaseHash)) {
12804+
throw new Error(`git rev-parse returned unexpected output: ${mergeBaseHash}`);
12805+
}
12806+
return mergeBaseHash;
12807+
}
12808+
catch (error) {
12809+
(0, Logger_1.error)(`Failed to get commit hash for ${remote}/main:`, error);
12810+
throw new Error(`Could not get commit hash for ${remote}/main`);
12811+
}
12812+
}
12813+
// For local development, try to find the actual merge base
12814+
let mergeBaseHash;
12815+
try {
12816+
mergeBaseHash = (0, child_process_1.execSync)(`git merge-base ${remote}/main HEAD`, { encoding: 'utf8' }).trim();
12817+
}
12818+
catch (error) {
12819+
// If merge-base fails locally, fall back to using the remote main branch
12820+
try {
12821+
mergeBaseHash = (0, child_process_1.execSync)(`git rev-parse ${remote}/main`, { encoding: 'utf8' }).trim();
12822+
(0, Logger_1.error)(`Warning: Could not find merge base between ${remote}/main and HEAD. Using ${remote}/main as base.`);
12823+
}
12824+
catch (fallbackError) {
12825+
(0, Logger_1.error)(`Failed to find merge base with ${remote}/main:`, error);
12826+
(0, Logger_1.error)(`Fallback also failed:`, fallbackError);
12827+
throw new Error(`Could not determine merge base with ${remote}/main`);
12828+
}
12829+
}
12830+
// Validate the output is a proper SHA hash
12831+
if (!mergeBaseHash || !/^[a-fA-F0-9]{40}$/.test(mergeBaseHash)) {
12832+
throw new Error(`git merge-base returned unexpected output: ${mergeBaseHash}`);
12833+
}
12834+
return mergeBaseHash;
12835+
}
12836+
static async getChangedFiles(remote) {
12837+
if (IS_CI) {
12838+
const { data: changedFiles } = await GithubUtils_1.default.octokit.pulls.listFiles({
12839+
owner: 'Expensify',
12840+
repo: 'App',
12841+
// eslint-disable-next-line @typescript-eslint/naming-convention
12842+
pull_number: github_1.context.payload.pull_request?.number ?? 0,
12843+
});
12844+
return changedFiles.map((file) => file.filename);
12845+
}
12846+
try {
12847+
// Get files changed in the current branch/commit
12848+
const mainBaseCommitHash = this.getMainBaseCommitHash(remote);
12849+
// Get the diff output and check status
12850+
const gitDiffOutput = (0, child_process_1.execSync)(`git diff --diff-filter=AMR --name-only ${mainBaseCommitHash} HEAD`, {
12851+
encoding: 'utf8',
12852+
});
12853+
const files = gitDiffOutput.trim().split('\n');
12854+
return files;
12855+
}
12856+
catch (error) {
12857+
if (error instanceof Error && error.message === GIT_ERRORS.FAILED_TO_FETCH_FROM_REMOTE) {
12858+
throw error;
12859+
}
12860+
(0, Logger_1.error)('Could not determine changed files:', error);
12861+
throw error;
12862+
}
12863+
}
1277712864
}
1277812865
exports["default"] = Git;
1277912866

1278012867

12868+
/***/ }),
12869+
12870+
/***/ 8891:
12871+
/***/ ((__unused_webpack_module, exports) => {
12872+
12873+
"use strict";
12874+
12875+
Object.defineProperty(exports, "__esModule", ({ value: true }));
12876+
exports.bold = exports.formatLink = exports.success = exports.error = exports.note = exports.warn = exports.info = exports.log = void 0;
12877+
const COLOR_DIM = '\x1b[2m';
12878+
const COLOR_RESET = '\x1b[0m';
12879+
const COLOR_YELLOW = '\x1b[33m';
12880+
const COLOR_RED = '\x1b[31m';
12881+
const COLOR_GREEN = '\x1b[32m';
12882+
const COLOR_BOLD = '\x1b[1m';
12883+
const EMOJIS = {
12884+
// One column emojis need to be rendered with an extra space after to align with two column emojis
12885+
INFO: '▶️ ',
12886+
// Two column emojis can be rendered as-is
12887+
SUCCESS: '✅',
12888+
WARN: '⚠️',
12889+
ERROR: '🔴',
12890+
};
12891+
const log = (...args) => {
12892+
console.debug(...args);
12893+
};
12894+
exports.log = log;
12895+
const info = (...args) => {
12896+
const lines = [EMOJIS.INFO, ...args];
12897+
log(...lines);
12898+
};
12899+
exports.info = info;
12900+
const bold = (...args) => {
12901+
const lines = [COLOR_BOLD, ...args, COLOR_RESET];
12902+
log(...lines);
12903+
};
12904+
exports.bold = bold;
12905+
const success = (...args) => {
12906+
const lines = [`${EMOJIS.SUCCESS}${COLOR_GREEN}`, ...args, COLOR_RESET];
12907+
log(...lines);
12908+
};
12909+
exports.success = success;
12910+
const warn = (...args) => {
12911+
const lines = [`${EMOJIS.WARN}${COLOR_YELLOW}`, ...args, COLOR_RESET];
12912+
log(...lines);
12913+
};
12914+
exports.warn = warn;
12915+
const note = (...args) => {
12916+
const lines = [COLOR_DIM, ...args, COLOR_RESET];
12917+
log(...lines);
12918+
};
12919+
exports.note = note;
12920+
const error = (...args) => {
12921+
const lines = [`${EMOJIS.ERROR}${COLOR_RED}`, ...args, COLOR_RESET];
12922+
log(...lines);
12923+
};
12924+
exports.error = error;
12925+
const formatLink = (name, url) => `\x1b]8;;${url}\x1b\\${name}\x1b]8;;\x1b\\`;
12926+
exports.formatLink = formatLink;
12927+
12928+
1278112929
/***/ }),
1278212930

1278312931
/***/ 9491:

.github/actions/javascript/markPullRequestsAsDeployed/index.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12845,7 +12845,7 @@ async function run() {
1284512845
const webResult = getDeployTableMessage(core.getInput('WEB', { required: true }));
1284612846
const date = core.getInput('DATE');
1284712847
const note = core.getInput('NOTE');
12848-
function getDeployMessage(deployer, deployVerb, prTitle) {
12848+
function getDeployMessage(deployer, deployVerb) {
1284912849
let message = `🚀 [${deployVerb}](${workflowURL}) to ${isProd ? 'production' : 'staging'}`;
1285012850
message += ` by https://github.com/${deployer} in version: ${version} `;
1285112851
if (date) {
@@ -12855,11 +12855,6 @@ async function run() {
1285512855
message += `\n\nplatform | result\n---|---\n🖥 desktop 🖥|${desktopResult}`;
1285612856
message += `\n🕸 web 🕸|${webResult}`;
1285712857
message += `\n🤖 android 🤖|${androidResult}\n🍎 iOS 🍎|${iOSResult}`;
12858-
if (deployVerb === 'Cherry-picked' && !/no ?qa/gi.test(prTitle ?? '')) {
12859-
// eslint-disable-next-line max-len
12860-
message +=
12861-
'\n\n@Expensify/applauseleads please QA this PR and check it off on the [deploy checklist](https://github.com/Expensify/App/issues?q=is%3Aopen+is%3Aissue+label%3AStagingDeployCash) if it passes.';
12862-
}
1286312858
if (note) {
1286412859
message += `\n\n_Note:_ ${note}`;
1286512860
}

.github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ async function run() {
110110
const date = core.getInput('DATE');
111111
const note = core.getInput('NOTE');
112112

113-
function getDeployMessage(deployer: string, deployVerb: string, prTitle?: string): string {
113+
function getDeployMessage(deployer: string, deployVerb: string): string {
114114
let message = `🚀 [${deployVerb}](${workflowURL}) to ${isProd ? 'production' : 'staging'}`;
115115
message += ` by https://github.com/${deployer} in version: ${version} `;
116116
if (date) {
@@ -121,12 +121,6 @@ async function run() {
121121
message += `\n🕸 web 🕸|${webResult}`;
122122
message += `\n🤖 android 🤖|${androidResult}\n🍎 iOS 🍎|${iOSResult}`;
123123

124-
if (deployVerb === 'Cherry-picked' && !/no ?qa/gi.test(prTitle ?? '')) {
125-
// eslint-disable-next-line max-len
126-
message +=
127-
'\n\n@Expensify/applauseleads please QA this PR and check it off on the [deploy checklist](https://github.com/Expensify/App/issues?q=is%3Aopen+is%3Aissue+label%3AStagingDeployCash) if it passes.';
128-
}
129-
130124
if (note) {
131125
message += `\n\n_Note:_ ${note}`;
132126
}

.github/workflows/claude-review.yml

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,12 @@ on:
99
types: [opened]
1010
pull_request_review_comment:
1111
types: [created]
12-
pull_request_review:
13-
types: [submitted]
12+
workflow_dispatch:
13+
inputs:
14+
PULL_REQUEST_URL:
15+
description: 'The full URL of the E/App pull request.'
16+
required: true
17+
type: string
1418

1519
jobs:
1620
review:
@@ -33,13 +37,34 @@ jobs:
3337
- 'docs/**/*.md'
3438
- 'docs/**/*.csv'
3539
40+
41+
- name: Validate that user is an Expensify employee
42+
uses: ./.github/actions/composite/validateActor
43+
if: github.event_name == 'workflow_dispatch'
44+
with:
45+
REQUIRE_APP_DEPLOYER: false
46+
OS_BOTIFY_TOKEN: ${{ secrets.OS_BOTIFY_COMMIT_TOKEN }}
47+
48+
- name: Get PR details
49+
if: github.event_name == 'workflow_dispatch'
50+
id: pr-data
51+
run: |
52+
echo "::notice::🔧 Manual workflow dispatch triggered"
53+
PR_INFO=$(gh pr view "${{ inputs.PULL_REQUEST_URL }}" --json number)
54+
{
55+
echo "PR_NUMBER=$(echo "$PR_INFO" | jq -r '.number')"
56+
} >> "$GITHUB_OUTPUT"
57+
echo "::notice::✅ Processing PR #$(echo "$PR_INFO" | jq -r '.number')"
58+
env:
59+
GITHUB_TOKEN: ${{ github.token }}
60+
3661
- name: Run Claude Code (code)
3762
if: steps.filter.outputs.code == 'true'
3863
uses: anthropics/claude-code-action@a3ff61d47aa5118a43b33ae44c4087d9eb51111a # v1.0.8
3964
with:
4065
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
4166
github_token: ${{ secrets.GITHUB_TOKEN }}
42-
prompt: "/review-code-pr REPO: ${{ github.repository }} PR_NUMBER: ${{ github.event.pull_request.number }}"
67+
prompt: "/review-code-pr REPO: ${{ github.repository }} PR_NUMBER: ${{ steps.pr-data.outputs.PR_NUMBER || github.event.pull_request.number }}"
4368
claude_args: |
4469
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*)"
4570
@@ -49,6 +74,6 @@ jobs:
4974
with:
5075
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
5176
github_token: ${{ secrets.GITHUB_TOKEN }}
52-
prompt: "/review-helpdot-pr REPO: ${{ github.repository }} PR_NUMBER: ${{ github.event.pull_request.number }}"
77+
prompt: "/review-helpdot-pr REPO: ${{ github.repository }} PR_NUMBER: ${{ steps.pr-data.outputs.PR_NUMBER || github.event.pull_request.number }}"
5378
claude_args: |
5479
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*)"
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: React Compiler Compliance Check
2+
3+
on:
4+
workflow_call:
5+
pull_request:
6+
types: [opened, synchronize]
7+
branches-ignore: [staging, production]
8+
paths: ['**.tsx']
9+
10+
concurrency:
11+
group: ${{ github.ref == 'refs/heads/main' && format('{0}-{1}', github.ref, github.sha) || github.ref }}-react-compiler-compliance
12+
cancel-in-progress: true
13+
jobs:
14+
react-compiler-compliance:
15+
name: React Compiler Compliance
16+
if: ${{ github.actor != 'OSBotify' }}
17+
runs-on: ubuntu-latest
18+
19+
steps:
20+
# v4
21+
- name: Checkout
22+
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
23+
24+
- name: Setup Node
25+
uses: ./.github/actions/composite/setupNode
26+
27+
- name: Run React Compiler Compliance Check
28+
run: npm run react-compiler-compliance-check check-changed
29+
env:
30+
CI: true
31+
GITHUB_TOKEN: ${{ github.token }}

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,8 @@ web-build/
145145
# Jeykll
146146
docs/.bundle
147147

148-
# Output of react compiler healthcheck dev script
148+
# React Compiler Compliance Check output
149+
react-compiler-report.json
149150
react-compiler-output.txt
150151

151152
# Rock Framework

Mobile-Expensify

0 commit comments

Comments
 (0)