@leverege/build-tools 2.93.0-beta.10 → 2.93.0-beta.12

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leverege/build-tools",
3
- "version": "2.93.0-beta.10",
3
+ "version": "2.93.0-beta.12",
4
4
  "description": "A collection of build / support tools for Leverege developers",
5
5
  "main": "index.js",
6
6
  "repository": {
@@ -1,7 +1,11 @@
1
- import crypto from 'crypto'
1
+ /* eslint-disable security/detect-non-literal-fs-filename */
2
2
  import fs from 'fs'
3
3
 
4
- class ArtifactPusher {
4
+ import { shellCmd, log, debug, err } from '../Utils.mjs'
5
+
6
+ import { toExplicitPath } from './Utils.mjs'
7
+
8
+ class ArtifactPuller {
5
9
  constructor( artifact ) {
6
10
  this.artifact = artifact
7
11
  }
@@ -11,11 +15,141 @@ class ArtifactPusher {
11
15
  }
12
16
  }
13
17
 
14
- class GenericArtifactPusher extends ArtifactPusher {
18
+ class GenericArtifactPuller extends ArtifactPuller {
19
+
20
+ async downloadFile( remoteFilePath, localFilePath ) {
21
+ debug( { remoteFilePath, localFilePath }, '<==Download File' )
22
+
23
+ const command = `gcloud artifacts generic download \
24
+ --project=${this.artifact.gcp_project_id} \
25
+ --location=${this.artifact.gcp_location} \
26
+ --repository=${this.artifact.gcp_artifact_registry_repository_name} \
27
+ --package=${this.artifact.gcp_artifact_registry_package_name} \
28
+ --version=${this.artifact.gcp_artifact_registry_package_version} \
29
+ --name="${remoteFilePath}" \
30
+ --destination=/tmp`
31
+
32
+ const oldPath = `/tmp/${remoteFilePath.split( '/' ).pop()}`
33
+ const newPath = localFilePath
34
+
35
+ // if file exists in the old path, delete it
36
+ if ( fs.existsSync( oldPath ) ) {
37
+ fs.unlinkSync( oldPath )
38
+ }
39
+
40
+ // if file exists in the new path, delete it
41
+ if ( fs.existsSync( newPath ) ) {
42
+ fs.unlinkSync( newPath )
43
+ }
44
+
45
+ // Ensure the directory exists
46
+ fs.mkdirSync( localFilePath.split( '/' ).slice( 0, -1 ).join( '/' ), { recursive : true } )
47
+
48
+ debug( { command }, '<==Download File Command' )
49
+
50
+ await shellCmd( command )
51
+
52
+ // Check if file exists in the old path
53
+ if ( !fs.existsSync( oldPath ) ) {
54
+ debug( { oldPath }, '<==File does not exist in the old path' )
55
+ return false
56
+ }
57
+
58
+ debug( { oldPath, newPath }, '<==Copying file' )
59
+
60
+ await fs.copyFileSync( oldPath, newPath )
61
+
62
+ // Check if file exists in the new path
63
+ if ( !fs.existsSync( newPath ) ) {
64
+ debug( { newPath }, '<==File does not exist in the new path' )
65
+ return false
66
+ }
67
+
68
+ return true
69
+ }
70
+
71
+ async downloadDirectory( localPath ) {
72
+ const command = `gcloud artifacts generic download \
73
+ --project=${this.artifact.gcp_project_id} \
74
+ --location=${this.artifact.gcp_location} \
75
+ --repository=${this.artifact.gcp_artifact_registry_repository_name} \
76
+ --package=${this.artifact.gcp_artifact_registry_package_name} \
77
+ --version=${this.artifact.gcp_artifact_registry_package_version} \
78
+ --destination=${localPath}`
79
+
80
+ debug( { command }, '<==Download Directory Command' )
81
+
82
+ await shellCmd( command )
83
+ }
84
+
85
+ async downloadNestedDirectory( remotePath, localPath ) {
86
+ debug( { remotePath, localPath }, '<==Download Nested Directory' )
87
+
88
+ const files = await this.listFiles( remotePath )
89
+ await Promise.all(
90
+ files
91
+ .filter( file => file.name.split( ':' ).pop().replaceAll( '%2F', '/' ).startsWith( remotePath ) )
92
+ .map( async ( file ) => {
93
+ const remoteFilePath = file.name.split( ':' ).pop().replaceAll( '%2F', '/' )
94
+ const localFilePath = `${localPath}${remoteFilePath.replaceAll( remotePath, '' )}`
95
+ await this.downloadFile( remoteFilePath, localFilePath )
96
+ } )
97
+ )
98
+ }
99
+
100
+ async listFiles( ) {
101
+ const command = `gcloud artifacts files list \
102
+ --project=${this.artifact.gcp_project_id} \
103
+ --location=${this.artifact.gcp_location} \
104
+ --repository=${this.artifact.gcp_artifact_registry_repository_name} \
105
+ --package=${this.artifact.gcp_artifact_registry_package_name} \
106
+ --version ${this.artifact.gcp_artifact_registry_package_version} \
107
+ --format="json"`
108
+
109
+ debug( { command }, '<==List Files Command' )
110
+
111
+ const result = await shellCmd( command )
112
+
113
+ // Parse the JSON response
114
+ const files = JSON.parse( result )
115
+ return files
116
+ }
15
117
 
16
118
  async pull() {
17
- throw new Error( 'Not implemented' )
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}` )
150
+ }
151
+ return false
18
152
  }
19
153
  }
20
154
 
21
- export { ArtifactPusher, GenericArtifactPusher }
155
+ export { ArtifactPuller, GenericArtifactPuller }
@@ -1,25 +1,10 @@
1
- import crypto from 'crypto'
2
- import fs from 'fs'
1
+ /* eslint-disable security/detect-non-literal-fs-filename */
2
+ import { shellCmd, log, err, debug } from '../Utils.mjs'
3
3
 
4
4
  class ArtifactPusher {
5
5
  constructor( artifact ) {
6
6
  this.artifact = artifact
7
7
  }
8
-
9
- calculateHash() {
10
- try {
11
- const hash = crypto.createHash( 'sha256' )
12
- hash.update( fs.readFileSync( this.artifact.source_path ) )
13
- return hash.digest( 'base64url' )
14
- } catch ( error ) {
15
- console.error( error )
16
- throw new Error( `Failed to calculate hash for artifact ${this.artifact.name}: ${error.message}` )
17
- }
18
- }
19
-
20
- async exists() {
21
- throw new Error( 'Not implemented' )
22
- }
23
8
 
24
9
  async push() {
25
10
  throw new Error( 'Not implemented' )
@@ -28,103 +13,69 @@ class ArtifactPusher {
28
13
 
29
14
  class GenericArtifactPusher extends ArtifactPusher {
30
15
 
31
- async exists() {
32
- const isDirectory = fs.statSync( this.artifact.source_path ).isDirectory()
33
-
34
- // If source path is a directory, check whether the destination path alreadu exists in the registry
35
- if ( isDirectory ) {
36
- // For the time being, return false, and let gcloud skip existing files in upload-time.
37
- // It's pretty slow, might be worth to break down the directory into individual artifacts
38
- // and manage each one with its own pusher.
39
- return false
40
- }
41
-
42
- // Check if artifact already exists in the registry
43
- console.log( 'Checking if artifact already exists in the registry...' )
44
-
45
- const artifactHash = this.calculateHash()
46
-
16
+ async listFiles( ) {
47
17
  const command = `gcloud artifacts files list \
48
- --project=${this.artifact.gcp_project_id} \
49
- --location=${this.artifact.gcp_location} \
50
- --repository=${this.artifact.gcp_artifact_registry_repository_name} \
51
- --package=${this.artifact.gcp_artifact_registry_package_name} \
52
- --version ${this.artifact.gcp_artifact_registry_package_version} \
53
- --filter="name:${this.artifact.destination_path}" \
54
- --format="json"`
18
+ --project=${this.artifact.gcp_project_id} \
19
+ --location=${this.artifact.gcp_location} \
20
+ --repository=${this.artifact.gcp_artifact_registry_repository_name} \
21
+ --package=${this.artifact.gcp_artifact_registry_package_name} \
22
+ --version ${this.artifact.gcp_artifact_registry_package_version} \
23
+ --format="json"`
55
24
 
56
- console.log( 'Command:', command.replace( /\s+/g, ' ' ).trim() )
57
-
58
- try {
59
- const { execSync } = await import( 'child_process' )
60
- const result = execSync( command, { encoding : 'utf8', stdio : 'pipe' } )
25
+ debug( { command }, '<==List Files Command' )
26
+
27
+ const result = await shellCmd( command )
28
+
29
+ // Parse the JSON response
30
+ const files = JSON.parse( result )
61
31
 
62
- // Parse the JSON response
63
- const files = JSON.parse( result )
64
-
65
- // Check if any files were found and match our hash
66
- if ( files && files.length > 0 ) {
67
- for ( const file of files ) {
68
- for ( const hash of file.hashes ) {
69
- // Compare without padding since base64url may omit trailing '='
70
- const normalizedOurHash = artifactHash.replace( /=+$/, '' )
71
- const normalizedRegistryHash = hash.value.replace( /=+$/, '' )
72
- if ( hash.type === 'SHA256' && normalizedRegistryHash === normalizedOurHash ) {
73
- console.log( `Artifact already exists in the registry: ${this.artifact.gcp_artifact_registry_package_name}:${this.artifact.gcp_artifact_registry_package_version}` )
74
- return true
75
- }
76
- }
77
- }
78
- }
79
- console.log( 'Artifact does not exist in the registry' )
80
- return false
81
-
82
- } catch ( error ) {
83
- console.error( 'Error checking artifact existence:', error.message )
84
- throw error
85
- }
32
+ return files
86
33
  }
87
34
 
88
35
  async push() {
89
- console.log( 'Publishing artifact to registry...' )
36
+ log( `Pushing artifact: ${this.artifact.name}` )
90
37
 
91
- if ( await this.exists() ) {
92
- console.log( 'Artifact already exists in the registry' )
38
+ if ( this.artifact.remote_file_path ) {
39
+ err( 'Remote file path is not supported for pushing artifacts' )
93
40
  return false
94
41
  }
95
42
 
96
- console.log( 'Uploading artifact to registry...' )
43
+ try {
97
44
 
98
- let command = ''
45
+ let command = ''
99
46
 
100
- command = `gcloud artifacts generic upload \
47
+ command = `gcloud artifacts generic upload \
101
48
  --project=${this.artifact.gcp_project_id} \
102
49
  --location=${this.artifact.gcp_location} \
103
50
  --repository=${this.artifact.gcp_artifact_registry_repository_name} \
104
51
  --package=${this.artifact.gcp_artifact_registry_package_name} \
105
52
  --version=${this.artifact.gcp_artifact_registry_package_version}`
106
53
 
107
- const isDirectory = fs.statSync( this.artifact.source_path ).isDirectory()
108
- if ( isDirectory ) {
109
- command += ` --source-directory=${this.artifact.source_path}`
110
- command += ' --skip-existing'
111
- } else {
112
- command += ` --source=${this.artifact.source_path}`
113
- }
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}`
64
+ }
114
65
 
115
- if ( this.artifact.destination_path ) {
116
- command += ` --destination-path=${this.artifact.destination_path}`
117
- }
118
-
119
- console.log( 'Command:', command.replace( /\s+/g, ' ' ).trim() )
66
+ if ( this.artifact.remote_path ) {
67
+ command += ` --destination-path=${this.artifact.remote_path}`
68
+ }
69
+
70
+ debug( { command }, '<==Upload Command' )
120
71
 
121
- try {
122
- const { execSync } = await import( 'child_process' )
123
- execSync( command, { encoding : 'utf8', stdio : 'pipe' } )
124
- 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
+
125
76
  return true
126
77
  } catch ( error ) {
127
- console.error( 'Error publishing artifact:', error.message )
78
+ err( `Error pushing artifact: ${this.artifact.name} ${error.message}` )
128
79
  return false
129
80
  }
130
81
  }
@@ -1,4 +1,4 @@
1
- import { assign, object, string, array, optional, enums, union } from 'superstruct'
1
+ import { assign, object, string, array, optional, enums, union, refine } from 'superstruct'
2
2
 
3
3
  const ArtifactTypeEnum = {
4
4
  GENERIC : 'generic',
@@ -25,16 +25,44 @@ const ArtifactSchema = assign( PartialArtifactSchema, object( {
25
25
  gcp_artifact_registry_package_version : string()
26
26
  } ) )
27
27
 
28
- const PartialGenericArtifactSchema = assign( PartialArtifactSchema, object( {
29
- type : enums( [ ArtifactTypeEnum.GENERIC ] ),
30
- source_path : string(),
31
- destination_path : string()
32
- } ) )
28
+ const PartialGenericArtifactSchema = refine(
29
+ assign( PartialArtifactSchema, object( {
30
+ type : enums( [ ArtifactTypeEnum.GENERIC ] ),
31
+ local_file_path : optional( string() ),
32
+ local_path : optional( string() ),
33
+ remote_file_path : optional( string() ),
34
+ remote_path : optional( string() )
35
+ } ) ),
36
+ 'ConflictingPaths',
37
+ ( value ) => {
38
+ if ( value.local_file_path && value.local_path ) {
39
+ return 'Only one of local_file_path or local_path must be provided'
40
+ }
41
+ if ( value.remote_file_path && value.remote_path ) {
42
+ return 'Only one of remote_file_path or remote_path must be provided'
43
+ }
44
+ return true
45
+ }
46
+ )
33
47
 
34
- const GenericArtifactSchema = assign( ArtifactSchema, object( {
35
- source_path : string(),
36
- destination_path : optional( string() )
37
- } ) )
48
+ const GenericArtifactSchema = refine(
49
+ assign( ArtifactSchema, object( {
50
+ local_file_path : optional( string() ),
51
+ local_path : optional( string() ),
52
+ remote_file_path : optional( string() ),
53
+ remote_path : optional( string() )
54
+ } ) ),
55
+ 'ConflictingPaths',
56
+ ( value ) => {
57
+ if ( value.local_file_path && value.local_path ) {
58
+ return 'Only one of local_file_path or local_path must be provided'
59
+ }
60
+ if ( value.remote_file_path && value.remote_path ) {
61
+ return 'Only one of remote_file_path or remote_path must be provided'
62
+ }
63
+ return true
64
+ }
65
+ )
38
66
 
39
67
  // Superstruct schema for defaults configuration
40
68
  const DefaultsSchema = object( {
@@ -1,3 +1,6 @@
1
+ import fs from 'fs'
2
+ import crypto from 'crypto'
3
+
1
4
  import { validate } from 'superstruct'
2
5
 
3
6
  import { parseYamlFile, warning } from '../Utils.mjs'
@@ -46,4 +49,36 @@ const flattenArtifactsSchema = ( artifactsSchema ) => {
46
49
  }, [] )
47
50
  }
48
51
 
49
- export { getArtifactsSchema, flattenArtifactsSchema }
52
+ const toImplicitPath = ( path ) => {
53
+ let implicitPath = path
54
+ // Remove leading './' if present
55
+ if ( implicitPath.startsWith( './' ) ) {
56
+ implicitPath = implicitPath.slice( 2 )
57
+ }
58
+ // Remove trailing slash
59
+ implicitPath = implicitPath.replace( /\/+$/, '' )
60
+ return implicitPath
61
+ }
62
+
63
+ const toExplicitPath = ( path ) => {
64
+ let explicitPath = path
65
+ // Keep absolute paths and paths already starting with '.' as-is
66
+ if ( !path.startsWith( '/' ) && !path.startsWith( '.' ) ) {
67
+ // Add './' to relative paths
68
+ explicitPath = `./${explicitPath}`
69
+ }
70
+ return explicitPath
71
+ }
72
+
73
+ const calculateHash = ( path ) => {
74
+ try {
75
+ const hash = crypto.createHash( 'sha256' )
76
+ hash.update( fs.readFileSync( path ) )
77
+ return hash.digest( 'base64url' )
78
+ } catch ( error ) {
79
+ console.error( error )
80
+ throw new Error( `Failed to calculate hash for artifact ${path}: ${error.message}` )
81
+ }
82
+ }
83
+
84
+ export { calculateHash, getArtifactsSchema, flattenArtifactsSchema, toImplicitPath, toExplicitPath }
@@ -1,7 +1,71 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ import { warning, err, log } from '../Utils.mjs'
4
+
5
+ import { getArtifactsSchema, flattenArtifactsSchema } from './Utils.mjs'
6
+ import { ArtifactTypeEnum } from './Structs.mjs'
7
+ import { GenericArtifactPuller } from './ArtifactPuller.mjs'
8
+
3
9
  async function main() {
4
- return null
10
+
11
+ if ( process.argv.length < 3 ) {
12
+ err( 'Usage:' )
13
+ err( ' pull-artifact.mjs <artifacts.yml>' )
14
+ err( ' pull-artifact.mjs <artifacts.yml> <artifact package name>' )
15
+ err( ' pull-artifact.mjs <artifacts.yml> <artifact package name> <artifact package version>' )
16
+ process.exit( 1 )
17
+ }
18
+
19
+ const artifactsYmlPath = process.argv[2]
20
+ const artifactPackageName = process.argv.length > 3 ? process.argv[3] : null
21
+ const artifactPackageVersion = process.argv.length > 4 ? process.argv[4] : null
22
+
23
+ const artifactsSchema = await getArtifactsSchema( artifactsYmlPath )
24
+ const flattenedArtifactsSchema = flattenArtifactsSchema( artifactsSchema )
25
+
26
+ let filteredArtifactsSchema
27
+ if ( artifactPackageName && artifactPackageVersion ) {
28
+ filteredArtifactsSchema = flattenedArtifactsSchema.filter(
29
+ artifact => artifact.gcp_artifact_registry_package_name === artifactPackageName &&
30
+ artifact.gcp_artifact_registry_package_version === artifactPackageVersion )
31
+ } else if ( artifactPackageName ) {
32
+ filteredArtifactsSchema = flattenedArtifactsSchema.filter(
33
+ artifact => artifact.gcp_artifact_registry_package_name === artifactPackageName )
34
+ } else {
35
+ filteredArtifactsSchema = flattenedArtifactsSchema
36
+ }
37
+
38
+ let counter = 0
39
+
40
+ const pullResults = await Promise.all(
41
+ filteredArtifactsSchema.map( async ( artifactSchema ) => {
42
+ let puller
43
+ switch ( artifactSchema.type ) {
44
+ case ArtifactTypeEnum.GENERIC:
45
+ puller = new GenericArtifactPuller( artifactSchema )
46
+ break
47
+ default:
48
+ warning( `Unsupported artifact type "${artifactSchema.type}"` )
49
+ return false
50
+ }
51
+
52
+ if ( !puller ) {
53
+ warning( `Unsupported artifact type "${artifactSchema.type}"` )
54
+ return false
55
+ }
56
+
57
+ try {
58
+ return await puller.pull()
59
+ } catch ( error ) {
60
+ warning( `Error pulling artifact "${artifactSchema.name}": ${error.message}` )
61
+ return false
62
+ }
63
+ } )
64
+ )
65
+
66
+ counter = pullResults.filter( Boolean ).length
67
+
68
+ log( `Successfully pushed ${counter}/${filteredArtifactsSchema.length} artifacts` )
5
69
  }
6
70
 
7
71
  main()
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { warning } from '../Utils.mjs'
3
+ import { warning, err, log } from '../Utils.mjs'
4
4
 
5
5
  import { getArtifactsSchema, flattenArtifactsSchema } from './Utils.mjs'
6
6
  import { ArtifactTypeEnum } from './Structs.mjs'
@@ -8,47 +8,64 @@ import { GenericArtifactPusher } from './ArtifactPusher.mjs'
8
8
 
9
9
  async function main() {
10
10
 
11
- // If an argument is provided, use it as the artifacts.yml file path
11
+ if ( process.argv.length < 3 ) {
12
+ err( 'Usage:' )
13
+ err( ' push-artifact.mjs <artifacts.yml>' )
14
+ err( ' push-artifact.mjs <artifacts.yml> <artifact package name>' )
15
+ err( ' push-artifact.mjs <artifacts.yml> <artifact package name> <artifact package version>' )
16
+ process.exit( 1 )
17
+ }
18
+
12
19
  const artifactsYmlPath = process.argv[2]
13
- const artifactPackageName = process.argv[3]
14
- const artifactPackageVersion = process.argv[4]
15
-
16
- if ( artifactsYmlPath ) {
17
- const artifactsSchema = await getArtifactsSchema( artifactsYmlPath )
18
- const flattenedArtifactsSchema = flattenArtifactsSchema( artifactsSchema )
19
-
20
- // Open for unexpected matches if we end up re-using the same package name and version for
21
- // multiple artifacts spread across multiple repositories and/or projects.
22
- const filteredArtifactSchemas = flattenedArtifactsSchema.filter(
20
+ const artifactPackageName = process.argv.length > 3 ? process.argv[3] : null
21
+ const artifactPackageVersion = process.argv.length > 4 ? process.argv[4] : null
22
+
23
+ const artifactsSchema = await getArtifactsSchema( artifactsYmlPath )
24
+ const flattenedArtifactsSchema = flattenArtifactsSchema( artifactsSchema )
25
+
26
+ let filteredArtifactsSchema
27
+ if ( artifactPackageName && artifactPackageVersion ) {
28
+ filteredArtifactsSchema = flattenedArtifactsSchema.filter(
23
29
  artifact => artifact.gcp_artifact_registry_package_name === artifactPackageName &&
24
30
  artifact.gcp_artifact_registry_package_version === artifactPackageVersion )
25
-
26
- if ( filteredArtifactSchemas.length === 0 ) {
27
- console.error( `No artifacts found for ${artifactPackageName} version ${artifactPackageVersion} in ${artifactsYmlPath}` )
28
- process.exit( 1 )
29
- }
30
-
31
- // TODO: Use concurrency to package artifacts and provide summary of results.
32
- for ( const artifactSchema of filteredArtifactSchemas ) {
33
- let packager
31
+ } else if ( artifactPackageName ) {
32
+ filteredArtifactsSchema = flattenedArtifactsSchema.filter(
33
+ artifact => artifact.gcp_artifact_registry_package_name === artifactPackageName )
34
+ } else {
35
+ filteredArtifactsSchema = flattenedArtifactsSchema
36
+ }
37
+
38
+ let counter = 0
39
+
40
+ const pushResults = await Promise.all(
41
+ filteredArtifactsSchema.map( async ( artifactSchema ) => {
42
+ let pusher
34
43
  switch ( artifactSchema.type ) {
35
44
  case ArtifactTypeEnum.GENERIC:
36
- packager = new GenericArtifactPusher( artifactSchema )
45
+ pusher = new GenericArtifactPusher( artifactSchema )
37
46
  break
38
47
  default:
39
48
  warning( `Unsupported artifact type "${artifactSchema.type}"` )
40
- continue
49
+ return false
41
50
  }
42
-
43
- if ( !packager ) {
51
+
52
+ if ( !pusher ) {
44
53
  warning( `Unsupported artifact type "${artifactSchema.type}"` )
45
- continue
54
+ return false
46
55
  }
47
-
48
- // eslint-disable-next-line no-await-in-loop
49
- await packager.package()
50
- }
51
- }
56
+
57
+ try {
58
+ return await pusher.push()
59
+ } catch ( error ) {
60
+ warning( `Error pushing artifact "${artifactSchema.name}": ${error.message}` )
61
+ return false
62
+ }
63
+ } )
64
+ )
65
+
66
+ counter = pushResults.filter( Boolean ).length
67
+
68
+ log( `Successfully pushed ${counter}/${filteredArtifactsSchema.length} artifacts` )
52
69
  }
53
70
 
54
71
  main()