@leverege/build-tools 2.93.0-beta.11 → 2.93.0-beta.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -18,7 +18,15 @@ npm install -g @leverege/build-tools
18
18
  ```bash
19
19
  . `build-tools --bashfun`
20
20
  ```
21
- * **docker-to-registry**: used to build and deploy docker images to the GCP image area
21
+ * **docker-to-registry**: used to build and deploy application docker images to the GCP artifact registry
22
+ * **pull-artifact**: used to pull generic artifacts from the GCP artifact registry
23
+ ```bash
24
+ Usage: pull-artifact -f <artifact schema file path> -pn <package name> -pv <package version>
25
+ ```
26
+ * **push-artifact**: used to push generic artifacts to the GCP artifact registry
27
+ ```bash
28
+ Usage: push-artifact -f <artifact schema file path> -pn <package name> -pv <package version>
29
+ ```
22
30
 
23
31
  ### Helm Helpers:
24
32
  * **overwhelm**: a k8s context helper and yaml replacer *${REPLACE_ME}*
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leverege/build-tools",
3
- "version": "2.93.0-beta.11",
3
+ "version": "2.93.0-beta.13",
4
4
  "description": "A collection of build / support tools for Leverege developers",
5
5
  "main": "index.js",
6
6
  "repository": {
@@ -1,4 +1,7 @@
1
- import fs from 'fs'
1
+ /* eslint-disable security/detect-non-literal-fs-filename */
2
+ import fs from 'node:fs'
3
+
4
+ import { shellCmd, log, debug, err } from '../Utils.mjs'
2
5
 
3
6
  import { toExplicitPath } from './Utils.mjs'
4
7
 
@@ -15,6 +18,8 @@ class ArtifactPuller {
15
18
  class GenericArtifactPuller extends ArtifactPuller {
16
19
 
17
20
  async downloadFile( remoteFilePath, localFilePath ) {
21
+ debug( { remoteFilePath, localFilePath }, '<==Download File' )
22
+
18
23
  const command = `gcloud artifacts generic download \
19
24
  --project=${this.artifact.gcp_project_id} \
20
25
  --location=${this.artifact.gcp_location} \
@@ -40,25 +45,23 @@ class GenericArtifactPuller extends ArtifactPuller {
40
45
  // Ensure the directory exists
41
46
  fs.mkdirSync( localFilePath.split( '/' ).slice( 0, -1 ).join( '/' ), { recursive : true } )
42
47
 
43
- console.log( 'Command:', command.replace( /\s+/g, ' ' ).trim() )
48
+ debug( { command }, '<==Download File Command' )
44
49
 
45
- const { execSync } = await import( 'child_process' )
46
- const result = execSync( command, { encoding : 'utf8', stdio : 'pipe' } )
47
- console.log( 'Result:', result )
50
+ await shellCmd( command )
48
51
 
49
52
  // Check if file exists in the old path
50
53
  if ( !fs.existsSync( oldPath ) ) {
51
- console.error( `File does not exist in the old path: ${oldPath}` )
54
+ debug( { oldPath }, '<==File does not exist in the old path' )
52
55
  return false
53
56
  }
54
57
 
55
- console.log( `Copying file from ${oldPath} to ${newPath}` )
58
+ debug( { oldPath, newPath }, '<==Copying file' )
56
59
 
57
60
  await fs.copyFileSync( oldPath, newPath )
58
61
 
59
62
  // Check if file exists in the new path
60
63
  if ( !fs.existsSync( newPath ) ) {
61
- console.error( `File does not exist in the new path: ${newPath}` )
64
+ debug( { newPath }, '<==File does not exist in the new path' )
62
65
  return false
63
66
  }
64
67
 
@@ -74,15 +77,14 @@ class GenericArtifactPuller extends ArtifactPuller {
74
77
  --version=${this.artifact.gcp_artifact_registry_package_version} \
75
78
  --destination=${localPath}`
76
79
 
77
- console.log( 'Command:', command.replace( /\s+/g, ' ' ).trim() )
80
+ debug( { command }, '<==Download Directory Command' )
78
81
 
79
- const { execSync } = await import( 'child_process' )
80
- execSync( command, { encoding : 'utf8', stdio : 'pipe' } )
81
-
82
- return true
82
+ await shellCmd( command )
83
83
  }
84
84
 
85
85
  async downloadNestedDirectory( remotePath, localPath ) {
86
+ debug( { remotePath, localPath }, '<==Download Nested Directory' )
87
+
86
88
  const files = await this.listFiles( remotePath )
87
89
  await Promise.all(
88
90
  files
@@ -93,7 +95,6 @@ class GenericArtifactPuller extends ArtifactPuller {
93
95
  await this.downloadFile( remoteFilePath, localFilePath )
94
96
  } )
95
97
  )
96
- return true
97
98
  }
98
99
 
99
100
  async listFiles( ) {
@@ -105,42 +106,48 @@ class GenericArtifactPuller extends ArtifactPuller {
105
106
  --version ${this.artifact.gcp_artifact_registry_package_version} \
106
107
  --format="json"`
107
108
 
108
- console.log( 'Command:', command.replace( /\s+/g, ' ' ).trim() )
109
+ debug( { command }, '<==List Files Command' )
109
110
 
110
- const { execSync } = await import( 'child_process' )
111
- const result = execSync( command, { encoding : 'utf8', stdio : 'pipe' } )
111
+ const result = await shellCmd( command )
112
112
 
113
113
  // Parse the JSON response
114
114
  const files = JSON.parse( result )
115
-
116
115
  return files
117
116
  }
118
117
 
119
118
  async pull() {
120
- console.log( 'Pulling artifact from registry...' )
121
-
122
- if ( this.artifact.remote_file_path && this.artifact.local_file_path ) {
123
- return this.downloadFile( this.artifact.remote_file_path, toExplicitPath( this.artifact.local_file_path ) )
124
- }
125
- if ( this.artifact.remote_file_path && this.artifact.local_path ) {
126
- return this.downloadFile( this.artifact.remote_file_path, toExplicitPath( `${this.artifact.local_path}/${this.artifact.remote_file_path.split( '/' ).pop()}` ) )
127
- }
128
- if ( this.artifact.remote_path && this.artifact.local_path ) {
129
- return this.downloadNestedDirectory( this.artifact.remote_path, toExplicitPath( this.artifact.local_path ) )
130
- }
131
- if ( this.artifact.remote_path && !this.artifact.local_path && !this.artifact.local_file_path ) {
132
- return this.downloadDirectory( this.artifact.remote_path, '.' )
133
- }
134
- if ( !this.artifact.remote_path && !this.artifact.remote_file_path && this.artifact.local_path ) {
135
- return this.downloadDirectory( toExplicitPath( this.artifact.local_path ) )
119
+ log( `Pulling artifact: ${this.artifact.name}` )
120
+
121
+ debug( { artifact : this.artifact }, '<==Pulling artifact' )
122
+
123
+ try {
124
+ if ( this.artifact.remote_file_path && this.artifact.local_file_path ) {
125
+ await this.downloadFile( this.artifact.remote_file_path, toExplicitPath( this.artifact.local_file_path ) )
126
+ } else if ( this.artifact.remote_file_path && this.artifact.local_path ) {
127
+ await this.downloadFile( this.artifact.remote_file_path, toExplicitPath( `${this.artifact.local_path}/${this.artifact.remote_file_path.split( '/' ).pop()}` ) )
128
+ } else if ( this.artifact.remote_path && this.artifact.local_path ) {
129
+ await this.downloadNestedDirectory( this.artifact.remote_path, toExplicitPath( this.artifact.local_path ) )
130
+ } else if ( this.artifact.remote_path && !this.artifact.local_path && !this.artifact.local_file_path ) {
131
+ await this.downloadDirectory( this.artifact.remote_path, '.' )
132
+ } else if ( !this.artifact.remote_path && !this.artifact.remote_file_path && this.artifact.local_path ) {
133
+ await this.downloadDirectory( toExplicitPath( this.artifact.local_path ) )
134
+ } else {
135
+ throw new Error( 'No valid paths provided' )
136
+ }
137
+
138
+ log( `Successfully pulled artifact: ${this.artifact.name}` )
139
+
140
+ return true
141
+
142
+ // if ( !this.artifact.remote_path && !this.artifact.remote_file_path && this.local_file_path ) {
143
+ // throw new Error( '' )
144
+ // }
145
+ // if ( this.artifact.remote_path && this.artifact.local_file_path ) {
146
+ // throw new Error( '' )
147
+ // }
148
+ } catch ( error ) {
149
+ err( `Error pulling artifact: ${this.artifact.name} ${error.message}` )
136
150
  }
137
- // if ( !this.artifact.remote_path && !this.artifact.remote_file_path && this.local_file_path ) {
138
- // throw new Error( '' )
139
- // }
140
- // if ( this.artifact.remote_path && this.artifact.local_file_path ) {
141
- // throw new Error( '' )
142
- // }
143
-
144
151
  return false
145
152
  }
146
153
  }
@@ -1,3 +1,6 @@
1
+ /* eslint-disable security/detect-non-literal-fs-filename */
2
+ import { shellCmd, log, err, debug } from '../Utils.mjs'
3
+
1
4
  class ArtifactPusher {
2
5
  constructor( artifact ) {
3
6
  this.artifact = artifact
@@ -19,10 +22,9 @@ class GenericArtifactPusher extends ArtifactPusher {
19
22
  --version ${this.artifact.gcp_artifact_registry_package_version} \
20
23
  --format="json"`
21
24
 
22
- console.log( 'Command:', command.replace( /\s+/g, ' ' ).trim() )
25
+ debug( { command }, '<==List Files Command' )
23
26
 
24
- const { execSync } = await import( 'child_process' )
25
- const result = execSync( command, { encoding : 'utf8', stdio : 'pipe' } )
27
+ const result = await shellCmd( command )
26
28
 
27
29
  // Parse the JSON response
28
30
  const files = JSON.parse( result )
@@ -31,45 +33,49 @@ class GenericArtifactPusher extends ArtifactPusher {
31
33
  }
32
34
 
33
35
  async push() {
34
- console.log( 'Pushing artifact to registry...' )
36
+ log( `Pushing artifact: ${this.artifact.name}` )
35
37
 
36
38
  if ( this.artifact.remote_file_path ) {
39
+ err( 'Remote file path is not supported for pushing artifacts' )
37
40
  return false
38
41
  }
39
42
 
40
- console.log( 'Uploading artifact to registry...' )
43
+ try {
41
44
 
42
- let command = ''
45
+ let command = ''
43
46
 
44
- command = `gcloud artifacts generic upload \
47
+ command = `gcloud artifacts generic upload \
45
48
  --project=${this.artifact.gcp_project_id} \
46
49
  --location=${this.artifact.gcp_location} \
47
50
  --repository=${this.artifact.gcp_artifact_registry_repository_name} \
48
51
  --package=${this.artifact.gcp_artifact_registry_package_name} \
49
52
  --version=${this.artifact.gcp_artifact_registry_package_version}`
50
53
 
51
- if ( this.artifact.local_path ) {
52
- command += ` --source-directory=${this.artifact.local_path}`
53
- command += ' --skip-existing'
54
- } else if ( this.artifact.local_file_path ) {
55
- const files = await this.listFiles( this.artifact.remote_path )
56
- if ( files.some( file => file.name.split( ':' ).pop().replaceAll( '%2F', '/' ) === `${this.artifact.remote_path}/${this.artifact.remote_file_path.split( '/' ).pop()}` ) ) {
57
- return false
54
+ if ( this.artifact.local_path ) {
55
+ command += ` --source-directory=${this.artifact.local_path}`
56
+ command += ' --skip-existing'
57
+ } else if ( this.artifact.local_file_path ) {
58
+ const files = await this.listFiles( this.artifact.remote_path )
59
+ if ( files.some( file => file.name.split( ':' ).pop().replaceAll( '%2F', '/' ) === `${this.artifact.remote_path}/${this.artifact.remote_file_path.split( '/' ).pop()}` ) ) {
60
+ err( `File already exists in the artifact registry: ${this.artifact.local_file_path}` )
61
+ return false
62
+ }
63
+ command += ` --source=${this.artifact.local_file_path}`
58
64
  }
59
- command += ` --source=${this.artifact.local_file_path}`
60
- }
61
65
 
62
- command += ` --destination-path=${this.artifact.remote_path}`
66
+ if ( this.artifact.remote_path ) {
67
+ command += ` --destination-path=${this.artifact.remote_path}`
68
+ }
63
69
 
64
- console.log( 'Command:', command.replace( /\s+/g, ' ' ).trim() )
70
+ debug( { command }, '<==Upload Command' )
65
71
 
66
- try {
67
- const { execSync } = await import( 'child_process' )
68
- execSync( command, { encoding : 'utf8', stdio : 'pipe' } )
69
- console.log( `Successfully published artifact: ${this.artifact.gcp_artifact_registry_package_name}:${this.artifact.gcp_artifact_registry_package_version}` )
72
+ await shellCmd( command )
73
+
74
+ log( `Successfully pushed artifact: ${this.artifact.name}` )
75
+
70
76
  return true
71
77
  } catch ( error ) {
72
- console.error( 'Error publishing artifact:', error.message )
78
+ err( `Error pushing artifact: ${this.artifact.name} ${error.message}` )
73
79
  return false
74
80
  }
75
81
  }
@@ -1,4 +1,4 @@
1
- import fs from 'fs'
1
+ import fs from 'node:fs'
2
2
  import crypto from 'crypto'
3
3
 
4
4
  import { validate } from 'superstruct'
@@ -70,35 +70,6 @@ const toExplicitPath = ( path ) => {
70
70
  return explicitPath
71
71
  }
72
72
 
73
- const buildGenericArtifactName = ( artifact ) => {
74
- const baseElements = [
75
- 'projects',
76
- artifact.gcp_project_id,
77
- 'locations',
78
- artifact.gcp_location,
79
- 'repositories',
80
- artifact.gcp_artifact_registry_repository_name,
81
- 'files',
82
- artifact.gcp_artifact_registry_package_name,
83
- ]
84
-
85
- const versionElement = artifact.gcp_artifact_registry_package_version
86
-
87
- const remotePathElements = []
88
-
89
- if ( artifact.remote_path || artifact.remote_file_path ) {
90
- const explicitRemotePath = toExplicitPath( artifact.remote_path || artifact.remote_file_path )
91
- const implicitRemotePath = toImplicitPath( explicitRemotePath )
92
- if ( implicitRemotePath !== '.' ) {
93
- remotePathElements.push( implicitRemotePath )
94
- }
95
- }
96
-
97
- const name = [ baseElements.join( '/' ), versionElement, encodeURIComponent( remotePathElements.join( '/' ) ) ].join( ':' )
98
-
99
- return name
100
- }
101
-
102
73
  const calculateHash = ( path ) => {
103
74
  try {
104
75
  const hash = crypto.createHash( 'sha256' )
@@ -110,4 +81,4 @@ const calculateHash = ( path ) => {
110
81
  }
111
82
  }
112
83
 
113
- export { calculateHash, getArtifactsSchema, flattenArtifactsSchema, toImplicitPath, toExplicitPath, buildGenericArtifactName }
84
+ export { calculateHash, getArtifactsSchema, flattenArtifactsSchema, toImplicitPath, toExplicitPath }
@@ -1,68 +1,74 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { warning } from '../Utils.mjs'
3
+ import { program } from 'commander'
4
+
5
+ import { warning, log } from '../Utils.mjs'
4
6
 
5
7
  import { getArtifactsSchema, flattenArtifactsSchema } from './Utils.mjs'
6
8
  import { ArtifactTypeEnum } from './Structs.mjs'
7
9
  import { GenericArtifactPuller } from './ArtifactPuller.mjs'
8
10
 
9
- async function main() {
11
+ program
12
+ .name( 'pull-artifact' )
13
+ .description( 'Pull artifacts from GCP Artifact Registry' )
14
+ .requiredOption( '-f, --file-path <path>', 'Path to artifacts.yaml file' )
15
+ .option( '-pn, --package-name <name>', 'Filter by artifact package name' )
16
+ .option( '-pv, --package-version <version>', 'Filter by artifact package version' )
17
+ .parse()
18
+
19
+ const options = program.opts()
10
20
 
11
- let artifactsYmlPath = null
12
- let artifactName = null
13
- let artifactPackageName = null
14
- let artifactPackageVersion = null
15
- let filteredArtifactSchema = null
21
+ async function main() {
22
+ const artifactsYmlPath = options.artifactsFilePath
23
+ const artifactPackageName = options.packageName || null
24
+ const artifactPackageVersion = options.packageVersion || null
25
+
26
+ const artifactsSchema = await getArtifactsSchema( artifactsYmlPath )
27
+ const flattenedArtifactsSchema = flattenArtifactsSchema( artifactsSchema )
16
28
 
17
- if ( process.argv.length === 3 ) {
18
- artifactsYmlPath = process.argv[2]
19
- filteredArtifactSchema = await getArtifactsSchema( artifactsYmlPath )
20
- const flattenedArtifactsSchema = flattenArtifactsSchema( filteredArtifactSchema )
21
- filteredArtifactSchema = flattenedArtifactsSchema
22
- } else if ( process.argv.length === 4 ) {
23
- artifactsYmlPath = process.argv[2]
24
- filteredArtifactSchema = await getArtifactsSchema( artifactsYmlPath )
25
- const flattenedArtifactsSchema = flattenArtifactsSchema( filteredArtifactSchema )
26
- filteredArtifactSchema = flattenedArtifactsSchema.find(
27
- artifact => artifact.name === artifactName )
28
- } else if ( process.argv.length === 5 ) {
29
- artifactsYmlPath = process.argv[2]
30
- artifactName = process.argv[3]
31
- artifactPackageName = process.argv[4]
32
- artifactPackageVersion = process.argv[5]
33
- filteredArtifactSchema = await getArtifactsSchema( artifactsYmlPath )
34
- const flattenedArtifactsSchema = flattenArtifactsSchema( filteredArtifactSchema )
35
- filteredArtifactSchema = flattenedArtifactsSchema.filter(
29
+ let filteredArtifactsSchema
30
+ if ( artifactPackageName && artifactPackageVersion ) {
31
+ filteredArtifactsSchema = flattenedArtifactsSchema.filter(
36
32
  artifact => artifact.gcp_artifact_registry_package_name === artifactPackageName &&
37
33
  artifact.gcp_artifact_registry_package_version === artifactPackageVersion )
34
+ } else if ( artifactPackageName ) {
35
+ filteredArtifactsSchema = flattenedArtifactsSchema.filter(
36
+ artifact => artifact.gcp_artifact_registry_package_name === artifactPackageName )
38
37
  } else {
39
- console.error( 'Usage:' )
40
- console.error( ' pull-artifact.mjs <artifacts.yml>' )
41
- console.error( ' pull-artifact.mjs <artifacts.yml> <artifact name>' )
42
- console.error( ' pull-artifact.mjs <artifacts.yml> <artifact package name> <artifact package version>' )
43
- process.exit( 1 )
38
+ filteredArtifactsSchema = flattenedArtifactsSchema
44
39
  }
40
+
41
+ let counter = 0
45
42
 
46
- // TODO: Use concurrency to pull artifacts and provide summary of results.
47
- for ( const artifactSchema of filteredArtifactSchema ) {
48
- let puller
49
- switch ( artifactSchema.type ) {
50
- case ArtifactTypeEnum.GENERIC:
51
- puller = new GenericArtifactPuller( artifactSchema )
52
- break
53
- default:
43
+ const pullResults = await Promise.all(
44
+ filteredArtifactsSchema.map( async ( artifactSchema ) => {
45
+ let puller
46
+ switch ( artifactSchema.type ) {
47
+ case ArtifactTypeEnum.GENERIC:
48
+ puller = new GenericArtifactPuller( artifactSchema )
49
+ break
50
+ default:
51
+ warning( `Unsupported artifact type "${artifactSchema.type}"` )
52
+ return false
53
+ }
54
+
55
+ if ( !puller ) {
54
56
  warning( `Unsupported artifact type "${artifactSchema.type}"` )
55
- continue
56
- }
57
-
58
- if ( !puller ) {
59
- warning( `Unsupported artifact type "${artifactSchema.type}"` )
60
- continue
61
- }
62
-
63
- // eslint-disable-next-line no-await-in-loop
64
- await puller.pull()
65
- }
57
+ return false
58
+ }
59
+
60
+ try {
61
+ return await puller.pull()
62
+ } catch ( error ) {
63
+ warning( `Error pulling artifact "${artifactSchema.name}": ${error.message}` )
64
+ return false
65
+ }
66
+ } )
67
+ )
68
+
69
+ counter = pullResults.filter( Boolean ).length
70
+
71
+ log( `Successfully pulled ${counter}/${filteredArtifactsSchema.length} artifacts` )
66
72
  }
67
73
 
68
74
  main()
@@ -1,68 +1,74 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { warning } from '../Utils.mjs'
3
+ import { program } from 'commander'
4
+
5
+ import { warning, log } from '../Utils.mjs'
4
6
 
5
7
  import { getArtifactsSchema, flattenArtifactsSchema } from './Utils.mjs'
6
8
  import { ArtifactTypeEnum } from './Structs.mjs'
7
9
  import { GenericArtifactPusher } from './ArtifactPusher.mjs'
8
10
 
9
- async function main() {
11
+ program
12
+ .name( 'push-artifact' )
13
+ .description( 'Push artifacts to GCP Artifact Registry' )
14
+ .requiredOption( '-f, --file-path <path>', 'Path to artifacts.yaml file' )
15
+ .option( '-pn, --package-name <name>', 'Filter by artifact package name' )
16
+ .option( '-pv, --package-version <version>', 'Filter by artifact package version' )
17
+ .parse()
18
+
19
+ const options = program.opts()
10
20
 
11
- let artifactsYmlPath = null
12
- let artifactName = null
13
- let artifactPackageName = null
14
- let artifactPackageVersion = null
15
- let filteredArtifactSchema = null
21
+ async function main() {
22
+ const artifactsYmlPath = options.artifactsFilePath
23
+ const artifactPackageName = options.packageName || null
24
+ const artifactPackageVersion = options.packageVersion || null
25
+
26
+ const artifactsSchema = await getArtifactsSchema( artifactsYmlPath )
27
+ const flattenedArtifactsSchema = flattenArtifactsSchema( artifactsSchema )
16
28
 
17
- if ( process.argv.length === 3 ) {
18
- artifactsYmlPath = process.argv[2]
19
- filteredArtifactSchema = await getArtifactsSchema( artifactsYmlPath )
20
- const flattenedArtifactsSchema = flattenArtifactsSchema( filteredArtifactSchema )
21
- filteredArtifactSchema = flattenedArtifactsSchema
22
- } else if ( process.argv.length === 4 ) {
23
- artifactsYmlPath = process.argv[2]
24
- filteredArtifactSchema = await getArtifactsSchema( artifactsYmlPath )
25
- const flattenedArtifactsSchema = flattenArtifactsSchema( filteredArtifactSchema )
26
- filteredArtifactSchema = flattenedArtifactsSchema.find(
27
- artifact => artifact.name === artifactName )
28
- } else if ( process.argv.length === 5 ) {
29
- artifactsYmlPath = process.argv[2]
30
- artifactName = process.argv[3]
31
- artifactPackageName = process.argv[4]
32
- artifactPackageVersion = process.argv[5]
33
- filteredArtifactSchema = await getArtifactsSchema( artifactsYmlPath )
34
- const flattenedArtifactsSchema = flattenArtifactsSchema( filteredArtifactSchema )
35
- filteredArtifactSchema = flattenedArtifactsSchema.filter(
29
+ let filteredArtifactsSchema
30
+ if ( artifactPackageName && artifactPackageVersion ) {
31
+ filteredArtifactsSchema = flattenedArtifactsSchema.filter(
36
32
  artifact => artifact.gcp_artifact_registry_package_name === artifactPackageName &&
37
33
  artifact.gcp_artifact_registry_package_version === artifactPackageVersion )
34
+ } else if ( artifactPackageName ) {
35
+ filteredArtifactsSchema = flattenedArtifactsSchema.filter(
36
+ artifact => artifact.gcp_artifact_registry_package_name === artifactPackageName )
38
37
  } else {
39
- console.error( 'Usage:' )
40
- console.error( ' push-artifact.mjs <artifacts.yml>' )
41
- console.error( ' push-artifact.mjs <artifacts.yml> <artifact name>' )
42
- console.error( ' push-artifact.mjs <artifacts.yml> <artifact package name> <artifact package version>' )
43
- process.exit( 1 )
38
+ filteredArtifactsSchema = flattenedArtifactsSchema
44
39
  }
45
40
 
46
- // TODO: Use concurrency to push artifacts and provide summary of results.
47
- for ( const artifactSchema of filteredArtifactSchema ) {
48
- let pusher
49
- switch ( artifactSchema.type ) {
50
- case ArtifactTypeEnum.GENERIC:
51
- pusher = new GenericArtifactPusher( artifactSchema )
52
- break
53
- default:
41
+ let counter = 0
42
+
43
+ const pushResults = await Promise.all(
44
+ filteredArtifactsSchema.map( async ( artifactSchema ) => {
45
+ let pusher
46
+ switch ( artifactSchema.type ) {
47
+ case ArtifactTypeEnum.GENERIC:
48
+ pusher = new GenericArtifactPusher( artifactSchema )
49
+ break
50
+ default:
51
+ warning( `Unsupported artifact type "${artifactSchema.type}"` )
52
+ return false
53
+ }
54
+
55
+ if ( !pusher ) {
54
56
  warning( `Unsupported artifact type "${artifactSchema.type}"` )
55
- continue
56
- }
57
-
58
- if ( !pusher ) {
59
- warning( `Unsupported artifact type "${artifactSchema.type}"` )
60
- continue
61
- }
62
-
63
- // eslint-disable-next-line no-await-in-loop
64
- await pusher.push()
65
- }
57
+ return false
58
+ }
59
+
60
+ try {
61
+ return await pusher.push()
62
+ } catch ( error ) {
63
+ warning( `Error pushing artifact "${artifactSchema.name}": ${error.message}` )
64
+ return false
65
+ }
66
+ } )
67
+ )
68
+
69
+ counter = pushResults.filter( Boolean ).length
70
+
71
+ log( `Successfully pushed ${counter}/${filteredArtifactsSchema.length} artifacts` )
66
72
  }
67
73
 
68
74
  main()