Skip to content

Commit 9fb663b

Browse files
committed
build actions with new PR comment logic
1 parent 6b487d2 commit 9fb663b

3 files changed

Lines changed: 155 additions & 149 deletions

File tree

.github/actions/javascript/getDeployPullRequestList/index.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11622,6 +11622,23 @@ async function run() {
1162211622
const prList = await GitUtils_1.default.getPullRequestsDeployedBetween(priorTag, inputTag, CONST_1.default.APP_REPO);
1162311623
console.log('Found the pull request list: ', prList);
1162411624
core.setOutput('PR_LIST', prList);
11625+
// Get Mobile-Expensify PRs deployed between the same tags
11626+
let mobileExpensifyPRList = [];
11627+
try {
11628+
mobileExpensifyPRList = await GitUtils_1.default.getPullRequestsDeployedBetween(priorTag, inputTag, CONST_1.default.MOBILE_EXPENSIFY_REPO);
11629+
console.log('Found Mobile-Expensify pull request list: ', mobileExpensifyPRList);
11630+
}
11631+
catch (error) {
11632+
// Check if this is a forked repository
11633+
if (process.env.GITHUB_REPOSITORY !== 'Expensify/App') {
11634+
console.warn("⚠️ Unable to fetch Mobile-Expensify PRs because this workflow is running on a forked repository and secrets aren't accessible. This is expected for development/testing on forks.");
11635+
}
11636+
else {
11637+
console.error('Failed to fetch Mobile-Expensify PRs from main repository:', error);
11638+
// Don't fail the entire workflow, just skip Mobile-Expensify PRs
11639+
}
11640+
}
11641+
core.setOutput('MOBILE_EXPENSIFY_PR_LIST', mobileExpensifyPRList);
1162511642
}
1162611643
catch (error) {
1162711644
console.error(error.message);

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

Lines changed: 71 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -12761,25 +12761,71 @@ function getDeployTableMessage(platformResult) {
1276112761
return `${platformResult} ❌`;
1276212762
}
1276312763
}
12764-
/**
12765-
* Comment Single PR
12766-
*/
12767-
async function commentPR(PR, message) {
12764+
async function commentPR(PR, message, repo = github_1.context.repo.repo) {
1276812765
try {
12769-
await GithubUtils_1.default.createComment(github_1.context.repo.repo, PR, message);
12770-
console.log(`Comment created on #${PR} successfully 🎉`);
12766+
await GithubUtils_1.default.createComment(repo, PR, message);
12767+
console.log(`Comment created on ${repo}#${PR} successfully 🎉`);
1277112768
}
1277212769
catch (err) {
12773-
console.log(`Unable to write comment on #${PR} 😞`);
12770+
console.log(`Unable to write comment on ${repo}#${PR} 😞`);
1277412771
if (err instanceof Error) {
1277512772
core.setFailed(err.message);
1277612773
}
1277712774
}
1277812775
}
1277912776
const workflowURL = `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`;
1278012777
const getCommit = (0, memoize_1.default)(GithubUtils_1.default.octokit.git.getCommit);
12778+
/**
12779+
* Process staging deploy comments for a list of PRs
12780+
*/
12781+
async function commentStagingDeployPRs(prList, repoName, recentTags, getDeployMessage) {
12782+
for (const prNumber of prList) {
12783+
try {
12784+
const { data: pr } = await GithubUtils_1.default.octokit.pulls.get({
12785+
owner: CONST_1.default.GITHUB_OWNER,
12786+
repo: repoName,
12787+
pull_number: prNumber,
12788+
});
12789+
// Find the deployer: either the merger, or for CPs, the tag creator
12790+
const isCP = pr.labels.some(({ name: labelName }) => labelName === CONST_1.default.LABELS.CP_STAGING);
12791+
let deployer = pr.merged_by?.login;
12792+
if (isCP) {
12793+
for (const tag of recentTags) {
12794+
const { data: commit } = await getCommit({
12795+
owner: CONST_1.default.GITHUB_OWNER,
12796+
repo: repoName,
12797+
commit_sha: tag.commit.sha,
12798+
});
12799+
const prNumForCPMergeCommit = commit.message.match(/Merge pull request #(\d+)[\S\s]*\(cherry picked from commit .*\)/);
12800+
if (prNumForCPMergeCommit?.at(1) === String(prNumber)) {
12801+
const cpActor = commit.message.match(/.*\(cherry-picked to .* by (.*)\)/)?.at(1);
12802+
if (cpActor) {
12803+
deployer = cpActor;
12804+
}
12805+
break;
12806+
}
12807+
}
12808+
}
12809+
const title = pr.title;
12810+
const deployMessage = deployer ? getDeployMessage(deployer, isCP ? 'Cherry-picked' : 'Deployed', title) : '';
12811+
await commentPR(prNumber, deployMessage, repoName);
12812+
}
12813+
catch (error) {
12814+
if (error.status === 404) {
12815+
console.log(`Unable to comment on ${repoName} PR #${prNumber}. GitHub responded with 404.`);
12816+
}
12817+
else if (repoName === CONST_1.default.MOBILE_EXPENSIFY_REPO && process.env.GITHUB_REPOSITORY !== 'Expensify/App') {
12818+
console.warn(`Unable to comment on ${repoName} PR #${prNumber} from forked repository. This is expected.`);
12819+
}
12820+
else {
12821+
throw error;
12822+
}
12823+
}
12824+
}
12825+
}
1278112826
async function run() {
1278212827
const prList = ActionUtils.getJSONInput('PR_LIST', { required: true }).map((num) => Number.parseInt(num, 10));
12828+
const mobileExpensifyPRList = ActionUtils.getJSONInput('MOBILE_EXPENSIFY_PR_LIST', { required: false })?.map((num) => Number.parseInt(num, 10)) ?? [];
1278312829
const isProd = ActionUtils.getJSONInput('IS_PRODUCTION_DEPLOY', { required: true });
1278412830
const version = core.getInput('DEPLOY_VERSION', { required: true });
1278512831
const androidResult = getDeployTableMessage(core.getInput('ANDROID', { required: true }));
@@ -12827,60 +12873,40 @@ async function run() {
1282712873
for (const pr of prList) {
1282812874
await commentPR(pr, deployMessage);
1282912875
}
12876+
// Comment on Mobile-Expensify PRs as well
12877+
for (const pr of mobileExpensifyPRList) {
12878+
await commentPR(pr, deployMessage, CONST_1.default.MOBILE_EXPENSIFY_REPO);
12879+
}
1283012880
return;
1283112881
}
12832-
const { data: recentTags } = await GithubUtils_1.default.octokit.repos.listTags({
12882+
const { data: appRecentTags } = await GithubUtils_1.default.octokit.repos.listTags({
1283312883
owner: CONST_1.default.GITHUB_OWNER,
1283412884
repo: CONST_1.default.APP_REPO,
1283512885
per_page: 100,
1283612886
});
12837-
for (const prNumber of prList) {
12838-
/*
12839-
* Determine who the deployer for the PR is. The "deployer" for staging deploys is:
12840-
* 1. For regular staging deploys, the person who merged the PR.
12841-
* 2. For CPs, the person who committed the cherry-picked commit (not necessarily the author of the commit).
12842-
*/
12887+
// Only fetch Mobile-Expensify tags if there are Mobile-Expensify PRs
12888+
let mobileExpensifyRecentTags = [];
12889+
if (mobileExpensifyPRList.length > 0) {
1284312890
try {
12844-
const { data: pr } = await GithubUtils_1.default.octokit.pulls.get({
12891+
const response = await GithubUtils_1.default.octokit.repos.listTags({
1284512892
owner: CONST_1.default.GITHUB_OWNER,
12846-
repo: CONST_1.default.APP_REPO,
12847-
pull_number: prNumber,
12893+
repo: CONST_1.default.MOBILE_EXPENSIFY_REPO,
12894+
per_page: 100,
1284812895
});
12849-
// Check for the CP Staging label on the issue to see if it was cherry-picked
12850-
const isCP = pr.labels.some(({ name: labelName }) => labelName === CONST_1.default.LABELS.CP_STAGING);
12851-
// Determine the deployer. For most PRs it will be whoever merged the PR.
12852-
// For CPs it will be whoever created the tag for the PR (i.e: whoever triggered the CP)
12853-
let deployer = pr.merged_by?.login;
12854-
if (isCP) {
12855-
for (const tag of recentTags) {
12856-
const { data: commit } = await getCommit({
12857-
owner: CONST_1.default.GITHUB_OWNER,
12858-
repo: CONST_1.default.APP_REPO,
12859-
commit_sha: tag.commit.sha,
12860-
});
12861-
const prNumForCPMergeCommit = commit.message.match(/Merge pull request #(\d+)[\S\s]*\(cherry picked from commit .*\)/);
12862-
if (prNumForCPMergeCommit?.at(1) === String(prNumber)) {
12863-
const cpActor = commit.message.match(/.*\(cherry-picked to .* by (.*)\)/)?.at(1);
12864-
if (cpActor) {
12865-
deployer = cpActor;
12866-
}
12867-
break;
12868-
}
12869-
}
12870-
}
12871-
const title = pr.title;
12872-
const deployMessage = deployer ? getDeployMessage(deployer, isCP ? 'Cherry-picked' : 'Deployed', title) : '';
12873-
await commentPR(prNumber, deployMessage);
12896+
mobileExpensifyRecentTags = response.data;
1287412897
}
1287512898
catch (error) {
12876-
if (error.status === 404) {
12877-
console.log(`Unable to comment on PR #${prNumber}. GitHub responded with 404.`);
12899+
if (process.env.GITHUB_REPOSITORY !== 'Expensify/App') {
12900+
console.warn('Unable to fetch Mobile-Expensify tags from forked repository. This is expected.');
1287812901
}
1287912902
else {
12880-
throw error;
12903+
console.error('Failed to fetch Mobile-Expensify tags:', error);
1288112904
}
1288212905
}
1288312906
}
12907+
// Comment on the PRs
12908+
await commentStagingDeployPRs(prList, CONST_1.default.APP_REPO, appRecentTags, getDeployMessage);
12909+
await commentStagingDeployPRs(mobileExpensifyPRList, CONST_1.default.MOBILE_EXPENSIFY_REPO, mobileExpensifyRecentTags, getDeployMessage);
1288412910
}
1288512911
if (require.main === require.cache[eval('__filename')]) {
1288612912
run();

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

Lines changed: 67 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,59 @@ const workflowURL = `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOS
4242

4343
const getCommit = memoize(GithubUtils.octokit.git.getCommit);
4444

45+
/**
46+
* Process staging deploy comments for a list of PRs
47+
*/
48+
async function commentStagingDeployPRs(
49+
prList: number[],
50+
repoName: string,
51+
recentTags: Awaited<ReturnType<typeof GithubUtils.octokit.repos.listTags>>['data'],
52+
getDeployMessage: (deployer: string, deployVerb: string, prTitle?: string) => string,
53+
) {
54+
for (const prNumber of prList) {
55+
try {
56+
const {data: pr} = await GithubUtils.octokit.pulls.get({
57+
owner: CONST.GITHUB_OWNER,
58+
repo: repoName,
59+
pull_number: prNumber,
60+
});
61+
62+
// Find the deployer: either the merger, or for CPs, the tag creator
63+
const isCP = pr.labels.some(({name: labelName}) => labelName === CONST.LABELS.CP_STAGING);
64+
let deployer = pr.merged_by?.login;
65+
if (isCP) {
66+
for (const tag of recentTags) {
67+
const {data: commit} = await getCommit({
68+
owner: CONST.GITHUB_OWNER,
69+
repo: repoName,
70+
commit_sha: tag.commit.sha,
71+
});
72+
const prNumForCPMergeCommit = commit.message.match(/Merge pull request #(\d+)[\S\s]*\(cherry picked from commit .*\)/);
73+
if (prNumForCPMergeCommit?.at(1) === String(prNumber)) {
74+
const cpActor = commit.message.match(/.*\(cherry-picked to .* by (.*)\)/)?.at(1);
75+
if (cpActor) {
76+
deployer = cpActor;
77+
}
78+
break;
79+
}
80+
}
81+
}
82+
83+
const title = pr.title;
84+
const deployMessage = deployer ? getDeployMessage(deployer, isCP ? 'Cherry-picked' : 'Deployed', title) : '';
85+
await commentPR(prNumber, deployMessage, repoName);
86+
} catch (error) {
87+
if ((error as RequestError).status === 404) {
88+
console.log(`Unable to comment on ${repoName} PR #${prNumber}. GitHub responded with 404.`);
89+
} else if (repoName === CONST.MOBILE_EXPENSIFY_REPO && process.env.GITHUB_REPOSITORY !== 'Expensify/App') {
90+
console.warn(`Unable to comment on ${repoName} PR #${prNumber} from forked repository. This is expected.`);
91+
} else {
92+
throw error;
93+
}
94+
}
95+
}
96+
}
97+
4598
async function run() {
4699
const prList = (ActionUtils.getJSONInput('PR_LIST', {required: true}) as string[]).map((num) => Number.parseInt(num, 10));
47100
const mobileExpensifyPRList = (ActionUtils.getJSONInput('MOBILE_EXPENSIFY_PR_LIST', {required: false}) as string[] | undefined)?.map((num) => Number.parseInt(num, 10)) ?? [];
@@ -109,124 +162,34 @@ async function run() {
109162
return;
110163
}
111164

112-
const {data: recentTags} = await GithubUtils.octokit.repos.listTags({
165+
const {data: appRecentTags} = await GithubUtils.octokit.repos.listTags({
113166
owner: CONST.GITHUB_OWNER,
114167
repo: CONST.APP_REPO,
115168
per_page: 100,
116169
});
117170

118-
for (const prNumber of prList) {
119-
/*
120-
* Determine who the deployer for the PR is. The "deployer" for staging deploys is:
121-
* 1. For regular staging deploys, the person who merged the PR.
122-
* 2. For CPs, the person who committed the cherry-picked commit (not necessarily the author of the commit).
123-
*/
171+
// Only fetch Mobile-Expensify tags if there are Mobile-Expensify PRs
172+
let mobileExpensifyRecentTags: typeof appRecentTags = [];
173+
if (mobileExpensifyPRList.length > 0) {
124174
try {
125-
const {data: pr} = await GithubUtils.octokit.pulls.get({
126-
owner: CONST.GITHUB_OWNER,
127-
repo: CONST.APP_REPO,
128-
pull_number: prNumber,
129-
});
130-
131-
// Check for the CP Staging label on the issue to see if it was cherry-picked
132-
const isCP = pr.labels.some(({name: labelName}) => labelName === CONST.LABELS.CP_STAGING);
133-
134-
// Determine the deployer. For most PRs it will be whoever merged the PR.
135-
// For CPs it will be whoever created the tag for the PR (i.e: whoever triggered the CP)
136-
let deployer = pr.merged_by?.login;
137-
if (isCP) {
138-
for (const tag of recentTags) {
139-
const {data: commit} = await getCommit({
140-
owner: CONST.GITHUB_OWNER,
141-
repo: CONST.APP_REPO,
142-
commit_sha: tag.commit.sha,
143-
});
144-
const prNumForCPMergeCommit = commit.message.match(/Merge pull request #(\d+)[\S\s]*\(cherry picked from commit .*\)/);
145-
if (prNumForCPMergeCommit?.at(1) === String(prNumber)) {
146-
const cpActor = commit.message.match(/.*\(cherry-picked to .* by (.*)\)/)?.at(1);
147-
if (cpActor) {
148-
deployer = cpActor;
149-
}
150-
break;
151-
}
152-
}
153-
}
154-
155-
const title = pr.title;
156-
const deployMessage = deployer ? getDeployMessage(deployer, isCP ? 'Cherry-picked' : 'Deployed', title) : '';
157-
await commentPR(prNumber, deployMessage);
158-
} catch (error) {
159-
if ((error as RequestError).status === 404) {
160-
console.log(`Unable to comment on PR #${prNumber}. GitHub responded with 404.`);
161-
} else {
162-
throw error;
163-
}
164-
}
165-
}
166-
167-
// Handle Mobile-Expensify PRs for staging deploys
168-
// Note: We'll need to fetch tags from Mobile-Expensify repo for cherry-pick detection
169-
let mobileExpensifyRecentTags: typeof recentTags = [];
170-
try {
171-
const response = await GithubUtils.octokit.repos.listTags({
172-
owner: CONST.GITHUB_OWNER,
173-
repo: CONST.MOBILE_EXPENSIFY_REPO,
174-
per_page: 100,
175-
});
176-
mobileExpensifyRecentTags = response.data;
177-
} catch (error) {
178-
if (process.env.GITHUB_REPOSITORY !== 'Expensify/App') {
179-
console.warn('Unable to fetch Mobile-Expensify tags from forked repository. This is expected.');
180-
} else {
181-
console.error('Failed to fetch Mobile-Expensify tags:', error);
182-
}
183-
}
184-
185-
for (const prNumber of mobileExpensifyPRList) {
186-
try {
187-
const {data: pr} = await GithubUtils.octokit.pulls.get({
175+
const response = await GithubUtils.octokit.repos.listTags({
188176
owner: CONST.GITHUB_OWNER,
189177
repo: CONST.MOBILE_EXPENSIFY_REPO,
190-
pull_number: prNumber,
178+
per_page: 100,
191179
});
192-
193-
// Check for the CP Staging label on the issue to see if it was cherry-picked
194-
const isCP = pr.labels.some(({name: labelName}) => labelName === CONST.LABELS.CP_STAGING);
195-
196-
// Determine the deployer. For most PRs it will be whoever merged the PR.
197-
// For CPs it will be whoever created the tag for the PR (i.e: whoever triggered the CP)
198-
let deployer = pr.merged_by?.login;
199-
if (isCP) {
200-
for (const tag of mobileExpensifyRecentTags) {
201-
const {data: commit} = await getCommit({
202-
owner: CONST.GITHUB_OWNER,
203-
repo: CONST.MOBILE_EXPENSIFY_REPO,
204-
commit_sha: tag.commit.sha,
205-
});
206-
const prNumForCPMergeCommit = commit.message.match(/Merge pull request #(\d+)[\S\s]*\(cherry picked from commit .*\)/);
207-
if (prNumForCPMergeCommit?.at(1) === String(prNumber)) {
208-
const cpActor = commit.message.match(/.*\(cherry-picked to .* by (.*)\)/)?.at(1);
209-
if (cpActor) {
210-
deployer = cpActor;
211-
}
212-
break;
213-
}
214-
}
215-
}
216-
217-
const title = pr.title;
218-
const deployMessage = deployer ? getDeployMessage(deployer, isCP ? 'Cherry-picked' : 'Deployed', title) : '';
219-
await commentPR(prNumber, deployMessage, CONST.MOBILE_EXPENSIFY_REPO);
180+
mobileExpensifyRecentTags = response.data;
220181
} catch (error) {
221-
if ((error as RequestError).status === 404) {
222-
console.log(`Unable to comment on Mobile-Expensify PR #${prNumber}. GitHub responded with 404.`);
223-
} else if (process.env.GITHUB_REPOSITORY !== 'Expensify/App') {
224-
console.warn(`Unable to comment on Mobile-Expensify PR #${prNumber} from forked repository. This is expected.`);
182+
if (process.env.GITHUB_REPOSITORY !== 'Expensify/App') {
183+
console.warn('Unable to fetch Mobile-Expensify tags from forked repository. This is expected.');
225184
} else {
226-
throw error;
185+
console.error('Failed to fetch Mobile-Expensify tags:', error);
227186
}
228187
}
229188
}
189+
190+
// Comment on the PRs
191+
await commentStagingDeployPRs(prList, CONST.APP_REPO, appRecentTags, getDeployMessage);
192+
await commentStagingDeployPRs(mobileExpensifyPRList, CONST.MOBILE_EXPENSIFY_REPO, mobileExpensifyRecentTags, getDeployMessage);
230193
}
231194

232195
if (require.main === module) {

0 commit comments

Comments
 (0)