Skip to content

Commit 9c26026

Browse files
Kirill89Mobb autofixer
authored and
Mobb autofixer
committed
version 1.0.47
1 parent 1f0a82b commit 9c26026

24 files changed

+239
-58
lines changed

__tests__/integration.test.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,13 @@ describe('Basic Analyze tests', () => {
140140
command: 'scan',
141141
autoPr: true,
142142
commitDirectly: true,
143+
pullRequest: 1,
143144
},
144145
{ skipPrompts: true }
145146
)
146147

147148
expect(runAnalysisSpy).toHaveBeenCalled()
148-
expect(autoPrAnalysisSpy).toHaveBeenCalledWith(expect.any(String), true)
149+
expect(autoPrAnalysisSpy).toHaveBeenCalledWith(expect.any(String), true, 1)
149150
expect(mockedOpen).toHaveBeenCalledTimes(2)
150151
expect(mockedOpen).toBeCalledWith(expect.stringMatching(PROJECT_PAGE_REGEX))
151152
}, 30000)
@@ -255,6 +256,7 @@ describe('Basic Analyze tests', () => {
255256
it('Checks ci flag', async () => {
256257
const consoleMock = vi.spyOn(console, 'log')
257258
const autoPrAnalysisSpy = vi.spyOn(GQLClient.prototype, 'autoPrAnalysis')
259+
const prNumber = 1
258260
await analysisExports.runAnalysis(
259261
{
260262
repo: 'https://bitbucket.com/a/b',
@@ -266,10 +268,15 @@ describe('Basic Analyze tests', () => {
266268
command: 'analyze',
267269
autoPr: true,
268270
commitDirectly: true,
271+
pullRequest: prNumber,
269272
},
270273
{ skipPrompts: true }
271274
)
272-
expect(autoPrAnalysisSpy).toHaveBeenCalledWith(expect.any(String), true)
275+
expect(autoPrAnalysisSpy).toHaveBeenCalledWith(
276+
expect.any(String),
277+
true,
278+
prNumber
279+
)
273280
expect(analysisRegex.test(consoleMock.mock.lastCall?.at(0))).toBe(true)
274281
consoleMock.mockClear()
275282
})

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mobbdev",
3-
"version": "1.0.46",
3+
"version": "1.0.47",
44
"description": "Automated secure code remediation tool",
55
"repository": "git+https://github.com/mobb-dev/bugsy.git",
66
"main": "dist/index.js",

src/args/commands/analyze.ts

+11
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ export function analyzeBuilder(
5858
.option('commit-hash', commitHashOption)
5959
.option('auto-pr', autoPrOption)
6060
.option('commit-directly', commitDirectlyOption)
61+
.option('pull-request', {
62+
alias: ['pr', 'pr-number', 'pr-id'],
63+
describe: chalk.bold('Number of the pull request'),
64+
type: 'number',
65+
demandOption: false,
66+
})
6167
.example(
6268
'npx mobbdev@latest analyze -r https://github.com/WebGoat/WebGoat -f <your_vulnerability_report_path>',
6369
'analyze an existing repository'
@@ -85,6 +91,11 @@ function validateAnalyzeOptions(argv: AnalyzeOptions) {
8591
'--commit-directly flag requires --auto-pr to be provided as well'
8692
)
8793
}
94+
if (argv.pullRequest && !argv['commit-directly']) {
95+
throw new CliError(
96+
'--pull-request flag requires --commit-directly to be provided as well'
97+
)
98+
}
8899
validateReportFileFormat(argv.f)
89100
}
90101

src/args/commands/review.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export function reviewBuilder(
4747
})
4848

4949
.option('pull-request', {
50-
alias: 'pr',
50+
alias: ['pr', 'pr-number', 'pr-id'],
5151
describe: chalk.bold('Number of the pull request'),
5252
type: 'number',
5353
demandOption: true,

src/args/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export type BaseAnalyzeOptions = {
2424
'auto-pr': boolean
2525
'commit-directly'?: boolean
2626
commitDirectly?: boolean
27+
pullRequest?: number
2728
}
2829

2930
export type ReviewOptions = Yargs.ArgumentsCamelCase<BaseReviewOptions>

src/commands/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ export async function analyze(
8282
organizationId,
8383
autoPr,
8484
commitDirectly,
85+
pullRequest,
8586
}: AnalyzeOptions,
8687
{ skipPrompts = false }: CommandOptions = {}
8788
) {
@@ -101,6 +102,7 @@ export async function analyze(
101102
command: 'analyze',
102103
autoPr,
103104
commitDirectly,
105+
pullRequest,
104106
},
105107
{ skipPrompts }
106108
)

src/features/analysis/auto_pr_handler.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ export async function handleAutoPr(params: {
1010
gqlClient: GQLClient
1111
analysisId: string
1212
commitDirectly?: boolean
13+
prId?: number
1314
createSpinner: CreateSpinner
1415
}) {
15-
const { gqlClient, analysisId, commitDirectly, createSpinner } = params
16+
const { gqlClient, analysisId, commitDirectly, prId, createSpinner } = params
1617
const createAutoPrSpinner = createSpinner(
1718
'🔄 Waiting for the analysis to finish before initiating automatic pull request creation'
1819
).start()
@@ -23,7 +24,8 @@ export async function handleAutoPr(params: {
2324
callback: async (analysisId) => {
2425
const autoPrAnalysisRes = await gqlClient.autoPrAnalysis(
2526
analysisId,
26-
commitDirectly
27+
commitDirectly,
28+
prId
2729
)
2830
debug('auto pr analysis res %o', autoPrAnalysisRes)
2931
if (autoPrAnalysisRes.autoPrAnalysis?.__typename === 'AutoPrError') {

src/features/analysis/graphql/gql.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -376,10 +376,15 @@ export class GQLClient {
376376
}
377377
return res.analysis
378378
}
379-
async autoPrAnalysis(analysisId: string, commitDirectly?: boolean) {
379+
async autoPrAnalysis(
380+
analysisId: string,
381+
commitDirectly?: boolean,
382+
prId?: number
383+
) {
380384
return this._clientSdk.autoPrAnalysis({
381385
analysisId,
382386
commitDirectly,
387+
prId,
383388
})
384389
}
385390
async getFixes(fixIds: string[]) {

src/features/analysis/index.ts

+3
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ export async function _scan(
345345
organizationId: userOrganizationId,
346346
autoPr,
347347
commitDirectly,
348+
pullRequest,
348349
} = params
349350
debug('start %s %s', dirname, repo)
350351
const { createSpinner } = Spinner({ ci })
@@ -513,6 +514,7 @@ export async function _scan(
513514
gqlClient,
514515
analysisId: reportUploadInfo.fixReportId,
515516
commitDirectly,
517+
prId: pullRequest,
516518
createSpinner,
517519
})
518520
}
@@ -734,6 +736,7 @@ export async function _scan(
734736
gqlClient,
735737
analysisId: reportUploadInfo.fixReportId,
736738
commitDirectly,
739+
prId: pullRequest,
737740
createSpinner,
738741
})
739742
}

src/features/analysis/scm/StubSCMLib.ts

+11-4
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,13 @@ export class StubSCMLib extends SCMLib {
103103
return ''
104104
}
105105

106-
async getPrUrl(_prNumber: number): Promise<string> {
107-
console.warn('getPrUrl() returning empty string')
106+
async getSubmitRequestUrl(_submitRequestIdNumber: number): Promise<string> {
107+
console.warn('getSubmitRequestUrl() returning empty string')
108108
return ''
109109
}
110110

111-
async getPrId(_prUrl: string): Promise<string> {
112-
console.warn('getPrId() returning empty string')
111+
async getSubmitRequestId(_submitRequestUrl: string): Promise<string> {
112+
console.warn('getSubmitRequestId() returning empty string')
113113
return ''
114114
}
115115

@@ -122,4 +122,11 @@ export class StubSCMLib extends SCMLib {
122122
console.warn('_getUsernameForAuthUrl() returning empty string')
123123
return ''
124124
}
125+
126+
async addCommentToSubmitRequest(
127+
_submitRequestId: string,
128+
_comment: string
129+
): Promise<void> {
130+
console.warn('addCommentToSubmitRequest() no-op')
131+
}
125132
}

src/features/analysis/scm/__tests__/ado.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ describe.each(Object.entries(scmTestParams))(
361361
expect(signedRepoUrl).toBe(
362362
`${protocol}//${accessToken}@${hostname}${pathname}`
363363
)
364-
const prUrl = await scmLib.getPrUrl(1)
364+
const prUrl = await scmLib.getSubmitRequestUrl(1)
365365
expect(prUrl).toMatch(`${url}/pullrequest/1`)
366366
})
367367
}

src/features/analysis/scm/ado/AdoSCMLib.ts

+16-4
Original file line numberDiff line numberDiff line change
@@ -209,16 +209,16 @@ export class AdoSCMLib extends SCMLib {
209209
repoUrl: this.url,
210210
})
211211
}
212-
async getPrUrl(prNumber: number): Promise<string> {
212+
async getSubmitRequestUrl(submitRequestIdNumber: number): Promise<string> {
213213
this._validateUrl()
214214
const adoSdk = await this.getAdoSdk()
215215
return adoSdk.getAdoPrUrl({
216216
url: this.url,
217-
prNumber,
217+
prNumber: submitRequestIdNumber,
218218
})
219219
}
220-
async getPrId(prUrl: string): Promise<string> {
221-
const match = prUrl.match(/\/pullrequest\/(\d+)/)
220+
async getSubmitRequestId(submitRequestUrl: string): Promise<string> {
221+
const match = submitRequestUrl.match(/\/pullrequest\/(\d+)/)
222222
return match?.[1] || ''
223223
}
224224
async getCommitUrl(commitId: string): Promise<string> {
@@ -229,4 +229,16 @@ export class AdoSCMLib extends SCMLib {
229229
commitId,
230230
})
231231
}
232+
async addCommentToSubmitRequest(
233+
scmSubmitRequestId: string,
234+
comment: string
235+
): Promise<void> {
236+
this._validateAccessTokenAndUrl()
237+
const adoSdk = await this.getAdoSdk()
238+
await adoSdk.addCommentToAdoPullRequest({
239+
repoUrl: this.url,
240+
prNumber: Number(scmSubmitRequestId),
241+
markdownComment: comment,
242+
})
243+
}
232244
}

src/features/analysis/scm/ado/ado.ts

+23
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,29 @@ export async function getAdoSdk(params: GetAdoApiClientParams) {
5050
}
5151
return parsedPullRequestStatus.data
5252
},
53+
async addCommentToAdoPullRequest({
54+
repoUrl,
55+
prNumber,
56+
markdownComment,
57+
}: {
58+
repoUrl: string
59+
prNumber: number
60+
markdownComment: string
61+
}) {
62+
const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl)
63+
const git = await api.getGitApi()
64+
const comment = {
65+
comments: [
66+
{
67+
parentCommentId: 0, // Root comment
68+
content: markdownComment,
69+
commentType: 1, // Default type
70+
},
71+
],
72+
}
73+
74+
await git.createThread(comment, repo, prNumber, projectName)
75+
},
5376
async getAdoIsRemoteBranch({
5477
repoUrl,
5578
branch,

src/features/analysis/scm/bitbucket/BitbucketSCMLib.ts

+19-7
Original file line numberDiff line numberDiff line change
@@ -261,22 +261,34 @@ export class BitbucketSCMLib extends SCMLib {
261261
const repoRes = await this.bitbucketSdk.getRepo({ repoUrl: this.url })
262262
return z.string().parse(repoRes.mainbranch?.name)
263263
}
264-
getPrUrl(prNumber: number): Promise<string> {
264+
getSubmitRequestUrl(submitRequestId: number): Promise<string> {
265265
this._validateUrl()
266-
const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(this.url)
266+
const { repo_slug, workspace } = parseBitbucketOrganizationAndRepo(this.url)
267267
return Promise.resolve(
268-
`https://bitbucket.org/${workspace}/${repoSlug}/pull-requests/${prNumber}`
268+
`https://bitbucket.org/${workspace}/${repo_slug}/pull-requests/${submitRequestId}`
269269
)
270270
}
271-
async getPrId(prUrl: string): Promise<string> {
272-
const match = prUrl.match(/\/pull-requests\/(\d+)/)
271+
async getSubmitRequestId(submitRequestUrl: string): Promise<string> {
272+
const match = submitRequestUrl.match(/\/pull-requests\/(\d+)/)
273273
return match?.[1] || ''
274274
}
275275
getCommitUrl(commitId: string): Promise<string> {
276276
this._validateUrl()
277-
const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(this.url)
277+
const { repo_slug, workspace } = parseBitbucketOrganizationAndRepo(this.url)
278278
return Promise.resolve(
279-
`https://bitbucket.org/${workspace}/${repoSlug}/commits/${commitId}`
279+
`https://bitbucket.org/${workspace}/${repo_slug}/commits/${commitId}`
280280
)
281281
}
282+
283+
async addCommentToSubmitRequest(
284+
submitRequestId: string,
285+
comment: string
286+
): Promise<void> {
287+
this._validateUrl()
288+
await this.bitbucketSdk.addCommentToPullRequest({
289+
prNumber: Number(submitRequestId),
290+
url: this.url,
291+
markdownComment: comment,
292+
})
293+
}
282294
}

0 commit comments

Comments
 (0)