@leverege/build-tools 2.93.0-beta.15 → 2.93.0-beta.2
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 +1 -9
- package/package.json +2 -3
- package/src/package-artifact/Packager.mjs +118 -0
- package/src/package-artifact/Structs.mjs +60 -0
- package/src/package-artifact/Utils.mjs +49 -0
- package/src/package-artifact/command.mjs +49 -0
- package/src/artifacts/ArtifactPuller.mjs +0 -155
- package/src/artifacts/ArtifactPusher.mjs +0 -84
- package/src/artifacts/Structs.mjs +0 -91
- package/src/artifacts/Utils.mjs +0 -84
- package/src/artifacts/pull-artifact.mjs +0 -74
- package/src/artifacts/push-artifact.mjs +0 -74
package/README.md
CHANGED
|
@@ -18,15 +18,7 @@ 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
|
|
22
|
-
* **pull-artifact**: used to pull generic artifacts from the GCP artifact registry
|
|
23
|
-
```bash
|
|
24
|
-
Usage: pull-artifact -f <artifact schema file path> -n <package name> -v <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> -n <package name> -v <package version>
|
|
29
|
-
```
|
|
21
|
+
* **docker-to-registry**: used to build and deploy docker images to the GCP image area
|
|
30
22
|
|
|
31
23
|
### Helm Helpers:
|
|
32
24
|
* **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.
|
|
3
|
+
"version": "2.93.0-beta.2",
|
|
4
4
|
"description": "A collection of build / support tools for Leverege developers",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"repository": {
|
|
@@ -50,13 +50,12 @@
|
|
|
50
50
|
"npm-link": "src/npm-link.sh",
|
|
51
51
|
"npm-unlink": "src/npm-unlink.sh",
|
|
52
52
|
"overwhelm": "src/overwhelm.mjs",
|
|
53
|
+
"package-artifact": "src/package-artifact/command.mjs",
|
|
53
54
|
"pkgck": "src/pkgck.sh",
|
|
54
55
|
"pkglint": "src/pkglint.sh",
|
|
55
56
|
"prepack": "src/prepack.mjs",
|
|
56
57
|
"prune-git": "src/prune-git.sh",
|
|
57
|
-
"pull-artifact": "src/artifacts/pull-artifact.mjs",
|
|
58
58
|
"pull-git": "src/pull-git.sh",
|
|
59
|
-
"push-artifact": "src/artifacts/push-artifact.mjs",
|
|
60
59
|
"push-my-chart": "src/push-my-chart.mjs",
|
|
61
60
|
"refresh-npm-token": "src/refresh-npm-token.mjs",
|
|
62
61
|
"refresh-py-idx": "src/refresh-py-idx.sh",
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import crypto from 'crypto'
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
|
|
4
|
+
class ArtifactPackager {
|
|
5
|
+
constructor( artifact ) {
|
|
6
|
+
this.artifact = artifact
|
|
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
|
+
throw new Error( `Failed to calculate hash for artifact ${this.artifact.name}: ${error.message}` )
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async exists() {
|
|
20
|
+
throw new Error( 'Not implemented' )
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async build() {
|
|
24
|
+
throw new Error( 'Not implemented' )
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async publish() {
|
|
28
|
+
throw new Error( 'Not implemented' )
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async package() {
|
|
32
|
+
if ( await this.exists() ) {
|
|
33
|
+
console.log( 'Artifact already exists in the registry' )
|
|
34
|
+
return false
|
|
35
|
+
}
|
|
36
|
+
await this.build()
|
|
37
|
+
return this.publish()
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
class GenericArtifactPackager extends ArtifactPackager {
|
|
42
|
+
|
|
43
|
+
async exists() {
|
|
44
|
+
// Check if artifact already exists in the registry
|
|
45
|
+
console.log( 'Checking if artifact already exists in the registry...' )
|
|
46
|
+
|
|
47
|
+
const artifactHash = this.calculateHash()
|
|
48
|
+
|
|
49
|
+
const command = `gcloud artifacts files list \
|
|
50
|
+
--project=${this.artifact.gcp_project_id} \
|
|
51
|
+
--location=${this.artifact.gcp_location} \
|
|
52
|
+
--repository=${this.artifact.gcp_artifact_registry_repository_name} \
|
|
53
|
+
--package=${this.artifact.gcp_artifact_registry_package_name} \
|
|
54
|
+
--version ${this.artifact.gcp_artifact_registry_package_version} \
|
|
55
|
+
--filter="name:${this.artifact.destination_path}" \
|
|
56
|
+
--format="json"`
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const { execSync } = await import( 'child_process' )
|
|
60
|
+
const result = execSync( command, { encoding : 'utf8', stdio : 'pipe' } )
|
|
61
|
+
|
|
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
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async build() {
|
|
89
|
+
return true
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async publish() {
|
|
93
|
+
console.log( 'Publishing artifact to registry...' )
|
|
94
|
+
|
|
95
|
+
const command = `gcloud artifacts generic upload \
|
|
96
|
+
--project=${this.artifact.gcp_project_id} \
|
|
97
|
+
--location=${this.artifact.gcp_location} \
|
|
98
|
+
--repository=${this.artifact.gcp_artifact_registry_repository_name} \
|
|
99
|
+
--package=${this.artifact.gcp_artifact_registry_package_name} \
|
|
100
|
+
--version=${this.artifact.gcp_artifact_registry_package_version} \
|
|
101
|
+
--source=${this.artifact.source_path} \
|
|
102
|
+
--destination-path=${this.artifact.destination_path}`
|
|
103
|
+
|
|
104
|
+
// console.log( 'Command:', command )
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
const { execSync } = await import( 'child_process' )
|
|
108
|
+
execSync( command, { encoding : 'utf8', stdio : 'pipe' } )
|
|
109
|
+
console.log( `Successfully published artifact: ${this.artifact.gcp_artifact_registry_package_name}:${this.artifact.gcp_artifact_registry_package_version}` )
|
|
110
|
+
return true
|
|
111
|
+
} catch ( error ) {
|
|
112
|
+
console.error( 'Error publishing artifact:', error.message )
|
|
113
|
+
return false
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export { ArtifactPackager, GenericArtifactPackager }
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { assign, object, string, array, optional, enums, union } from 'superstruct'
|
|
2
|
+
|
|
3
|
+
const ArtifactTypeEnum = enums( [ 'generic' ] )
|
|
4
|
+
|
|
5
|
+
// Superstruct schema for individual artifact configuration
|
|
6
|
+
const PartialArtifactEntrySchema = object( {
|
|
7
|
+
name : string(),
|
|
8
|
+
type : optional( ArtifactTypeEnum ),
|
|
9
|
+
gcp_project_id : optional( string() ),
|
|
10
|
+
gcp_location : optional( string() ),
|
|
11
|
+
gcp_artifact_registry_repository_name : optional( string() ),
|
|
12
|
+
gcp_artifact_registry_package_name : optional( string() ),
|
|
13
|
+
gcp_artifact_registry_package_version : optional( string() )
|
|
14
|
+
} )
|
|
15
|
+
|
|
16
|
+
const ArtifactEntrySchema = assign( PartialArtifactEntrySchema, object( {
|
|
17
|
+
name : string(),
|
|
18
|
+
type : ArtifactTypeEnum,
|
|
19
|
+
gcp_project_id : string(),
|
|
20
|
+
gcp_location : string(),
|
|
21
|
+
gcp_artifact_registry_repository_name : string(),
|
|
22
|
+
gcp_artifact_registry_package_name : string(),
|
|
23
|
+
gcp_artifact_registry_package_version : string()
|
|
24
|
+
} ) )
|
|
25
|
+
|
|
26
|
+
const PartialGenericArtifactEntrySchema = assign( PartialArtifactEntrySchema, object( {
|
|
27
|
+
type : enums( [ 'generic' ] ),
|
|
28
|
+
source_path : string(),
|
|
29
|
+
destination_path : string()
|
|
30
|
+
} ) )
|
|
31
|
+
|
|
32
|
+
const GenericArtifactEntrySchema = assign( ArtifactEntrySchema, object( {
|
|
33
|
+
source_path : string(),
|
|
34
|
+
destination_path : string()
|
|
35
|
+
} ) )
|
|
36
|
+
|
|
37
|
+
// Superstruct schema for defaults configuration
|
|
38
|
+
const DefaultsSchema = object( {
|
|
39
|
+
gcp_project_id : optional( string() ),
|
|
40
|
+
gcp_location : optional( string() ),
|
|
41
|
+
gcp_artifact_registry_repository_name : optional( string() ),
|
|
42
|
+
gcp_artifact_registry_package_name : optional( string() ),
|
|
43
|
+
gcp_artifact_registry_package_version : optional( string() )
|
|
44
|
+
} )
|
|
45
|
+
|
|
46
|
+
// Superstruct schema for the complete artifacts configuration with defaults
|
|
47
|
+
const ArtifactEntriesSchema = object( {
|
|
48
|
+
defaults : DefaultsSchema,
|
|
49
|
+
artifacts : array( union( [ PartialArtifactEntrySchema, PartialGenericArtifactEntrySchema ] ) )
|
|
50
|
+
} )
|
|
51
|
+
|
|
52
|
+
const FlattenedArtifactEntriesSchema = array( assign( union( [ ArtifactEntrySchema, GenericArtifactEntrySchema ] ) ) )
|
|
53
|
+
|
|
54
|
+
export {
|
|
55
|
+
ArtifactEntriesSchema,
|
|
56
|
+
FlattenedArtifactEntriesSchema,
|
|
57
|
+
ArtifactEntrySchema,
|
|
58
|
+
DefaultsSchema,
|
|
59
|
+
GenericArtifactEntrySchema,
|
|
60
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { validate } from 'superstruct'
|
|
2
|
+
|
|
3
|
+
import { parseYamlFile, warning } from '../Utils.mjs'
|
|
4
|
+
|
|
5
|
+
import { ArtifactEntriesSchema, GenericArtifactEntrySchema } from './Structs.mjs'
|
|
6
|
+
|
|
7
|
+
const getArtifactEntriesSchema = async ( artifactsConfigPath = './artifacts.yml' ) => {
|
|
8
|
+
const artifactsConfig = await parseYamlFile( artifactsConfigPath )
|
|
9
|
+
const [ error, result ] = validate( artifactsConfig, ArtifactEntriesSchema )
|
|
10
|
+
if ( error ) {
|
|
11
|
+
throw new Error( `Invalid artifacts.yml file: ${error.message}` )
|
|
12
|
+
}
|
|
13
|
+
return result
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const flattenArtifactEntriesSchema = ( artifactsSchema ) => {
|
|
17
|
+
return artifactsSchema.artifacts.reduce( ( flattenedArtifacts, artifact ) => {
|
|
18
|
+
const mergedArtifact = {
|
|
19
|
+
...artifactsSchema.defaults,
|
|
20
|
+
...artifact
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let schema
|
|
24
|
+
switch ( mergedArtifact.type ) {
|
|
25
|
+
case 'generic':
|
|
26
|
+
schema = GenericArtifactEntrySchema
|
|
27
|
+
break
|
|
28
|
+
default:
|
|
29
|
+
warning( `Unsupported artifact type "${mergedArtifact.type}"` )
|
|
30
|
+
break
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if ( !schema ) {
|
|
34
|
+
warning( `Invalid artifact type "${mergedArtifact.type}"` )
|
|
35
|
+
return flattenedArtifacts
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const [ error, validatedArtifact ] = validate( mergedArtifact, schema )
|
|
39
|
+
|
|
40
|
+
if ( error ) {
|
|
41
|
+
warning( `Invalid artifact "${mergedArtifact.name}": ${error.message}` )
|
|
42
|
+
return flattenedArtifacts
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return [ ...flattenedArtifacts, validatedArtifact ]
|
|
46
|
+
}, [] )
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export { getArtifactEntriesSchema, flattenArtifactEntriesSchema }
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { warning } from '../Utils.mjs'
|
|
2
|
+
|
|
3
|
+
import { getArtifactEntriesSchema, flattenArtifactEntriesSchema } from './Utils.mjs'
|
|
4
|
+
import { GenericArtifactEntryPackager } from './Packager.mjs'
|
|
5
|
+
|
|
6
|
+
async function main() {
|
|
7
|
+
|
|
8
|
+
// If an argument is provided, use it as the artifacts.yml file path
|
|
9
|
+
const artifactsYmlPath = process.argv[2]
|
|
10
|
+
const artifactPackageName = process.argv[3]
|
|
11
|
+
const artifactPackageVersion = process.argv[4]
|
|
12
|
+
|
|
13
|
+
if ( artifactsYmlPath ) {
|
|
14
|
+
const artifactsSchema = await getArtifactEntriesSchema( artifactsYmlPath )
|
|
15
|
+
const flattenedArtifactsSchema = flattenArtifactEntriesSchema( artifactsSchema )
|
|
16
|
+
|
|
17
|
+
// Open for unexpected matches if we end up re-using the same package name and version for
|
|
18
|
+
// multiple artifacts spread across multiple repositories and/or projects.
|
|
19
|
+
const filteredArtifactSchemas = flattenedArtifactsSchema.filter(
|
|
20
|
+
artifact => artifact.gcp_artifact_registry_package_name === artifactPackageName &&
|
|
21
|
+
artifact.gcp_artifact_registry_package_version === artifactPackageVersion )
|
|
22
|
+
|
|
23
|
+
if ( filteredArtifactSchemas.length === 0 ) {
|
|
24
|
+
console.error( `No artifact entries found for ${artifactPackageName} version ${artifactPackageVersion} in ${artifactsYmlPath}` )
|
|
25
|
+
process.exit( 1 )
|
|
26
|
+
}
|
|
27
|
+
for ( const artifactSchema of filteredArtifactSchemas ) {
|
|
28
|
+
let packager
|
|
29
|
+
switch ( artifactSchema.type ) {
|
|
30
|
+
case 'generic':
|
|
31
|
+
packager = new GenericArtifactEntryPackager( artifactSchema )
|
|
32
|
+
break
|
|
33
|
+
default:
|
|
34
|
+
warning( `Unsupported artifact type "${artifactSchema.type}"` )
|
|
35
|
+
continue
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if ( !packager ) {
|
|
39
|
+
warning( `Unsupported artifact type "${artifactSchema.type}"` )
|
|
40
|
+
continue
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// eslint-disable-next-line no-await-in-loop
|
|
44
|
+
await packager.package()
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
main()
|
|
@@ -1,155 +0,0 @@
|
|
|
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'
|
|
5
|
-
|
|
6
|
-
import { toExplicitPath } from './Utils.mjs'
|
|
7
|
-
|
|
8
|
-
class ArtifactPuller {
|
|
9
|
-
constructor( artifact ) {
|
|
10
|
-
this.artifact = artifact
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
async pull() {
|
|
14
|
-
throw new Error( 'Not implemented' )
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
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
|
-
}
|
|
117
|
-
|
|
118
|
-
async pull() {
|
|
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
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
export { ArtifactPuller, GenericArtifactPuller }
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/* eslint-disable security/detect-non-literal-fs-filename */
|
|
2
|
-
import { shellCmd, log, err, debug } from '../Utils.mjs'
|
|
3
|
-
|
|
4
|
-
class ArtifactPusher {
|
|
5
|
-
constructor( artifact ) {
|
|
6
|
-
this.artifact = artifact
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
async push() {
|
|
10
|
-
throw new Error( 'Not implemented' )
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
class GenericArtifactPusher extends ArtifactPusher {
|
|
15
|
-
|
|
16
|
-
async listFiles( ) {
|
|
17
|
-
const command = `gcloud artifacts files list \
|
|
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"`
|
|
24
|
-
|
|
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 )
|
|
31
|
-
|
|
32
|
-
return files
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async push() {
|
|
36
|
-
log( `Pushing artifact: ${this.artifact.name}` )
|
|
37
|
-
|
|
38
|
-
if ( this.artifact.remote_file_path ) {
|
|
39
|
-
err( 'Remote file path is not supported for pushing artifacts' )
|
|
40
|
-
return false
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
try {
|
|
44
|
-
|
|
45
|
-
let command = ''
|
|
46
|
-
|
|
47
|
-
command = `gcloud artifacts generic upload \
|
|
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
|
-
|
|
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
|
-
}
|
|
65
|
-
|
|
66
|
-
if ( this.artifact.remote_path ) {
|
|
67
|
-
command += ` --destination-path=${this.artifact.remote_path}`
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
debug( { command }, '<==Upload Command' )
|
|
71
|
-
|
|
72
|
-
await shellCmd( command )
|
|
73
|
-
|
|
74
|
-
log( `Successfully pushed artifact: ${this.artifact.name}` )
|
|
75
|
-
|
|
76
|
-
return true
|
|
77
|
-
} catch ( error ) {
|
|
78
|
-
err( `Error pushing artifact: ${this.artifact.name} ${error.message}` )
|
|
79
|
-
return false
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export { ArtifactPusher, GenericArtifactPusher }
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { assign, object, string, array, optional, enums, union, refine } from 'superstruct'
|
|
2
|
-
|
|
3
|
-
const ArtifactTypeEnum = {
|
|
4
|
-
GENERIC : 'generic',
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
// Superstruct schema for individual artifact configuration
|
|
8
|
-
const PartialArtifactSchema = object( {
|
|
9
|
-
name : string(),
|
|
10
|
-
type : optional( enums( Object.values( ArtifactTypeEnum ) ) ),
|
|
11
|
-
gcp_project_id : optional( string() ),
|
|
12
|
-
gcp_location : optional( string() ),
|
|
13
|
-
gcp_artifact_registry_repository_name : optional( string() ),
|
|
14
|
-
gcp_artifact_registry_package_name : optional( string() ),
|
|
15
|
-
gcp_artifact_registry_package_version : optional( string() )
|
|
16
|
-
} )
|
|
17
|
-
|
|
18
|
-
const ArtifactSchema = assign( PartialArtifactSchema, object( {
|
|
19
|
-
name : string(),
|
|
20
|
-
type : enums( Object.values( ArtifactTypeEnum ) ),
|
|
21
|
-
gcp_project_id : string(),
|
|
22
|
-
gcp_location : string(),
|
|
23
|
-
gcp_artifact_registry_repository_name : string(),
|
|
24
|
-
gcp_artifact_registry_package_name : string(),
|
|
25
|
-
gcp_artifact_registry_package_version : string()
|
|
26
|
-
} ) )
|
|
27
|
-
|
|
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
|
-
)
|
|
47
|
-
|
|
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
|
-
)
|
|
66
|
-
|
|
67
|
-
// Superstruct schema for defaults configuration
|
|
68
|
-
const DefaultsSchema = object( {
|
|
69
|
-
gcp_project_id : optional( string() ),
|
|
70
|
-
gcp_location : optional( string() ),
|
|
71
|
-
gcp_artifact_registry_repository_name : optional( string() ),
|
|
72
|
-
gcp_artifact_registry_package_name : optional( string() ),
|
|
73
|
-
gcp_artifact_registry_package_version : optional( string() )
|
|
74
|
-
} )
|
|
75
|
-
|
|
76
|
-
// Superstruct schema for the complete artifacts configuration with defaults
|
|
77
|
-
const ArtifactsSchema = object( {
|
|
78
|
-
defaults : optional( DefaultsSchema ),
|
|
79
|
-
artifacts : array( union( [ PartialArtifactSchema, PartialGenericArtifactSchema ] ) )
|
|
80
|
-
} )
|
|
81
|
-
|
|
82
|
-
const FlattenedArtifactsSchema = array( assign( union( [ ArtifactSchema, GenericArtifactSchema ] ) ) )
|
|
83
|
-
|
|
84
|
-
export {
|
|
85
|
-
ArtifactTypeEnum,
|
|
86
|
-
ArtifactsSchema,
|
|
87
|
-
FlattenedArtifactsSchema,
|
|
88
|
-
ArtifactSchema,
|
|
89
|
-
DefaultsSchema,
|
|
90
|
-
GenericArtifactSchema,
|
|
91
|
-
}
|
package/src/artifacts/Utils.mjs
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs'
|
|
2
|
-
import crypto from 'crypto'
|
|
3
|
-
|
|
4
|
-
import { validate } from 'superstruct'
|
|
5
|
-
|
|
6
|
-
import { parseYamlFile, warning } from '../Utils.mjs'
|
|
7
|
-
|
|
8
|
-
import { ArtifactTypeEnum, ArtifactsSchema, GenericArtifactSchema } from './Structs.mjs'
|
|
9
|
-
|
|
10
|
-
const getArtifactsSchema = async ( artifactsFilePath = './artifacts.yml' ) => {
|
|
11
|
-
const artifactsConfig = await parseYamlFile( artifactsFilePath )
|
|
12
|
-
const [ error, result ] = validate( artifactsConfig, ArtifactsSchema )
|
|
13
|
-
if ( error ) {
|
|
14
|
-
throw new Error( `Invalid artifacts.yml file: ${error.message}` )
|
|
15
|
-
}
|
|
16
|
-
return result
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const flattenArtifactsSchema = ( artifactsSchema ) => {
|
|
20
|
-
return artifactsSchema.artifacts.reduce( ( flattenedArtifacts, artifact ) => {
|
|
21
|
-
const mergedArtifact = {
|
|
22
|
-
...artifactsSchema.defaults,
|
|
23
|
-
...artifact
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
let schema
|
|
27
|
-
switch ( mergedArtifact.type ) {
|
|
28
|
-
case ArtifactTypeEnum.GENERIC:
|
|
29
|
-
schema = GenericArtifactSchema
|
|
30
|
-
break
|
|
31
|
-
default:
|
|
32
|
-
warning( `Unsupported artifact type "${mergedArtifact.type}"` )
|
|
33
|
-
break
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if ( !schema ) {
|
|
37
|
-
warning( `Invalid artifact type "${mergedArtifact.type}"` )
|
|
38
|
-
return flattenedArtifacts
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const [ error, validatedArtifact ] = validate( mergedArtifact, schema )
|
|
42
|
-
|
|
43
|
-
if ( error ) {
|
|
44
|
-
warning( `Invalid artifact "${mergedArtifact.name}": ${error.message}` )
|
|
45
|
-
return flattenedArtifacts
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return [ ...flattenedArtifacts, validatedArtifact ]
|
|
49
|
-
}, [] )
|
|
50
|
-
}
|
|
51
|
-
|
|
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,74 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { program } from 'commander'
|
|
4
|
-
|
|
5
|
-
import { warning, log } from '../Utils.mjs'
|
|
6
|
-
|
|
7
|
-
import { getArtifactsSchema, flattenArtifactsSchema } from './Utils.mjs'
|
|
8
|
-
import { ArtifactTypeEnum } from './Structs.mjs'
|
|
9
|
-
import { GenericArtifactPuller } from './ArtifactPuller.mjs'
|
|
10
|
-
|
|
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( '-n, --package-name <name>', 'Filter by artifact package name' )
|
|
16
|
-
.option( '-v, --package-version <version>', 'Filter by artifact package version' )
|
|
17
|
-
.parse()
|
|
18
|
-
|
|
19
|
-
const options = program.opts()
|
|
20
|
-
|
|
21
|
-
async function main() {
|
|
22
|
-
const artifactsYmlPath = options.filePath
|
|
23
|
-
const artifactPackageName = options.packageName || null
|
|
24
|
-
const artifactPackageVersion = options.packageVersion || null
|
|
25
|
-
|
|
26
|
-
const artifactsSchema = await getArtifactsSchema( artifactsYmlPath )
|
|
27
|
-
const flattenedArtifactsSchema = flattenArtifactsSchema( artifactsSchema )
|
|
28
|
-
|
|
29
|
-
let filteredArtifactsSchema
|
|
30
|
-
if ( artifactPackageName && artifactPackageVersion ) {
|
|
31
|
-
filteredArtifactsSchema = flattenedArtifactsSchema.filter(
|
|
32
|
-
artifact => artifact.gcp_artifact_registry_package_name === artifactPackageName &&
|
|
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 )
|
|
37
|
-
} else {
|
|
38
|
-
filteredArtifactsSchema = flattenedArtifactsSchema
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
let counter = 0
|
|
42
|
-
|
|
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 ) {
|
|
56
|
-
warning( `Unsupported artifact type "${artifactSchema.type}"` )
|
|
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` )
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
main()
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { program } from 'commander'
|
|
4
|
-
|
|
5
|
-
import { warning, log } from '../Utils.mjs'
|
|
6
|
-
|
|
7
|
-
import { getArtifactsSchema, flattenArtifactsSchema } from './Utils.mjs'
|
|
8
|
-
import { ArtifactTypeEnum } from './Structs.mjs'
|
|
9
|
-
import { GenericArtifactPusher } from './ArtifactPusher.mjs'
|
|
10
|
-
|
|
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( '-n, --package-name <name>', 'Filter by artifact package name' )
|
|
16
|
-
.option( '-v, --package-version <version>', 'Filter by artifact package version' )
|
|
17
|
-
.parse()
|
|
18
|
-
|
|
19
|
-
const options = program.opts()
|
|
20
|
-
|
|
21
|
-
async function main() {
|
|
22
|
-
const artifactsYmlPath = options.filePath
|
|
23
|
-
const artifactPackageName = options.packageName || null
|
|
24
|
-
const artifactPackageVersion = options.packageVersion || null
|
|
25
|
-
|
|
26
|
-
const artifactsSchema = await getArtifactsSchema( artifactsYmlPath )
|
|
27
|
-
const flattenedArtifactsSchema = flattenArtifactsSchema( artifactsSchema )
|
|
28
|
-
|
|
29
|
-
let filteredArtifactsSchema
|
|
30
|
-
if ( artifactPackageName && artifactPackageVersion ) {
|
|
31
|
-
filteredArtifactsSchema = flattenedArtifactsSchema.filter(
|
|
32
|
-
artifact => artifact.gcp_artifact_registry_package_name === artifactPackageName &&
|
|
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 )
|
|
37
|
-
} else {
|
|
38
|
-
filteredArtifactsSchema = flattenedArtifactsSchema
|
|
39
|
-
}
|
|
40
|
-
|
|
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 ) {
|
|
56
|
-
warning( `Unsupported artifact type "${artifactSchema.type}"` )
|
|
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` )
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
main()
|