11/* This file is a part of @mdn/browser-compat-data
22 * See LICENSE file for more information. */
33
4- import { execSync } from 'node:child_process' ;
4+ import { exec , execSync } from 'node:child_process' ;
55import fs from 'node:fs' ;
6+ import { promisify } from 'node:util' ;
7+ import path from 'node:path' ;
68
79import esMain from 'es-main' ;
810import yargs from 'yargs' ;
911import { hideBin } from 'yargs/helpers' ;
12+ import { temporaryDirectoryTask } from 'tempy' ;
13+
14+ /**
15+ * Executes a command asynchronously.
16+ * @param command The command to execute asynchronously.
17+ * @returns The output of the command.
18+ */
19+ const execAsync = async ( command : string ) : Promise < string > => {
20+ const result = await promisify ( exec ) ( command , { encoding : 'utf-8' } ) ;
21+
22+ return result . stdout . trim ( ) ;
23+ } ;
1024
1125/**
1226 * Compare two references and print diff as Markdown or JSON
@@ -16,14 +30,14 @@ import { hideBin } from 'yargs/helpers';
1630 * @param opts.format Format to export data as (either 'markdown' or 'json', default 'json')
1731 * @param opts.github Whether to obtain artifacts from GitHub
1832 */
19- const main = ( opts : {
33+ const main = async ( opts : {
2034 ref1 : string | undefined ;
2135 ref2 : string | undefined ;
2236 format ?: string ;
2337 github ?: boolean ;
24- } ) : void => {
38+ } ) : Promise < void > => {
2539 const { ref1, ref2, format, github } = opts ;
26- const results = diff ( { ref1, ref2, github } ) ;
40+ const results = await diff ( { ref1, ref2, github } ) ;
2741
2842 if ( format === 'markdown' ) {
2943 printMarkdown ( results . added , results . removed ) ;
@@ -41,12 +55,12 @@ const main = (opts: {
4155 * @param opts.quiet If true, don't log to console
4256 * @returns Diff between two refs
4357 */
44- const diff = ( opts : {
58+ const diff = async ( opts : {
4559 ref1 ?: string ;
4660 ref2 ?: string ;
4761 github ?: boolean ;
4862 quiet ?: boolean ;
49- } ) : { added : string [ ] ; removed : string [ ] } => {
63+ } ) : Promise < { added : string [ ] ; removed : string [ ] } > => {
5064 const { ref1, ref2, github, quiet } = opts ;
5165 let refA , refB ;
5266
@@ -64,8 +78,8 @@ const diff = (opts: {
6478 refB = `${ ref1 } ` ;
6579 }
6680
67- const aSide = enumerate ( refA , github === false , quiet ) ;
68- const bSide = enumerate ( refB , github === false , quiet ) ;
81+ const aSide = await enumerate ( refA , github === false , quiet ) ;
82+ const bSide = await enumerate ( refB , github === false , quiet ) ;
6983
7084 return {
7185 added : [ ...bSide ] . filter ( ( feature ) => ! aSide . has ( feature ) ) ,
@@ -80,14 +94,14 @@ const diff = (opts: {
8094 * @param quiet If true, don't log to console
8195 * @returns Feature list from reference
8296 */
83- const enumerate = (
97+ const enumerate = async (
8498 ref : string ,
8599 skipGithub : boolean ,
86100 quiet = false ,
87- ) : Set < string > => {
101+ ) : Promise < Set < string > > => {
88102 if ( ! skipGithub ) {
89103 try {
90- return new Set ( getEnumerationFromGithub ( ref ) ) ;
104+ return new Set ( await getEnumerationFromGithub ( ref ) ) ;
91105 } catch ( e ) {
92106 if ( ! quiet ) {
93107 console . error (
@@ -105,50 +119,28 @@ const enumerate = (
105119 * @param ref Reference to obtain features for
106120 * @returns Feature list from reference
107121 */
108- const getEnumerationFromGithub = ( ref : string ) : string [ ] => {
122+ const getEnumerationFromGithub = async ( ref : string ) : Promise < string [ ] > => {
109123 const ENUMERATE_WORKFLOW = '15595228' ;
110124 const ENUMERATE_WORKFLOW_ARTIFACT = 'enumerate-features' ;
111125 const ENUMERATE_WORKFLOW_FILE = 'features.json' ;
112126
113- /**
114- * Unlinks the workflow file
115- */
116- const unlinkFile = ( ) => {
117- try {
118- fs . unlinkSync ( ENUMERATE_WORKFLOW_FILE ) ;
119- } catch ( err : any ) {
120- if ( err . code == 'ENOENT' ) {
121- return ;
122- }
123- throw err ;
124- }
125- } ;
126-
127- const hash = execSync ( `git rev-parse ${ ref } ` , {
128- encoding : 'utf-8' ,
129- } ) . trim ( ) ;
130- const workflowRun = execSync (
127+ const hash = await execAsync ( `git rev-parse ${ ref } ` ) ;
128+ const workflowRun = await execAsync (
131129 `gh api /repos/:owner/:repo/actions/workflows/${ ENUMERATE_WORKFLOW } /runs\\?branch=main\\&head_sha=${ hash } \\&per_page=1 --jq '[.workflow_runs[] | select(.head_sha=="${ hash } ") | .id] | first'` ,
132- {
133- encoding : 'utf-8' ,
134- } ,
135- ) . trim ( ) ;
130+ ) ;
136131
137132 if ( ! workflowRun ) {
138133 throw Error ( 'No workflow run found for commit.' ) ;
139134 }
140135
141- try {
142- unlinkFile ( ) ;
143- execSync (
144- `gh run download ${ workflowRun } -n ${ ENUMERATE_WORKFLOW_ARTIFACT } ` ,
145- ) ;
146- return JSON . parse (
147- fs . readFileSync ( ENUMERATE_WORKFLOW_FILE , { encoding : 'utf-8' } ) ,
136+ return await temporaryDirectoryTask ( async ( tempdir ) => {
137+ await execAsync (
138+ `gh run download ${ workflowRun } -n ${ ENUMERATE_WORKFLOW_ARTIFACT } --dir ${ tempdir } ` ,
148139 ) ;
149- } finally {
150- unlinkFile ( ) ;
151- }
140+ const file = path . join ( tempdir , ENUMERATE_WORKFLOW_FILE ) ;
141+
142+ return JSON . parse ( fs . readFileSync ( file , { encoding : 'utf-8' } ) ) ;
143+ } ) ;
152144} ;
153145
154146/**
@@ -249,7 +241,7 @@ if (esMain(import.meta)) {
249241 } ,
250242 ) ;
251243
252- main ( argv as any ) ;
244+ await main ( argv as any ) ;
253245}
254246
255247export default diff ;
0 commit comments