11import chalk from 'chalk' ;
2- import { spawn , ChildProcess } from 'child_process' ;
2+ import { spawn , execFile } from 'child_process' ;
33import path from 'path' ;
44import fs from 'fs' ;
55import os from 'os' ;
@@ -8,11 +8,12 @@ import ComponentDetection from './componentDetection.js';
88import {
99 Job ,
1010 Snapshot ,
11- submitSnapshot
1211} from '@github/dependency-submission-toolkit' ;
12+ import { Octokit } from 'octokit' ;
13+ import { RequestError } from '@octokit/request-error'
1314
1415export interface SubmitOpts {
15- octokit ?: any ; // Octokit instance, optional
16+ octokit : Octokit ;
1617 owner : string ;
1718 repo : string ;
1819 branch : string ;
@@ -51,8 +52,9 @@ export async function sparseCheckout(owner: string, repo: string, branch: string
5152 await execGit ( [ 'fetch' , '--depth=1' , 'origin' , branch ] , { cwd } ) ;
5253 await execGit ( [ 'checkout' , 'FETCH_HEAD' ] , { cwd } ) ;
5354
54- const process = await execGit ( [ 'rev-parse' , 'HEAD' ] , { cwd : destDir } ) ;
55- const sha = process ?. stdout ?. toString ( ) . trim ( ) ;
55+ const { stdout : shaOut } = await execGit ( [ 'rev-parse' , 'HEAD' ] , { cwd : destDir } ) ;
56+ const sha = shaOut . trim ( ) ;
57+ console . debug ( `Checked out ${ owner } /${ repo } @${ branch } to ${ destDir } at commit ${ sha } ` ) ;
5658 return sha ;
5759}
5860
@@ -74,7 +76,7 @@ export async function submitSnapshotIfPossible(opts: SubmitOpts): Promise<boolea
7476 if ( ! opts . quiet ) console . error ( chalk . red ( `Failed to determine SHA for ${ opts . owner } /${ opts . repo } on branch ${ opts . branch } ` ) ) ;
7577 return false ;
7678 }
77- await run ( tmp , opts . owner , opts . repo , sha , opts . branch , opts . componentDetectionBinPath ) ;
79+ await run ( opts . octokit , tmp , opts . owner , opts . repo , sha , opts . branch , opts . componentDetectionBinPath ) ;
7880
7981 } catch ( e ) {
8082 if ( ! opts . quiet ) console . error ( chalk . red ( `Component Detection failed: ${ ( e as Error ) . message } ` ) ) ;
@@ -127,15 +129,20 @@ function buildSparsePatterns(langs: string[]): string[] {
127129 return Array . from ( set ) ;
128130}
129131
130- async function execGit ( args : string [ ] , opts : { cwd : string , quiet ?: boolean } ) : Promise < ChildProcess > {
131- return await new Promise < ChildProcess > ( ( resolve , reject ) => {
132- const child = spawn ( 'git' , args , { cwd : opts . cwd , stdio : 'pipe' } ) ;
133- child . on ( 'error' , reject ) ;
134- child . on ( 'exit' , code => code === 0 ? resolve ( child ) : reject ( new Error ( `git ${ args . join ( ' ' ) } exit ${ code } ` ) ) ) ;
132+ async function execGit ( args : string [ ] , opts : { cwd : string , quiet ?: boolean } ) : Promise < { stdout : string ; stderr : string } > {
133+ return await new Promise < { stdout : string ; stderr : string } > ( ( resolve , reject ) => {
134+ execFile ( 'git' , args , { cwd : opts . cwd , encoding : 'utf8' , maxBuffer : 10 * 1024 * 1024 } , ( error , stdout , stderr ) => {
135+ if ( error ) {
136+ const msg = stderr ?. trim ( ) || error . message ;
137+ reject ( new Error ( `git ${ args . join ( ' ' ) } failed: ${ msg } ` ) ) ;
138+ } else {
139+ resolve ( { stdout, stderr : stderr ?? '' } ) ;
140+ }
141+ } ) ;
135142 } ) ;
136143}
137144
138- export async function run ( tmpDir : string , owner : string , repo : string , sha : string , ref : string , componentDetectionBinPath ?: string ) {
145+ export async function run ( octokit : Octokit , tmpDir : string , owner : string , repo : string , sha : string , ref : string , componentDetectionBinPath ?: string ) {
139146
140147 let manifests = await ComponentDetection . scanAndGetManifests (
141148 tmpDir ,
@@ -160,12 +167,70 @@ export async function run(tmpDir: string, owner: string, repo: string, sha: stri
160167 } ;
161168
162169 let snapshot = new Snapshot ( detector , undefined , job ) ;
170+ snapshot . ref = `refs/heads/${ ref } ` ;
171+ snapshot . sha = sha ;
172+
173+ console . debug ( `Submitting snapshot for ${ owner } /${ repo } at ${ snapshot . ref } (${ snapshot . sha } ) with ${ manifests ?. length || 0 } manifests` ) ;
163174
164175 manifests ?. forEach ( ( manifest ) => {
165176 snapshot . addManifest ( manifest ) ;
166177 } ) ;
167178
179+ submitSnapshot ( octokit , snapshot , { owner, repo } ) ;
180+ }
181+
182+ /**
183+ * submitSnapshot submits a snapshot to the Dependency Submission API - vendored in from @github/dependency-submission-toolkit, to make it work at the CLI, vs in Actions.
184+ *
185+ * @param {Snapshot } snapshot
186+ * @param {Repo } repo
187+ */
188+ export async function submitSnapshot (
189+ octokit : Octokit ,
190+ snapshot : Snapshot ,
191+ repo : { owner : string ; repo : string }
192+ ) {
193+ console . debug ( 'Submitting snapshot...' )
168194 console . debug ( snapshot . prettyJSON ( ) )
169195
170- //submitSnapshot(snapshot);
171- }
196+ try {
197+ const response = await octokit . request (
198+ 'POST /repos/{owner}/{repo}/dependency-graph/snapshots' ,
199+ {
200+ headers : {
201+ accept : 'application/vnd.github.foo-bar-preview+json'
202+ } ,
203+ owner : repo . owner ,
204+ repo : repo . repo ,
205+ ...snapshot
206+ }
207+ )
208+ const result = response . data . result
209+ if ( result === 'SUCCESS' || result === 'ACCEPTED' ) {
210+ console . debug (
211+ `Snapshot successfully created at ${ response . data . created_at . toString ( ) } ` +
212+ ` with id ${ response . data . id } `
213+ )
214+ } else {
215+ console . error (
216+ `Snapshot creation failed with result: "${ result } : ${ response . data . message } "`
217+ )
218+ }
219+ } catch ( error ) {
220+ if ( error instanceof RequestError ) {
221+ console . error (
222+ `HTTP Status ${ error . status } for request ${ error . request . method } ${ error . request . url } `
223+ )
224+ if ( error . response ) {
225+ console . error (
226+ `Response body:\n${ JSON . stringify ( error . response . data , undefined , 2 ) } `
227+ )
228+ }
229+ }
230+ if ( error instanceof Error ) {
231+ console . error ( error . message )
232+ if ( error . stack ) console . error ( error . stack )
233+ }
234+ throw new Error ( `Failed to submit snapshot: ${ error } ` )
235+ }
236+ }
0 commit comments