11import { existsSync , rmSync } from 'node:fs'
22import { Octokit } from '@octokit/rest'
33
4- import { cherryPickCommits , cloneAndCacheRepo , hasDiff , hasEmptyCommits , hasSkipCiCommits , pushBranch } from './gitUtils'
5- import { CherryPickResult , Task } from './constants'
6- import { debug , error , info , warn } from './logUtils'
7- import { Reaction , addReaction , getAuthToken , getAvailableLabels , getLabelsFromPR , getAvailableMilestones , requestReviewers , getReviewers , createBackportPullRequest , setPRLabels , setPRMilestone , getChangesFromPR , updatePRBody , commentOnPR , assignToPR } from './githubUtils'
8- import { getBackportBody , getFailureCommentBody , getLabelsForPR , getMilestoneFromBase } from './nextcloudUtils'
9-
10- export const backport = ( task : Task ) => new Promise < void > ( ( resolve , reject ) => {
11- getAuthToken ( task . installationId ) . then ( async token => {
12- const octokit = new Octokit ( { auth : token } )
13-
14- let tmpDir : string = ''
15- let prNumber : number = 0
16- let conflicts : CherryPickResult | null = null
17- const backportBranch = `backport/${ task . prNumber } /${ task . branch } `
18-
19- info ( task , `Starting backport request` )
20-
21- // Add a reaction to the comment to indicate that we're processing it
4+ import { cherryPickCommits , cloneAndCacheRepo , hasDiff , hasEmptyCommits , hasSkipCiCommits , pushBranch } from './gitUtils.js'
5+ import { CherryPickResult , Task } from './constants.js'
6+ import { debug , error , info , warn } from './logUtils.js'
7+ import { Reaction , addReaction , getAuthToken , getAvailableLabels , getLabelsFromPR , getAvailableMilestones , requestReviewers , getReviewers , createBackportPullRequest , setPRLabels , setPRMilestone , getChangesFromPR , updatePRBody , commentOnPR , assignToPR } from './githubUtils.js'
8+ import { getBackportBody , getFailureCommentBody , getLabelsForPR , getMilestoneFromBase } from './nextcloudUtils.js'
9+
10+ export async function backport ( task : Task ) : Promise < void > {
11+ const token = await getAuthToken ( task . installationId )
12+ const octokit = new Octokit ( { auth : token } )
13+
14+ let tmpDir : string = ''
15+ let prNumber : number = 0
16+ let conflicts : CherryPickResult | null = null
17+ const backportBranch = `backport/${ task . prNumber } /${ task . branch } `
18+
19+ info ( task , `Starting backport request` )
20+
21+ // Add a reaction to the comment to indicate that we're processing it
22+ try {
23+ await addReaction ( octokit , task , Reaction . THUMBS_UP )
24+ } catch ( e ) {
25+ error ( task , `Failed to add reaction to PR: ${ e . message } ` )
26+ // continue, this is not a fatal error
27+ }
28+
29+ try {
30+ // Clone and cache the repo
2231 try {
23- await addReaction ( octokit , task , Reaction . THUMBS_UP )
32+ tmpDir = await cloneAndCacheRepo ( task , backportBranch )
33+ info ( task , `Cloned to ${ tmpDir } ` )
2434 } catch ( e ) {
25- error ( task , `Failed to add reaction to PR: ${ e . message } ` )
26- // continue, this is not a fatal error
35+ throw new Error ( `Failed to clone repository: ${ e . message } ` )
2736 }
2837
38+ // Cherry pick the commits
2939 try {
30- // Clone and cache the repo
31- try {
32- tmpDir = await cloneAndCacheRepo ( task , backportBranch )
33- info ( task , `Cloned to ${ tmpDir } ` )
34- } catch ( e ) {
35- throw new Error ( `Failed to clone repository: ${ e . message } ` )
40+ conflicts = await cherryPickCommits ( task , tmpDir )
41+ if ( conflicts === CherryPickResult . CONFLICTS ) {
42+ warn ( task , `Cherry picking commits resulted in conflicts` )
43+ } else {
44+ info ( task , `Cherry picking commits successful` )
3645 }
46+ } catch ( e ) {
47+ throw new Error ( `Failed to cherry pick commits: ${ e . message } ` )
48+ }
3749
38- // Cherry pick the commits
39- try {
40- conflicts = await cherryPickCommits ( task , tmpDir )
41- if ( conflicts === CherryPickResult . CONFLICTS ) {
42- warn ( task , `Cherry picking commits resulted in conflicts` )
43- } else {
44- info ( task , `Cherry picking commits successful` )
45- }
46- } catch ( e ) {
47- throw new Error ( `Failed to cherry pick commits: ${ e . message } ` )
48- }
50+ // Check if there are any changes to backport
51+ const hasChanges = await hasDiff ( tmpDir , task . branch , backportBranch , task )
52+ if ( ! hasChanges ) {
53+ throw new Error ( `No changes found in backport branch` )
54+ }
4955
50- // Check if there are any changes to backport
51- const hasChanges = await hasDiff ( tmpDir , task . branch , backportBranch , task )
52- if ( ! hasChanges ) {
53- throw new Error ( `No changes found in backport branch` )
54- }
56+ // Push the branch
57+ try {
58+ await pushBranch ( task , tmpDir , token , backportBranch )
59+ info ( task , `Pushed branch ${ backportBranch } ` )
60+ } catch ( e ) {
61+ throw new Error ( `Failed to push branch ${ backportBranch } : ${ e . message } ` )
62+ }
5563
56- // Push the branch
57- try {
58- await pushBranch ( task , tmpDir , token , backportBranch )
59- info ( task , `Pushed branch ${ backportBranch } ` )
60- } catch ( e ) {
61- throw new Error ( `Failed to push branch ${ backportBranch } : ${ e . message } ` )
62- }
64+ // Create the pull request
65+ try {
66+ const reviewers = await getReviewers ( octokit , task )
67+ const prCreationResult = await createBackportPullRequest ( octokit , task , backportBranch , conflicts === CherryPickResult . CONFLICTS )
68+ prNumber = prCreationResult . data . number
69+ info ( task , `Opened Pull Request #${ prNumber } on ${ prCreationResult . data . html_url } ` )
6370
64- // Create the pull request
6571 try {
66- const reviewers = await getReviewers ( octokit , task )
67- const prCreationResult = await createBackportPullRequest ( octokit , task , backportBranch , conflicts === CherryPickResult . CONFLICTS )
68- prNumber = prCreationResult . data . number
69- info ( task , `Opened Pull Request #${ prNumber } on ${ prCreationResult . data . html_url } ` )
70-
71- try {
72- // Ask for reviews from all reviewers of the original PR
73- if ( reviewers . length !== 0 ) {
74- await requestReviewers ( octokit , task , prNumber , reviewers )
75- }
76-
77- // Also ask the author of the original PR for a review
78- await requestReviewers ( octokit , task , prNumber , [ task . author ] )
79- info ( task , `Requested reviews from ${ [ ...reviewers , task . author ] . join ( ', ' ) } ` )
80- } catch ( e ) {
81- error ( task , `Failed to request reviews: ${ e . message } ` )
72+ // Ask for reviews from all reviewers of the original PR
73+ if ( reviewers . length !== 0 ) {
74+ await requestReviewers ( octokit , task , prNumber , reviewers )
8275 }
83- } catch ( e ) {
84- throw new Error ( `Failed to create pull request: ${ e . message } ` )
85- }
8676
87- // Get labels from original PR and set them on the new PR
88- try {
89- const availableLabels = await getAvailableLabels ( octokit , task )
90- const prLabels = await getLabelsFromPR ( octokit , task )
91- const labels = getLabelsForPR ( prLabels , availableLabels )
92- await setPRLabels ( octokit , task , prNumber , labels )
93- info ( task , `Set labels: ${ labels . join ( ', ' ) } ` )
77+ // Also ask the author of the original PR for a review
78+ await requestReviewers ( octokit , task , prNumber , [ task . author ] )
79+ info ( task , `Requested reviews from ${ [ ...reviewers , task . author ] . join ( ', ' ) } ` )
9480 } catch ( e ) {
95- error ( task , `Failed to get and set labels: ${ e . message } ` )
96- // continue, this is not a fatal error
81+ error ( task , `Failed to request reviews: ${ e . message } ` )
9782 }
83+ } catch ( e ) {
84+ throw new Error ( `Failed to create pull request: ${ e . message } ` )
85+ }
9886
99- // Find new appropriate Milestone and set it on the new PR
100- try {
101- const availableMilestone = await getAvailableMilestones ( octokit , task )
102- const milestone = await getMilestoneFromBase ( task . branch , availableMilestone )
103- await setPRMilestone ( octokit , task , prNumber , milestone )
104- info ( task , `Set milestone: ${ milestone . title } ` )
105- } catch ( e ) {
106- error ( task , `Failed to find appropriate milestone: ${ e . message } ` )
107- // continue, this is not a fatal error
108- }
87+ // Get labels from original PR and set them on the new PR
88+ try {
89+ const availableLabels = await getAvailableLabels ( octokit , task )
90+ const prLabels = await getLabelsFromPR ( octokit , task )
91+ const labels = getLabelsForPR ( prLabels , availableLabels )
92+ await setPRLabels ( octokit , task , prNumber , labels )
93+ info ( task , `Set labels: ${ labels . join ( ', ' ) } ` )
94+ } catch ( e ) {
95+ error ( task , `Failed to get and set labels: ${ e . message } ` )
96+ // continue, this is not a fatal error
97+ }
10998
110- // Assign the PR to the author of the original PR
111- try {
112- await assignToPR ( octokit , task , prNumber , [ task . author ] )
113- info ( task , `Assigned original author: ${ task . author } ` )
114- } catch ( e ) {
115- error ( task , `Failed to assign PR: ${ e . message } ` )
116- // continue, this is not a fatal error
117- }
99+ // Find new appropriate Milestone and set it on the new PR
100+ try {
101+ const availableMilestone = await getAvailableMilestones ( octokit , task )
102+ const milestone = await getMilestoneFromBase ( task . branch , availableMilestone )
103+ await setPRMilestone ( octokit , task , prNumber , milestone )
104+ info ( task , `Set milestone: ${ milestone . title } ` )
105+ } catch ( e ) {
106+ error ( task , `Failed to find appropriate milestone: ${ e . message } ` )
107+ // continue, this is not a fatal error
108+ }
109+
110+ // Assign the PR to the author of the original PR
111+ try {
112+ await assignToPR ( octokit , task , prNumber , [ task . author ] )
113+ info ( task , `Assigned original author: ${ task . author } ` )
114+ } catch ( e ) {
115+ error ( task , `Failed to assign PR: ${ e . message } ` )
116+ // continue, this is not a fatal error
117+ }
118118
119- // Compare the original PR with the new PR
119+ // Compare the original PR with the new PR
120+ try {
121+ const oldChanges = await getChangesFromPR ( octokit , task , task . prNumber )
122+ const newChanges = await getChangesFromPR ( octokit , task , prNumber )
123+ const diffChanges = oldChanges . additions !== newChanges . additions
124+ || oldChanges . deletions !== newChanges . deletions
125+ || oldChanges . changedFiles !== newChanges . changedFiles
126+ const skipCi = await hasSkipCiCommits ( tmpDir , task . commits . length )
127+ const emptyCommits = await hasEmptyCommits ( tmpDir , task . commits . length , task )
128+ const hasConflicts = conflicts === CherryPickResult . CONFLICTS
129+
130+ debug ( task , `hasConflicts: ${ hasConflicts } , diffChanges: ${ diffChanges } , emptyCommits: ${ emptyCommits } , skipCi: ${ skipCi } ` )
120131 try {
121- const oldChanges = await getChangesFromPR ( octokit , task , task . prNumber )
122- const newChanges = await getChangesFromPR ( octokit , task , prNumber )
123- const diffChanges = oldChanges . additions !== newChanges . additions
124- || oldChanges . deletions !== newChanges . deletions
125- || oldChanges . changedFiles !== newChanges . changedFiles
126- const skipCi = await hasSkipCiCommits ( tmpDir , task . commits . length )
127- const emptyCommits = await hasEmptyCommits ( tmpDir , task . commits . length , task )
128- const hasConflicts = conflicts === CherryPickResult . CONFLICTS
129-
130- debug ( task , `hasConflicts: ${ hasConflicts } , diffChanges: ${ diffChanges } , emptyCommits: ${ emptyCommits } , skipCi: ${ skipCi } ` )
131- try {
132- if ( hasConflicts || diffChanges || emptyCommits || skipCi ) {
133- const newBody = await getBackportBody ( task . prNumber , hasConflicts , diffChanges , emptyCommits , skipCi )
134- await updatePRBody ( octokit , task , prNumber , newBody )
135- }
136- } catch ( e ) {
137- error ( task , `Failed to update PR body: ${ e . message } ` )
138- // continue, this is not a fatal error
132+ if ( hasConflicts || diffChanges || emptyCommits || skipCi ) {
133+ const newBody = await getBackportBody ( task . prNumber , hasConflicts , diffChanges , emptyCommits , skipCi )
134+ await updatePRBody ( octokit , task , prNumber , newBody )
139135 }
140136 } catch ( e ) {
141- error ( task , `Failed to compare changes : ${ e . message } ` )
137+ error ( task , `Failed to update PR body : ${ e . message } ` )
142138 // continue, this is not a fatal error
143139 }
144-
145- // Success! We're done here
146- addReaction ( octokit , task , Reaction . HOORAY )
147140 } catch ( e ) {
148- // Add a thumbs down reaction to the comment to indicate that we failed
149- try {
150- addReaction ( octokit , task , Reaction . THUMBS_DOWN )
151- const failureComment = getFailureCommentBody ( task , backportBranch , e ?. message )
152- await commentOnPR ( octokit , task , failureComment )
153- } catch ( e ) {
154- error ( task , `Failed to comment failure on PR: ${ e . message } ` )
155- // continue, this is not a fatal error
156- }
141+ error ( task , `Failed to compare changes: ${ e . message } ` )
142+ // continue, this is not a fatal error
143+ }
157144
158- reject ( `Failed to backport: ${ e . message } ` )
145+ // Success! We're done here
146+ addReaction ( octokit , task , Reaction . HOORAY )
147+ } catch ( e ) {
148+ // Add a thumbs down reaction to the comment to indicate that we failed
149+ try {
150+ addReaction ( octokit , task , Reaction . THUMBS_DOWN )
151+ const failureComment = getFailureCommentBody ( task , backportBranch , e ?. message )
152+ await commentOnPR ( octokit , task , failureComment )
153+ } catch ( e ) {
154+ error ( task , `Failed to comment failure on PR: ${ e . message } ` )
155+ // continue, this is not a fatal error
159156 }
160157
161- // Remove the temp dir if it exists
162- if ( tmpDir !== '' && existsSync ( tmpDir ) ) {
163- try {
164- rmSync ( tmpDir , { recursive : true } )
165- info ( task , `Removed ${ tmpDir } ` )
166- resolve ( )
167- } catch ( e ) {
168- reject ( `Failed to remove ${ tmpDir } : ${ e . message } ` )
169- }
158+ throw new Error ( `Failed to backport: ${ e . message } ` )
159+ }
160+
161+ // Remove the temp dir if it exists
162+ if ( tmpDir !== '' && existsSync ( tmpDir ) ) {
163+ try {
164+ rmSync ( tmpDir , { recursive : true } )
165+ info ( task , `Removed ${ tmpDir } ` )
166+ } catch ( e ) {
167+ throw new Error ( `Failed to remove ${ tmpDir } : ${ e . message } ` )
170168 }
171- } )
172- } ) . catch ( e => {
173- error ( task , e )
174- throw e
175- } )
169+ }
170+ }
0 commit comments