Skip to content

Commit a51ba2d

Browse files
committed
Merge branch 'main' into @GCygnaek/landscape-mode/hidden-input-fixes
2 parents a6c6091 + f8263d4 commit a51ba2d

702 files changed

Lines changed: 24966 additions & 11996 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.

.claude/skills/coding-standards/rules/clean-react-0-compiler.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Manual memoization is therefore:
1717

1818
The codebase enforces this via:
1919
- **Babel plugin**: `babel-plugin-react-compiler` in `babel.config.js`
20-
- **ESLint processor**: `eslint-plugin-react-compiler-compat` suppresses redundant lint rules when files compile successfully
20+
- **ESLint processor**: `eslint-processor-react-compiler-compat` suppresses redundant lint rules when files compile successfully
2121
- **CI compliance check**: `scripts/react-compiler-compliance-check.ts` enforces that new components/hooks compile and that existing compiled files don't regress
2222

2323
Reference: [React Compiler documentation](https://react.dev/learn/react-compiler)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Is Contributor+
2+
description: Check whether a GitHub user is a member of the Expensify/contributor-plus team. Sets IS_CPLUS=true when the user is a member, IS_CPLUS=false otherwise.
3+
4+
inputs:
5+
USERNAME:
6+
description: The GitHub login of the user to check.
7+
required: true
8+
OS_BOTIFY_TOKEN:
9+
description: OSBotify token. Needed to read team memberships (the default GITHUB_TOKEN lacks the read:org scope).
10+
required: true
11+
12+
outputs:
13+
IS_CPLUS:
14+
description: "'true' if the user is a member of Expensify/contributor-plus, 'false' otherwise."
15+
value: ${{ steps.check.outputs.IS_CPLUS }}
16+
17+
runs:
18+
using: composite
19+
steps:
20+
- name: Check Contributor+ membership
21+
id: check
22+
shell: bash
23+
env:
24+
GH_TOKEN: ${{ inputs.OS_BOTIFY_TOKEN }}
25+
USERNAME: ${{ inputs.USERNAME }}
26+
run: |
27+
if gh api "/orgs/Expensify/teams/contributor-plus/memberships/$USERNAME" --silent; then
28+
echo "::notice::✅ $USERNAME is a Contributor+ member"
29+
echo "IS_CPLUS=true" >> "$GITHUB_OUTPUT"
30+
else
31+
echo "::notice::$USERNAME is not a Contributor+ member"
32+
echo "IS_CPLUS=false" >> "$GITHUB_OUTPUT"
33+
fi

.github/actions/javascript/failureNotifier/failureNotifier.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ ${errorMessage}
122122
1. **Why the PR caused the job to fail?**
123123
2. **Address any underlying issues.**
124124
125+
**For detailed instructions, check [this SO](https://stackoverflowteams.com/c/expensify/questions/21936).**
126+
125127
**🐛 We appreciate your help in squashing this bug!**`;
126128

127129
await octokit.rest.issues.create({

.github/workflows/claude-review.yml

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,50 @@ permissions:
77
on:
88
pull_request_target:
99
types: [opened, ready_for_review]
10+
pull_request_review:
11+
types: [submitted]
1012

1113
concurrency:
1214
group: claude-review-${{ github.event.pull_request.html_url }}
1315
cancel-in-progress: true
1416

1517
jobs:
1618
validate:
19+
if: github.event_name == 'pull_request_target'
1720
uses: ./.github/workflows/contributorValidationGate.yml
1821
with:
1922
PR_NUMBER: ${{ github.event.pull_request.number }}
2023
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
2124
AUTHOR_ASSOCIATION: ${{ github.event.pull_request.author_association }}
2225

26+
checkCPlusApproval:
27+
if: github.event_name == 'pull_request_review' && github.event.review.state == 'approved'
28+
runs-on: blacksmith-2vcpu-ubuntu-2404
29+
outputs:
30+
IS_CPLUS: ${{ steps.check.outputs.IS_CPLUS }}
31+
steps:
32+
- name: Checkout repository
33+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
34+
with:
35+
fetch-depth: 1
36+
37+
- name: Check Contributor+ membership
38+
id: check
39+
uses: ./.github/actions/composite/isContributorPlus
40+
with:
41+
USERNAME: ${{ github.event.review.user.login }}
42+
OS_BOTIFY_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}
43+
2344
review:
24-
needs: [validate]
45+
needs: [validate, checkCPlusApproval]
2546
if: |
26-
needs.validate.outputs.IS_AUTHORIZED == 'true'
47+
!cancelled()
2748
&& github.event.pull_request.draft != true
2849
&& !contains(github.event.pull_request.title, 'Revert')
50+
&& (
51+
(github.event_name == 'pull_request_target' && needs.validate.outputs.IS_AUTHORIZED == 'true')
52+
|| (github.event_name == 'pull_request_review' && needs.checkCPlusApproval.outputs.IS_CPLUS == 'true')
53+
)
2954
runs-on: blacksmith-2vcpu-ubuntu-2404
3055
env:
3156
PR_NUMBER: ${{ github.event.pull_request.number }}

.github/workflows/deployExpensifyHelp.yml

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ on:
77
- main
88
paths:
99
- 'docs/**'
10+
- '.github/workflows/deployExpensifyHelp.yml'
1011

1112
# Run on any pull request (except PRs against staging or production) that has changes to the docs directory
1213
pull_request:
1314
types: [opened, synchronize]
1415
branches-ignore: [staging, production]
1516
paths:
1617
- 'docs/**'
18+
- '.github/workflows/deployExpensifyHelp.yml'
1719

1820
# Run on any manual trigger
1921
workflow_dispatch:
@@ -51,18 +53,23 @@ jobs:
5153

5254
- name: Enforce that a redirect link has been created
5355
run: ./.github/scripts/enforceRedirect.sh
54-
56+
5557
- name: Enforce iframe and Cloudflare CDN usage
5658
run: ./.github/scripts/enforceVideoFormats.sh
5759

5860
- name: Generate allowed URLs whitelist for AI search
5961
run: npx ts-node .github/scripts/generateAllowedUrls.ts
6062

61-
- name: Build with Jekyll
62-
uses: actions/jekyll-build-pages@0143c158f4fa0c5dcd99499a5d00859d79f70b0e
63+
- name: Set up Ruby
64+
# v1.306.0
65+
uses: ruby/setup-ruby@c4e5b1316158f92e3d49443a9d58b31d25ac0f8f
6366
with:
64-
source: ./docs/
65-
destination: ./docs/_site
67+
bundler-cache: true
68+
working-directory: ./docs
69+
70+
- name: Build Jekyll site
71+
run: bundle exec jekyll build --source ./ --destination ./_site
72+
working-directory: ./docs
6673

6774
- name: Deploy to Cloudflare Pages
6875
uses: cloudflare/pages-action@f0a1cd58cd66095dee69bfa18fa5efd1dde93bca

.github/workflows/lint-changed.yml

Lines changed: 0 additions & 89 deletions
This file was deleted.

.github/workflows/lint.yml

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ on:
55
pull_request:
66
types: [opened, synchronize]
77
branches-ignore: [staging, production]
8-
paths: ['**.js', '**.ts', '**.tsx', '**.json', '**.mjs', '**.cjs', 'config/.editorconfig', '.watchmanconfig', '.imgbotconfig']
8+
paths: ['**.js', '**.ts', '**.tsx', '**.json', '**.mjs', '**.cjs', 'config/.editorconfig', 'config/eslint/**', 'scripts/lint.sh', 'scripts/lintChanged.sh', '.watchmanconfig', '.imgbotconfig']
99

1010
concurrency:
1111
group: ${{ github.ref == 'refs/heads/main' && format('{0}-{1}', github.ref, github.sha) || github.ref }}-lint
@@ -20,6 +20,12 @@ jobs:
2020
- name: Checkout
2121
# v6
2222
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
23+
with:
24+
# Only use the elevated OSBotify token on the post-merge `workflow_call` run
25+
# (so the auto-commit step below can push to the protected `main` branch).
26+
# PR runs use the default GITHUB_TOKEN so PR code can't borrow push-to-main
27+
# access via the persisted checkout credentials.
28+
token: ${{ github.event_name == 'workflow_call' && secrets.OS_BOTIFY_COMMIT_TOKEN || github.token }}
2329

2430
- name: Setup Node
2531
uses: ./.github/actions/composite/setupNode
@@ -33,9 +39,9 @@ jobs:
3339
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb
3440
with:
3541
path: node_modules/.cache/eslint
36-
key: ${{ runner.os }}-eslint-${{ hashFiles('eslint.config.*', 'normalized-package-lock.json') }}-${{ github.sha }}
42+
key: ${{ runner.os }}-eslint-${{ hashFiles('eslint.config.mjs', 'config/eslint/**', 'normalized-package-lock.json') }}-${{ github.sha }}
3743
restore-keys: |
38-
${{ runner.os }}-eslint-${{ hashFiles('eslint.config.*', 'normalized-package-lock.json') }}-
44+
${{ runner.os }}-eslint-${{ hashFiles('eslint.config.mjs', 'config/eslint/**', 'normalized-package-lock.json') }}-
3945
${{ runner.os }}-eslint-
4046
4147
# ESLint's cache doesn't track cross-file TypeScript dependencies, which can cause stale errors.
@@ -48,13 +54,44 @@ jobs:
4854
rm -rf node_modules/.cache/eslint
4955
npm run lint
5056
fi
51-
env:
52-
CI: true
5357
5458
- name: Save ESLint cache
5559
# v5.0.1
5660
uses: actions/cache/save@9255dc7a253b0ccc959486e2bca901246202afeb
5761
if: always()
5862
with:
5963
path: node_modules/.cache/eslint
60-
key: ${{ runner.os }}-eslint-${{ hashFiles('eslint.config.*', 'normalized-package-lock.json') }}-${{ github.sha }}
64+
key: ${{ runner.os }}-eslint-${{ hashFiles('eslint.config.mjs', 'config/eslint/**', 'normalized-package-lock.json') }}-${{ github.sha }}
65+
66+
# If lint tightened the seatbelt baseline (i.e. fewer baselined errors than last time),
67+
# commit the updated TSV back to `main` as OSBotify. Only runs under `workflow_call`
68+
# (i.e. invoked from preDeploy.yml, which only triggers on push to main).
69+
- name: Check for tightened eslint-seatbelt baseline
70+
id: seatbelt_diff
71+
if: github.event_name == 'workflow_call'
72+
run: |
73+
if git diff --quiet config/eslint/eslint.seatbelt.tsv; then
74+
echo "tightened=false" >> "$GITHUB_OUTPUT"
75+
echo "::notice::eslint.seatbelt.tsv unchanged; skipping auto-commit."
76+
else
77+
echo "tightened=true" >> "$GITHUB_OUTPUT"
78+
fi
79+
80+
- name: Setup git for OSBotify
81+
if: steps.seatbelt_diff.outputs.tightened == 'true'
82+
uses: Expensify/GitHub-Actions/setupGitForOSBotify@main
83+
with:
84+
OP_VAULT: ${{ vars.OP_VAULT }}
85+
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
86+
SETUP_AS_APP: false
87+
88+
# If the push races with another commit to `main`, let this step fail.
89+
# The next `push: main` lint run will re-tighten the baseline and try
90+
# again; no need to retry here.
91+
- name: Auto-commit tightened eslint-seatbelt baseline
92+
if: steps.seatbelt_diff.outputs.tightened == 'true'
93+
continue-on-error: true
94+
run: |
95+
git add config/eslint/eslint.seatbelt.tsv
96+
git commit -m "Auto-tighten eslint-seatbelt baseline"
97+
git push origin main

.github/workflows/preDeploy.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ jobs:
1212

1313
lint:
1414
uses: ./.github/workflows/lint.yml
15+
secrets: inherit
1516

1617
prettier:
1718
uses: ./.github/workflows/prettier.yml

.github/workflows/test.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@ jobs:
3131
- name: Setup Node
3232
uses: ./.github/actions/composite/setupNode
3333

34-
- name: Get number of CPU cores
35-
id: cpu-cores
36-
uses: SimenB/github-actions-cpu-cores@31e91de0f8654375a21e8e83078be625380e2b18
37-
3834
- name: Cache Jest cache
3935
id: cache-jest-cache
4036
# v5.0.1

CLAUDE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,14 +185,14 @@ The skill provides guidance on:
185185

186186
### Code Quality
187187
- **TypeScript**: Strict mode enabled
188-
- **ESLint**: Linter
188+
- **ESLint**: Linter. Pre-existing violations are grandfathered via [`eslint-seatbelt`](https://github.com/justjake/eslint-seatbelt).
189189
- **Prettier**: Code formatting - run `npm run prettier` after making changes
190190
- **Patch Management**: patch-package for dependency fixes
191191

192192
### Post-Edit Checklist (IMPORTANT)
193193
**ALWAYS run these steps after making code changes, before committing:**
194194
1. **Prettier**: Run `npx prettier --write <changed files>` on every file you modified. This is mandatory - CI will reject unformatted code.
195-
2. **ESLint**: Run `npx eslint <changed files> --max-warnings=0` to catch lint errors early.
195+
2. **ESLint**: Run `npm run lint-changed` to catch lint errors early.
196196
3. **TypeScript**: Run `npm run typecheck-tsgo` after changes that may affect typing (types, interfaces, or function signatures). It is ~10x faster and usually stricter than tsc. CI validates with `npm run typecheck` (tsc), which remains the required merge gate.
197197
4. **React Compiler**: If you added new React components/hooks or modified existing ones, run `npm run react-compiler-compliance-check check-changed` to verify they compile with React Compiler. This applies the same rules as CI: new components/hooks must compile, and existing compiled files must not regress. See `contributingGuides/REACT_COMPILER.md` for details and common fixes.
198198

0 commit comments

Comments
 (0)