-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
343 changed files
with
52,396 additions
and
30,833 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
--- | ||
name: New Library Request | ||
about: Use this when you want to propose adding a new library to package.json (dev-dependencies excluded) | ||
labels: Weekly, AutoAssignerAppLibraryReview | ||
--- | ||
In order to properly evaluate if a new library can be added to `package.json`, please fill out this request form. It will be automatically assigned someone from our review team that will go through and vet the library. | ||
|
||
Note: This is only for production dependencies. While we don't want people to add packages to dev-dependencies willy-nilly, we recognize that there isn't as great of a need there to secure them. | ||
|
||
# Name of library: | ||
|
||
## Details | ||
- Link to package: | ||
- Problem solved by using this package: | ||
- Number of stars in GH: | ||
- Number of monthly downloads: | ||
- Number of releases in the last year: | ||
- Level of activity in the repo: | ||
- Alternatives: | ||
- Are security concerns brought up and addressed in the library's repo? | ||
- How many dependencies does this lib use that will be brought into our code? | ||
- What will the effect be on the bundle size of our code? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
name: Build an Android apk | ||
description: Build an Android apk for an E2E test build and upload it as an artifact | ||
|
||
inputs: | ||
ARTIFACT_NAME: | ||
description: The name of the workflow artifact where the APK should be uploaded | ||
required: true | ||
|
||
runs: | ||
using: composite | ||
steps: | ||
- uses: Expensify/App/.github/actions/composite/setupNode@main | ||
|
||
- uses: ruby/setup-ruby@a05e47355e80e57b9a67566a813648fa67d92011 | ||
with: | ||
ruby-version: "2.7" | ||
bundler-cache: true | ||
|
||
- uses: gradle/gradle-build-action@3fbe033aaae657f011f88f29be9e65ed26bd29ef | ||
|
||
- name: Build APK | ||
run: npm run android-build-e2edelta | ||
shell: bash | ||
|
||
- name: Upload APK | ||
uses: actions/upload-artifact@65d862660abb392b8c4a3d1195a2108db131dd05 | ||
with: | ||
name: ${{ inputs.ARTIFACT_NAME }} | ||
path: android/app/build/outputs/apk/e2e/release/app-e2edelta-release.apk |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
67 changes: 0 additions & 67 deletions
67
.github/actions/javascript/authorChecklist/authorChecklist.js
This file was deleted.
Oops, something went wrong.
163 changes: 163 additions & 0 deletions
163
.github/actions/javascript/authorChecklist/authorChecklist.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
import * as core from '@actions/core'; | ||
import * as github from '@actions/github'; | ||
import escapeRegExp from 'lodash/escapeRegExp'; | ||
import CONST from '../../../libs/CONST'; | ||
import GithubUtils from '../../../libs/GithubUtils'; | ||
import newComponentCategory from './categories/newComponentCategory'; | ||
|
||
const pathToAuthorChecklist = `https://raw.githubusercontent.com/${CONST.GITHUB_OWNER}/${CONST.APP_REPO}/main/.github/PULL_REQUEST_TEMPLATE.md`; | ||
const checklistStartsWith = '### PR Author Checklist'; | ||
const checklistEndsWith = '\r\n### Screenshots/Videos'; | ||
|
||
const prNumber = github.context.payload.pull_request?.number; | ||
|
||
const CHECKLIST_CATEGORIES = { | ||
NEW_COMPONENT: newComponentCategory, | ||
}; | ||
|
||
/** | ||
* Look at the contents of the pull request, and determine which checklist categories apply. | ||
*/ | ||
async function getChecklistCategoriesForPullRequest(): Promise<Set<string>> { | ||
const checks = new Set<string>(); | ||
const changedFiles = await GithubUtils.paginate(GithubUtils.octokit.pulls.listFiles, { | ||
owner: CONST.GITHUB_OWNER, | ||
repo: CONST.APP_REPO, | ||
// eslint-disable-next-line @typescript-eslint/naming-convention | ||
pull_number: prNumber, | ||
// eslint-disable-next-line @typescript-eslint/naming-convention | ||
per_page: 100, | ||
}); | ||
const possibleCategories = await Promise.all( | ||
Object.values(CHECKLIST_CATEGORIES).map(async (category) => ({ | ||
items: category.items, | ||
doesCategoryApply: await category.detect(changedFiles), | ||
})), | ||
); | ||
for (const category of possibleCategories) { | ||
if (category.doesCategoryApply) { | ||
for (const item of category.items) { | ||
checks.add(item); | ||
} | ||
} | ||
} | ||
return checks; | ||
} | ||
|
||
function partitionWithChecklist(body: string): string[] { | ||
const [contentBeforeChecklist, contentAfterStartOfChecklist] = body.split(checklistStartsWith); | ||
const [checklistContent, contentAfterChecklist] = contentAfterStartOfChecklist.split(checklistEndsWith); | ||
return [contentBeforeChecklist, checklistContent, contentAfterChecklist]; | ||
} | ||
|
||
async function getNumberOfItemsFromAuthorChecklist(): Promise<number> { | ||
const response = await fetch(pathToAuthorChecklist); | ||
const fileContents = await response.text(); | ||
const checklist = partitionWithChecklist(fileContents)[1]; | ||
const numberOfChecklistItems = (checklist.match(/\[ \]/g) ?? []).length; | ||
return numberOfChecklistItems; | ||
} | ||
|
||
function checkPRForCompletedChecklist(expectedNumberOfChecklistItems: number, checklist: string) { | ||
const numberOfFinishedChecklistItems = (checklist.match(/- \[x\]/gi) ?? []).length; | ||
const numberOfUnfinishedChecklistItems = (checklist.match(/- \[ \]/g) ?? []).length; | ||
|
||
const minCompletedItems = expectedNumberOfChecklistItems - 2; | ||
|
||
console.log(`You completed ${numberOfFinishedChecklistItems} out of ${expectedNumberOfChecklistItems} checklist items with ${numberOfUnfinishedChecklistItems} unfinished items`); | ||
|
||
if (numberOfFinishedChecklistItems >= minCompletedItems && numberOfUnfinishedChecklistItems === 0) { | ||
console.log('PR Author checklist is complete 🎉'); | ||
return; | ||
} | ||
|
||
console.log(`Make sure you are using the most up to date checklist found here: ${pathToAuthorChecklist}`); | ||
core.setFailed("PR Author Checklist is not completely filled out. Please check every box to verify you've thought about the item."); | ||
} | ||
|
||
async function generateDynamicChecksAndCheckForCompletion() { | ||
// Generate dynamic checks | ||
console.log('Generating dynamic checks...'); | ||
const dynamicChecks = await getChecklistCategoriesForPullRequest(); | ||
let isPassing = true; | ||
let didChecklistChange = false; | ||
|
||
const body = github.context.payload.pull_request?.body ?? ''; | ||
|
||
// eslint-disable-next-line prefer-const | ||
let [contentBeforeChecklist, checklist, contentAfterChecklist] = partitionWithChecklist(body); | ||
|
||
for (const check of dynamicChecks) { | ||
// Check if it's already in the PR body, capturing the whether or not it's already checked | ||
const regex = new RegExp(`- \\[([ x])] ${escapeRegExp(check)}`); | ||
const match = regex.exec(checklist); | ||
if (!match) { | ||
console.log('Adding check to the checklist:', check); | ||
// Add it to the PR body | ||
isPassing = false; | ||
checklist += `- [ ] ${check}\r\n`; | ||
didChecklistChange = true; | ||
} else { | ||
const isChecked = match[1] === 'x'; | ||
if (!isChecked) { | ||
console.log('Found unchecked checklist item:', check); | ||
isPassing = false; | ||
} | ||
} | ||
} | ||
|
||
// Check if some dynamic check was added with previous commit, but is not relevant anymore | ||
const allChecks = Object.values(CHECKLIST_CATEGORIES).reduce((acc: string[], category) => acc.concat(category.items), []); | ||
|
||
for (const check of allChecks) { | ||
if (!dynamicChecks.has(check)) { | ||
const regex = new RegExp(`- \\[([ x])] ${escapeRegExp(check)}\r\n`); | ||
const match = regex.exec(checklist); | ||
if (match) { | ||
// Remove it from the PR body | ||
console.log('Check has been removed from the checklist:', check); | ||
checklist = checklist.replace(match[0], ''); | ||
didChecklistChange = true; | ||
} | ||
} | ||
} | ||
|
||
// Put the PR body back together, need to add the markers back in | ||
const newBody = contentBeforeChecklist + checklistStartsWith + checklist + checklistEndsWith + contentAfterChecklist; | ||
|
||
// Update the PR body | ||
if (didChecklistChange) { | ||
console.log('Checklist changed, updating PR...'); | ||
await GithubUtils.octokit.pulls.update({ | ||
owner: CONST.GITHUB_OWNER, | ||
repo: CONST.APP_REPO, | ||
// eslint-disable-next-line @typescript-eslint/naming-convention | ||
pull_number: prNumber, | ||
body: newBody, | ||
}); | ||
console.log('Updated PR checklist'); | ||
} | ||
|
||
if (!isPassing) { | ||
const err = new Error("New checks were added into checklist. Please check every box to verify you've thought about the item."); | ||
console.error(err); | ||
core.setFailed(err); | ||
} | ||
|
||
// check for completion | ||
try { | ||
const numberOfItems = await getNumberOfItemsFromAuthorChecklist(); | ||
checkPRForCompletedChecklist(numberOfItems, checklist); | ||
} catch (error) { | ||
console.error(error); | ||
if (error instanceof Error) { | ||
core.setFailed(error.message); | ||
} | ||
} | ||
} | ||
|
||
if (require.main === module) { | ||
generateDynamicChecksAndCheckForCompletion(); | ||
} | ||
|
||
export default generateDynamicChecksAndCheckForCompletion; |
6 changes: 6 additions & 0 deletions
6
.github/actions/javascript/authorChecklist/categories/Category.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
type Category = { | ||
detect: (changedFiles: Array<{filename: string; status: string}>) => Promise<boolean>; | ||
items: string[]; | ||
}; | ||
|
||
export default Category; |
6 changes: 6 additions & 0 deletions
6
.github/actions/javascript/authorChecklist/categories/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import Category from './Category'; | ||
import newComponent from './newComponentCategory'; | ||
|
||
const categories: Category[] = [newComponent]; | ||
|
||
export default categories; |
Oops, something went wrong.