1
+ import * as core from "@actions/core" ;
1
2
import * as fs from "fs" ;
2
3
import * as util from "util" ;
3
4
import addressparser from "nodemailer/lib/addressparser/index.js" ;
5
+ import path from "path" ;
4
6
import { ILintError , LintCommit } from "./commit-lint.js" ;
5
7
import { commitExists , git , emptyTreeName } from "./git.js" ;
6
8
import { GitNotes } from "./git-notes.js" ;
@@ -15,6 +17,7 @@ import { IPatchSeriesMetadata } from "./patch-series-metadata.js";
15
17
import { IConfig , getExternalConfig , setConfig } from "./project-config.js" ;
16
18
import { getPullRequestKeyFromURL , pullRequestKey } from "./pullRequestKey.js" ;
17
19
import { ISMTPOptions } from "./send-mail.js" ;
20
+ import { fileURLToPath } from "url" ;
18
21
19
22
const readFile = util . promisify ( fs . readFile ) ;
20
23
type CommentFunction = ( comment : string ) => Promise < void > ;
@@ -62,6 +65,84 @@ export class CIHelper {
62
65
this . urlRepo = `${ this . urlBase } ${ this . config . repo . name } /` ;
63
66
}
64
67
68
+ public async setupGitHubAction ( ) : Promise < void > {
69
+ // help dugite realize where `git` is...
70
+ process . env . LOCAL_GIT_DIRECTORY = "/usr/" ;
71
+ process . env . GIT_EXEC_PATH = "/usr/lib/git-core" ;
72
+
73
+ // get the access tokens via the inputs of the GitHub Action
74
+ this . setAccessToken ( "gitgitgadget" , core . getInput ( "gitgitgadget-git-access-token" ) ) ;
75
+ this . setAccessToken ( "git" , core . getInput ( "git-git-access-token" ) ) ;
76
+ this . setAccessToken ( "dscho" , core . getInput ( "dscho-git-access-token" ) ) ;
77
+
78
+ // set the SMTP options
79
+ try {
80
+ const options = JSON . parse ( core . getInput ( "smtp-options" ) ) as {
81
+ user ?: string ;
82
+ host ?: string ;
83
+ pass ?: string ;
84
+ opts ?: string ;
85
+ } ;
86
+ if ( typeof options === "object" && options . user && options . host && options . pass ) {
87
+ this . setSMTPOptions ( {
88
+ smtpUser : options . user ,
89
+ smtpHost : options . host ,
90
+ smtpPass : options . pass ,
91
+ smtpOpts : options . opts ,
92
+ } ) ;
93
+ }
94
+ } catch ( e ) {
95
+ // Ignore, for now
96
+ }
97
+
98
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
99
+ if ( ! fs . existsSync ( this . workDir ) ) await git ( [ "init" , "--bare" , "--initial-branch" , "main" , this . workDir ] ) ;
100
+ for ( const [ key , value ] of [
101
+ [ "remote.origin.url" , `https://github.com/${ this . config . repo . owner } /${ this . config . repo . name } ` ] ,
102
+ [ "remote.origin.promisor" , "true" ] ,
103
+ [ "remote.origin.partialclonefilter" , "blob:none" ] ,
104
+ ] ) {
105
+ await git ( [ "config" , key , value ] , { workDir : this . workDir } ) ;
106
+ }
107
+ const notesRefs = [ GitNotes . defaultNotesRef ] ;
108
+ // TODO Add `refs/notes/mail-to-commit` on demand
109
+ await git (
110
+ [
111
+ "-c" ,
112
+ "remote.origin.promisor=false" , // let's fetch the notes with all of their blobs
113
+ "fetch" ,
114
+ "origin" ,
115
+ "--depth=1" ,
116
+ ...notesRefs . map ( ( ref ) => `+${ ref } :${ ref } ` ) ,
117
+ ] ,
118
+ {
119
+ workDir : this . workDir ,
120
+ } ,
121
+ ) ;
122
+ this . gggNotesUpdated = true ;
123
+ // TODO: determine on demand how many commits to fetch; This is contingent on the need
124
+ // to fetch a PR branch (for handle-pr-push or handle-pr-comment), or whether the upstream branches
125
+ // are needed (for update-commit-mappings and handle-open-prs).
126
+ // await git(["fetch", "origin", "--depth=500", `${GitNotes.defaultNotesRef}:${GitNotes.defaultNotesRef}`], {
127
+ // workDir: this.workDir,
128
+ // });
129
+ // "Un-shallow" the refs without fetching anything; Since this is a partial clone,
130
+ // any missing commits will be fetched on demand (but when fetching a commit, you
131
+ // get the entire commit history reachable from it, too, that's why we go through
132
+ // the stunt of making a shallow-not-shallow fetch here).
133
+ await fs . promises . rm ( path . join ( this . workDir , ".git" , "shallow" ) , { force : true } ) ;
134
+ }
135
+
136
+ public parsePRCommentURLInput ( ) : { owner : string ; repo : string ; prNumber : number ; commentId : number } {
137
+ const prCommentUrl = core . getInput ( "pr-comment-url" ) ;
138
+ const [ , owner , repo , prNumber , commentId ] =
139
+ prCommentUrl . match ( / ^ h t t p s : \/ \/ g i t h u b \. c o m \/ ( [ ^ / ] + ) \/ ( [ ^ / ] + ) \/ p u l l \/ ( \d + ) # i s s u e c o m m e n t - ( \d + ) / ) || [ ] ;
140
+ if ( ! this . config . repo . owners . includes ( owner ) || repo !== "git" ) {
141
+ throw new Error ( `Invalid PR comment URL: ${ prCommentUrl } ` ) ;
142
+ }
143
+ return { owner, repo, prNumber : parseInt ( prNumber , 10 ) , commentId : parseInt ( commentId , 10 ) } ;
144
+ }
145
+
65
146
public setAccessToken ( repositoryOwner : string , token : string ) : void {
66
147
this . github . setAccessToken ( repositoryOwner , token ) ;
67
148
if ( this . config . repo . owner === repositoryOwner ) {
@@ -73,6 +154,10 @@ export class CIHelper {
73
154
this . smtpOptions = smtpOptions ;
74
155
}
75
156
157
+ public static getActionsCore ( ) : typeof import ( "@actions/core" ) {
158
+ return core ;
159
+ }
160
+
76
161
/*
77
162
* Given a commit that was contributed as a patch via GitGitGadget (i.e.
78
163
* a commit with a Message-ID recorded in `refs/notes/gitgitgadget`),
@@ -785,6 +870,11 @@ export class CIHelper {
785
870
}
786
871
}
787
872
873
+ public static async getWelcomeMessage ( username : string ) : Promise < string > {
874
+ const resPath = path . resolve ( fileURLToPath ( new URL ( "." , import . meta. url ) ) , ".." , "res" , "WELCOME.md" ) ;
875
+ return ( await readFile ( resPath ) ) . toString ( ) . replace ( / \$ { username} / g, username ) ;
876
+ }
877
+
788
878
public async handlePush ( repositoryOwner : string , prNumber : number ) : Promise < void > {
789
879
const prKey = {
790
880
owner : repositoryOwner ,
@@ -808,7 +898,7 @@ export class CIHelper {
808
898
this . smtpOptions ,
809
899
) ;
810
900
if ( ! pr . hasComments && ! gitGitGadget . isUserAllowed ( pr . author ) ) {
811
- const welcome = ( await readFile ( "res/WELCOME.md" ) ) . toString ( ) . replace ( / \$ { username } / g , pr . author ) ;
901
+ const welcome = await CIHelper . getWelcomeMessage ( pr . author ) ;
812
902
await this . github . addPRComment ( prKey , welcome ) ;
813
903
814
904
await this . github . addPRLabels ( prKey , [ "new user" ] ) ;
0 commit comments