@leverege/build-tools 2.113.6 → 2.114.0-DEVOP-578.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 +0 -15
- package/package.json +15 -10
- package/src/bash-funcs +1 -1
- package/src/build-tools.mjs +3 -2
- package/src/chart-compass.yaml +6 -1
- package/src/helm-charts/api-server/values-local.yaml +1 -1
- package/src/helm-charts/cnpg-db-psql-stack/cluster.yaml.ovh +1 -1
- package/src/helm-charts/cnpg-db-tsdb-basic/cluster.yaml.ovh +1 -1
- package/src/helm-charts/cnpg-db-tsdb-dense/cluster.yaml.ovh +1 -1
- package/src/helm-charts/llm-prompt-server/values-local.yaml +5 -0
- package/src/helm-charts/prom-operator/helmup.plugin +3 -3
- package/src/helm-charts/prom-operator/prometheus-stack.yaml.ovh +1 -1
- package/src/helm-charts/triton-inference-server/values-local.yaml +28 -0
- package/src/helm-charts/vms-server/values-local.yaml +45 -0
- package/src/helmup.sh +5 -4
- package/src/k8s/commands/completion.mjs +100 -0
- package/src/k8s/commands/cryo.mjs +164 -0
- package/src/k8s/commands/exe.mjs +57 -0
- package/src/k8s/commands/fwd.mjs +35 -0
- package/src/k8s/commands/log.mjs +76 -0
- package/src/k8s/commands/roll.mjs +37 -0
- package/src/k8s/commands/scale.mjs +43 -0
- package/src/k8s/k8s.mjs +26 -0
- package/src/k8s/lib/gate.mjs +9 -0
- package/src/k8s/lib/kubectl.mjs +26 -0
- package/src/k8s/lib/select.mjs +18 -0
- package/src/overwhelm.mjs +1 -1
- package/src/repo-panopticon.mjs +16 -12
- package/src/service-man/config/Config.mjs +1 -1
- package/src/service-man/config/iam-roles/leveregeVertexEndpointUser.json +10 -0
- package/src/service-man/config/service-accounts/llm-prompt-server.json +6 -0
- package/src/service-man/config/service-accounts/triton-inference-server.json +5 -0
- package/src/service-man/config/service-accounts/vms-server.json +8 -0
- package/src/service-man/gcloud-k8s/ServiceAccountManager.mjs +9 -5
- package/src/artifacts/ArtifactPuller.mjs +0 -131
- package/src/artifacts/ArtifactPusher.mjs +0 -110
- package/src/artifacts/Structs.mjs +0 -98
- package/src/artifacts/Utils.mjs +0 -284
- package/src/artifacts/pull-artifact.mjs +0 -81
- package/src/artifacts/push-artifact.mjs +0 -80
- package/src/change-up.sh +0 -27
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import path from 'node:path'
|
|
2
|
-
import fs from 'node:fs'
|
|
3
|
-
|
|
4
|
-
import { shellCmd, log, err, debug } from '../Utils.mjs'
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
parseGenericArtifactFileToRemoteRelativePath,
|
|
8
|
-
parseGenericArtifactSchemaToRemoteRelativePath,
|
|
9
|
-
listGenericArtifactFiles,
|
|
10
|
-
shouldUseIgnoreConfiguration,
|
|
11
|
-
findIgnoreFilePath,
|
|
12
|
-
copyFilesWithIgnoreConfiguration
|
|
13
|
-
} from './Utils.mjs'
|
|
14
|
-
|
|
15
|
-
class ArtifactPusher {
|
|
16
|
-
constructor( path, artifact ) {
|
|
17
|
-
this.path = path
|
|
18
|
-
this.artifact = artifact
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
async push() {
|
|
22
|
-
throw new Error( 'Not implemented' )
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
class GenericArtifactPusher extends ArtifactPusher {
|
|
27
|
-
|
|
28
|
-
async push() {
|
|
29
|
-
log( `Pushing artifact: ${this.artifact.name}` )
|
|
30
|
-
|
|
31
|
-
if ( this.artifact.remote_file_path ) {
|
|
32
|
-
err( 'Remote file path is not supported for pushing artifacts' )
|
|
33
|
-
return false
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if ( !this.artifact.local_path && !this.artifact.local_file_path ) {
|
|
37
|
-
err( 'Local path or local file path is required for pushing artifacts' )
|
|
38
|
-
return false
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
let command = ''
|
|
43
|
-
|
|
44
|
-
command = `gcloud artifacts generic upload \
|
|
45
|
-
--project=${this.artifact.project} \
|
|
46
|
-
--location=${this.artifact.location} \
|
|
47
|
-
--repository=${this.artifact.repository} \
|
|
48
|
-
--package=${this.artifact.package} \
|
|
49
|
-
--version=${this.artifact.version}`
|
|
50
|
-
|
|
51
|
-
let pathToDelete
|
|
52
|
-
|
|
53
|
-
if ( this.artifact.local_path ) {
|
|
54
|
-
const originalLocalPath = path.join( this.path, this.artifact.local_path )
|
|
55
|
-
|
|
56
|
-
let localPath = originalLocalPath
|
|
57
|
-
|
|
58
|
-
const useIgnoreConfiguration = await shouldUseIgnoreConfiguration()
|
|
59
|
-
|
|
60
|
-
if ( useIgnoreConfiguration ) {
|
|
61
|
-
const ignoreFilePath = await findIgnoreFilePath( this.path )
|
|
62
|
-
if ( ignoreFilePath ) {
|
|
63
|
-
const tmpLocalPath = path.join( '/', 'tmp', `${this.artifact.project}_${this.artifact.location}_${this.artifact.repository}_${this.artifact.package}_${this.artifact.version}` )
|
|
64
|
-
localPath = tmpLocalPath
|
|
65
|
-
pathToDelete = tmpLocalPath
|
|
66
|
-
await copyFilesWithIgnoreConfiguration( originalLocalPath, tmpLocalPath, ignoreFilePath )
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
command += ` --source-directory=${localPath}`
|
|
71
|
-
command += ' --skip-existing'
|
|
72
|
-
} else if ( this.artifact.local_file_path ) {
|
|
73
|
-
|
|
74
|
-
const files = await listGenericArtifactFiles( this.artifact )
|
|
75
|
-
|
|
76
|
-
const newRemoteFilePath = parseGenericArtifactSchemaToRemoteRelativePath( this.artifact )
|
|
77
|
-
|
|
78
|
-
for ( const file of files ) {
|
|
79
|
-
const existingRemoteFilePath = parseGenericArtifactFileToRemoteRelativePath( file )
|
|
80
|
-
if ( existingRemoteFilePath === newRemoteFilePath ) {
|
|
81
|
-
err( `File already exists in the artifact registry: ${existingRemoteFilePath}` )
|
|
82
|
-
return false
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
const localPath = path.join( this.path, this.artifact.local_file_path )
|
|
86
|
-
command += ` --source=${localPath}`
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
command += ` --destination-path=${this.artifact.remote_path || '""'}`
|
|
90
|
-
|
|
91
|
-
debug( { command }, '<==Upload Command' )
|
|
92
|
-
|
|
93
|
-
await shellCmd( command )
|
|
94
|
-
|
|
95
|
-
if ( pathToDelete ) {
|
|
96
|
-
await fs.promises.rm( pathToDelete, { recursive : true } )
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
log( `Successfully pushed artifact: ${this.artifact.name}` )
|
|
100
|
-
|
|
101
|
-
return true
|
|
102
|
-
} catch ( error ) {
|
|
103
|
-
debug( { error }, '<==Error Pushing Artifact' )
|
|
104
|
-
err( `Error pushing artifact: ${this.artifact.name} ${error.message}` )
|
|
105
|
-
return false
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export { ArtifactPusher, GenericArtifactPusher }
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import path from 'node:path'
|
|
2
|
-
|
|
3
|
-
import { assign, coerce, object, string, array, optional, enums, union, refine } from 'superstruct'
|
|
4
|
-
|
|
5
|
-
const ArtifactTypeEnum = {
|
|
6
|
-
GENERIC : 'generic',
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
// Structs with the Partial prefix come from the need to validate the schema with defaults and without defaults merged together.
|
|
10
|
-
|
|
11
|
-
const PartialArtifactSchema = object( {
|
|
12
|
-
name : string(),
|
|
13
|
-
type : optional( enums( Object.values( ArtifactTypeEnum ) ) ),
|
|
14
|
-
project : optional( string() ),
|
|
15
|
-
location : optional( string() ),
|
|
16
|
-
repository : optional( string() ),
|
|
17
|
-
package : optional( string() ),
|
|
18
|
-
version : optional( string() )
|
|
19
|
-
} )
|
|
20
|
-
|
|
21
|
-
const ArtifactSchema = assign( PartialArtifactSchema, object( {
|
|
22
|
-
name : string(),
|
|
23
|
-
type : enums( Object.values( ArtifactTypeEnum ) ),
|
|
24
|
-
project : string(),
|
|
25
|
-
location : string(),
|
|
26
|
-
repository : string(),
|
|
27
|
-
package : string(),
|
|
28
|
-
version : string()
|
|
29
|
-
} ) )
|
|
30
|
-
|
|
31
|
-
const normalizedPath = () => coerce( string(), string(), value => path.normalize( value ) )
|
|
32
|
-
|
|
33
|
-
const PartialGenericArtifactSchema = refine(
|
|
34
|
-
assign( PartialArtifactSchema, object( {
|
|
35
|
-
type : optional( enums( [ ArtifactTypeEnum.GENERIC ] ) ),
|
|
36
|
-
local_file_path : optional( normalizedPath() ),
|
|
37
|
-
local_path : optional( normalizedPath() ),
|
|
38
|
-
remote_file_path : optional( normalizedPath() ),
|
|
39
|
-
remote_path : optional( normalizedPath() )
|
|
40
|
-
} ) ),
|
|
41
|
-
'ConflictingPaths',
|
|
42
|
-
( value ) => {
|
|
43
|
-
if ( value.local_file_path && value.local_path ) {
|
|
44
|
-
return 'Only one of local_file_path or local_path must be provided'
|
|
45
|
-
}
|
|
46
|
-
if ( value.remote_file_path && value.remote_path ) {
|
|
47
|
-
return 'Only one of remote_file_path or remote_path must be provided'
|
|
48
|
-
}
|
|
49
|
-
return true
|
|
50
|
-
}
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
const GenericArtifactSchema = refine(
|
|
54
|
-
assign( ArtifactSchema, object( {
|
|
55
|
-
type : enums( [ ArtifactTypeEnum.GENERIC ] ),
|
|
56
|
-
local_file_path : optional( normalizedPath() ),
|
|
57
|
-
local_path : optional( normalizedPath() ),
|
|
58
|
-
remote_file_path : optional( string() ),
|
|
59
|
-
remote_path : optional( normalizedPath() )
|
|
60
|
-
} ) ),
|
|
61
|
-
'ConflictingPaths',
|
|
62
|
-
( value ) => {
|
|
63
|
-
if ( value.local_file_path && value.local_path ) {
|
|
64
|
-
return 'Only one of local_file_path or local_path must be provided'
|
|
65
|
-
}
|
|
66
|
-
if ( value.remote_file_path && value.remote_path ) {
|
|
67
|
-
return 'Only one of remote_file_path or remote_path must be provided'
|
|
68
|
-
}
|
|
69
|
-
return true
|
|
70
|
-
}
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
// Superstruct schema for defaults configuration
|
|
74
|
-
const DefaultsSchema = object( {
|
|
75
|
-
type : optional( enums( Object.values( ArtifactTypeEnum ) ) ),
|
|
76
|
-
project : optional( string() ),
|
|
77
|
-
location : optional( string() ),
|
|
78
|
-
repository : optional( string() ),
|
|
79
|
-
package : optional( string() ),
|
|
80
|
-
version : optional( string() )
|
|
81
|
-
} )
|
|
82
|
-
|
|
83
|
-
// Superstruct schema for the complete artifacts configuration with defaults
|
|
84
|
-
const ArtifactsSchema = object( {
|
|
85
|
-
defaults : optional( DefaultsSchema ),
|
|
86
|
-
artifacts : array( union( [ PartialArtifactSchema, PartialGenericArtifactSchema ] ) )
|
|
87
|
-
} )
|
|
88
|
-
|
|
89
|
-
const FlattenedArtifactsSchema = array( assign( union( [ ArtifactSchema, GenericArtifactSchema ] ) ) )
|
|
90
|
-
|
|
91
|
-
export {
|
|
92
|
-
ArtifactTypeEnum,
|
|
93
|
-
ArtifactsSchema,
|
|
94
|
-
FlattenedArtifactsSchema,
|
|
95
|
-
ArtifactSchema,
|
|
96
|
-
DefaultsSchema,
|
|
97
|
-
GenericArtifactSchema,
|
|
98
|
-
}
|
package/src/artifacts/Utils.mjs
DELETED
|
@@ -1,284 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs'
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
import crypto from 'node:crypto'
|
|
4
|
-
|
|
5
|
-
import { validate } from 'superstruct'
|
|
6
|
-
|
|
7
|
-
import { parseYamlFile, err, warning, debug, shellCmd } from '../Utils.mjs'
|
|
8
|
-
|
|
9
|
-
import { ArtifactTypeEnum, ArtifactsSchema, GenericArtifactSchema } from './Structs.mjs'
|
|
10
|
-
|
|
11
|
-
const getArtifactsSchema = async ( artifactsFilePath = './artifacts.yaml' ) => {
|
|
12
|
-
const artifactsConfig = await parseYamlFile( artifactsFilePath )
|
|
13
|
-
const [ error, result ] = validate( artifactsConfig, ArtifactsSchema )
|
|
14
|
-
if ( error ) {
|
|
15
|
-
err( `Invalid artifacts.yml file: ${error.message}` )
|
|
16
|
-
debug( { err : error }, '<==Invalid artifacts.yml file' )
|
|
17
|
-
throw new Error( `Invalid artifacts.yml file: ${error.message}` )
|
|
18
|
-
}
|
|
19
|
-
return result
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const flattenArtifactsSchema = ( artifactsSchema ) => {
|
|
23
|
-
return artifactsSchema.artifacts.reduce( ( flattenedArtifacts, artifact ) => {
|
|
24
|
-
const mergedArtifact = {
|
|
25
|
-
...artifactsSchema.defaults,
|
|
26
|
-
...artifact
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
let schema
|
|
30
|
-
switch ( mergedArtifact.type ) {
|
|
31
|
-
case ArtifactTypeEnum.GENERIC:
|
|
32
|
-
schema = GenericArtifactSchema
|
|
33
|
-
break
|
|
34
|
-
default:
|
|
35
|
-
warning( `Unsupported artifact type "${mergedArtifact.type}"` )
|
|
36
|
-
break
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if ( !schema ) {
|
|
40
|
-
warning( `Invalid artifact type "${mergedArtifact.type}"` )
|
|
41
|
-
return flattenedArtifacts
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const [ error, validatedArtifact ] = validate( mergedArtifact, schema )
|
|
45
|
-
|
|
46
|
-
if ( error ) {
|
|
47
|
-
warning( `Invalid artifact "${mergedArtifact.name}": ${error.message}` )
|
|
48
|
-
return flattenedArtifacts
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return [ ...flattenedArtifacts, validatedArtifact ]
|
|
52
|
-
}, [] )
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Example of a file in a generic artifact registry repository:
|
|
56
|
-
// [
|
|
57
|
-
// {
|
|
58
|
-
// "createTime": "2025-12-02T17:52:08.694541Z",
|
|
59
|
-
// "hashes": [
|
|
60
|
-
// {
|
|
61
|
-
// "type": "SHA256",
|
|
62
|
-
// "value": "wrBRqJOUjm-zy6B7YzgKlK0fv9Ad0EEjydBnsmc9Ruw="
|
|
63
|
-
// },
|
|
64
|
-
// {
|
|
65
|
-
// "type": "MD5",
|
|
66
|
-
// "value": "Ebp3fVphzrITJ461Mg7Kmg=="
|
|
67
|
-
// }
|
|
68
|
-
// ],
|
|
69
|
-
// "name": "projects/leverege-registry/locations/us-central1/repositories/test-generic-registry/files/sweet-poems-1-1764697925426:v1:test1.txt%2Ftest1.txt",
|
|
70
|
-
// "owner": "projects/leverege-registry/locations/us-central1/repositories/test-generic-registry/packages/sweet-poems-1-1764697925426/versions/v1",
|
|
71
|
-
// "sizeBytes": "40",
|
|
72
|
-
// "updateTime": "2025-12-02T17:52:08.694541Z"
|
|
73
|
-
// }
|
|
74
|
-
// ]
|
|
75
|
-
// Obtained with:gcloud artifacts files list --project=leverege-registry --location=us-central1 --repository=test-generic-registry --package=sweet-poems-1-1764697925426 --version v1 --format="json"
|
|
76
|
-
|
|
77
|
-
const parseGenericArtifactFileToRemoteRelativePath = ( genericArtifactFile ) => {
|
|
78
|
-
// "projects/leverege-registry/locations/us-central1/repositories/test-generic-registry/files/sweet-poems-1-1764697925426:v1:test1.txt%2Ftest1.txt"
|
|
79
|
-
const artifactFileName = genericArtifactFile.name.split( '/' ).pop()
|
|
80
|
-
// sweet-poems-1-1764697925426:v1:test1.txt%2Ftest1.txt
|
|
81
|
-
const remoteRelativePath = artifactFileName.split( ':' ).pop().replaceAll( '%2F', '/' )
|
|
82
|
-
// test1.txt
|
|
83
|
-
return path.normalize( remoteRelativePath )
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const parseGenericArtifactSchemaToRemoteRelativePath = ( genericArtifactSchema ) => {
|
|
87
|
-
if ( genericArtifactSchema.remote_file_path ) {
|
|
88
|
-
return path.normalize( genericArtifactSchema.remote_file_path )
|
|
89
|
-
}
|
|
90
|
-
if ( genericArtifactSchema.remote_path && genericArtifactSchema.local_file_path ) {
|
|
91
|
-
return path.join( genericArtifactSchema.remote_path, path.basename( genericArtifactSchema.local_file_path ) )
|
|
92
|
-
}
|
|
93
|
-
if ( !genericArtifactSchema.remote_file_path && !genericArtifactSchema.remote_path && genericArtifactSchema.local_file_path ) {
|
|
94
|
-
return path.basename( genericArtifactSchema.local_file_path )
|
|
95
|
-
}
|
|
96
|
-
if ( !genericArtifactSchema.remote_file_path && !genericArtifactSchema.remote_path && genericArtifactSchema.local_file_path ) {
|
|
97
|
-
return path.basename( genericArtifactSchema.local_file_path )
|
|
98
|
-
}
|
|
99
|
-
if ( genericArtifactSchema.remote_path && genericArtifactSchema.local_path ) {
|
|
100
|
-
return path.normalize( genericArtifactSchema.remote_path )
|
|
101
|
-
}
|
|
102
|
-
return path.normalize( '.' )
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const parseGenericArtifactSchemaToLocalRelativePath = ( genericArtifactSchema ) => {
|
|
106
|
-
if ( genericArtifactSchema.local_file_path ) {
|
|
107
|
-
return path.normalize( genericArtifactSchema.local_file_path )
|
|
108
|
-
}
|
|
109
|
-
if ( genericArtifactSchema.local_path && genericArtifactSchema.remote_file_path ) {
|
|
110
|
-
return path.join( genericArtifactSchema.local_path, path.basename( genericArtifactSchema.remote_file_path ) )
|
|
111
|
-
}
|
|
112
|
-
if ( genericArtifactSchema.local_path && !genericArtifactSchema.remote_file_path && !genericArtifactSchema.remote_file_path ) {
|
|
113
|
-
return path.normalize( genericArtifactSchema.local_path )
|
|
114
|
-
}
|
|
115
|
-
if ( !genericArtifactSchema.local_file_path && !genericArtifactSchema.local_path && genericArtifactSchema.remote_file_path ) {
|
|
116
|
-
return path.basename( genericArtifactSchema.remote_file_path )
|
|
117
|
-
}
|
|
118
|
-
return path.normalize( '.' )
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const parseGenericArtifactSchemaToArtifactNameBase = ( genericArtifactSchema ) => {
|
|
122
|
-
const elements = [
|
|
123
|
-
'projecs',
|
|
124
|
-
genericArtifactSchema.project,
|
|
125
|
-
'locations',
|
|
126
|
-
genericArtifactSchema.location,
|
|
127
|
-
'repositories',
|
|
128
|
-
genericArtifactSchema.repository,
|
|
129
|
-
'files',
|
|
130
|
-
]
|
|
131
|
-
return elements.join( '/' )
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const parseGenericArtifactSchemaToArtifactNameFile = ( genericArtifactSchema ) => {
|
|
135
|
-
// // "name": "projects/leverege-registry/locations/us-central1/repositories/test-generic-registry/files/sweet-poems-1-1764697925426:v1:test1.txt%2Ftest1.txt",
|
|
136
|
-
|
|
137
|
-
const remoteRelativePath = parseGenericArtifactSchemaToRemoteRelativePath( genericArtifactSchema )
|
|
138
|
-
const encodedRemoteRelativePath = encodeURIComponent( remoteRelativePath )
|
|
139
|
-
|
|
140
|
-
const elements = [
|
|
141
|
-
genericArtifactSchema.package,
|
|
142
|
-
genericArtifactSchema.version,
|
|
143
|
-
encodedRemoteRelativePath,
|
|
144
|
-
]
|
|
145
|
-
return elements.join( ':' )
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const parseGenericArtifactSchemaToArtifactName = ( genericArtifactSchema ) => {
|
|
149
|
-
const base = parseGenericArtifactSchemaToArtifactNameBase( genericArtifactSchema )
|
|
150
|
-
const file = parseGenericArtifactSchemaToArtifactNameFile( genericArtifactSchema )
|
|
151
|
-
|
|
152
|
-
const elements = [
|
|
153
|
-
base,
|
|
154
|
-
file,
|
|
155
|
-
]
|
|
156
|
-
|
|
157
|
-
return elements.join( ':' )
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const calculateHash = async ( path ) => {
|
|
161
|
-
try {
|
|
162
|
-
const hash = crypto.createHash( 'sha256' )
|
|
163
|
-
hash.update( await fs.promises.readFile( path ) ) // eslint-disable-line security/detect-non-literal-fs-filename
|
|
164
|
-
return `${hash.digest( 'base64url' )}=`
|
|
165
|
-
} catch ( error ) {
|
|
166
|
-
throw new Error( `Failed to calculate hash for artifact ${path}: ${error.message}` )
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const listGenericArtifactFiles = async ( artifact ) => {
|
|
171
|
-
const command = `gcloud artifacts files list \
|
|
172
|
-
--project=${artifact.project} \
|
|
173
|
-
--location=${artifact.location} \
|
|
174
|
-
--repository=${artifact.repository} \
|
|
175
|
-
--package=${artifact.package} \
|
|
176
|
-
--version ${artifact.version} \
|
|
177
|
-
--format="json"`
|
|
178
|
-
|
|
179
|
-
debug( { command }, '<==List Files Command' )
|
|
180
|
-
|
|
181
|
-
const result = await shellCmd( command )
|
|
182
|
-
|
|
183
|
-
// Parse the JSON response
|
|
184
|
-
const files = JSON.parse( result )
|
|
185
|
-
return files
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const getMissingRemoteFiles = async ( genericArtifactFiles, genericArtifactSchemaPath, genericArtifactSchema ) => {
|
|
189
|
-
|
|
190
|
-
const expectedRemoteRelativePath = parseGenericArtifactSchemaToRemoteRelativePath( genericArtifactSchema )
|
|
191
|
-
const localRelativePath = parseGenericArtifactSchemaToLocalRelativePath( genericArtifactSchema )
|
|
192
|
-
const expectedLocalRelativePath = path.join( genericArtifactSchemaPath, localRelativePath )
|
|
193
|
-
|
|
194
|
-
const actualFiles = new Set()
|
|
195
|
-
const expectedFiles = new Set()
|
|
196
|
-
|
|
197
|
-
for ( const file of genericArtifactFiles ) {
|
|
198
|
-
const actualRemoteFilePath = parseGenericArtifactFileToRemoteRelativePath( file )
|
|
199
|
-
const actualRemoteFileHash = file.hashes.find( hash => hash.type === 'SHA256' ).value
|
|
200
|
-
actualFiles.add( { remoteFilePath : actualRemoteFilePath, remoteFileHash : actualRemoteFileHash } )
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/* eslint-disable security/detect-non-literal-fs-filename */
|
|
204
|
-
if ( ( await fs.promises.stat( expectedLocalRelativePath ) ).isDirectory() ) {
|
|
205
|
-
const localFiles = await fs.promises.readdir( expectedLocalRelativePath, { withFileTypes : true, recursive : true } )
|
|
206
|
-
for ( const localFile of localFiles ) {
|
|
207
|
-
if ( localFile.isDirectory() ) {
|
|
208
|
-
continue
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const expectedRemoteFilePath = path.join( expectedRemoteRelativePath, localFile.path.replace( expectedLocalRelativePath, '' ), localFile.name )
|
|
212
|
-
const expectedLocalFilePath = path.join( localFile.path, localFile.name )
|
|
213
|
-
// eslint-disable-next-line no-await-in-loop
|
|
214
|
-
expectedFiles.add( { remoteFilePath : expectedRemoteFilePath, remoteFileHash : await calculateHash( expectedLocalFilePath ) } )
|
|
215
|
-
}
|
|
216
|
-
} else {
|
|
217
|
-
const expectedRemoteFilePath = expectedRemoteRelativePath
|
|
218
|
-
const expectedLocalFilePath = expectedLocalRelativePath
|
|
219
|
-
expectedFiles.add( { remoteFilePath : expectedRemoteFilePath, remoteFileHash : await calculateHash( expectedLocalFilePath ) } )
|
|
220
|
-
}
|
|
221
|
-
/* eslint-enable security/detect-non-literal-fs-filename */
|
|
222
|
-
|
|
223
|
-
const actualArray = Array.from( actualFiles )
|
|
224
|
-
const expectedArray = Array.from( expectedFiles )
|
|
225
|
-
|
|
226
|
-
return expectedArray.filter( expected => !actualArray.some( actual => actual.remoteFilePath === expected.remoteFilePath && actual.remoteFileHash === expected.remoteFileHash ) )
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const shouldUseIgnoreConfiguration = async () => {
|
|
230
|
-
let result
|
|
231
|
-
try {
|
|
232
|
-
result = await shellCmd( 'gcloud config get-value gcloudignore/enabled' )
|
|
233
|
-
if ( result.trim() === '' || result.includes( 'has no property' ) ) {
|
|
234
|
-
return false
|
|
235
|
-
}
|
|
236
|
-
return result.trim() === 'true'
|
|
237
|
-
} catch ( error ) {
|
|
238
|
-
if ( error.message && error.message.includes( 'Section [gcloudignore] has no property [enabled]' ) ) {
|
|
239
|
-
return false
|
|
240
|
-
}
|
|
241
|
-
// Re-throw other errors
|
|
242
|
-
throw error
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const findIgnoreFilePath = async ( relativePath ) => {
|
|
247
|
-
if ( relativePath ) {
|
|
248
|
-
const ignoreFilePath = path.join( relativePath, '.gcloudignore' )
|
|
249
|
-
if ( fs.existsSync( ignoreFilePath ) ) { // eslint-disable-line security/detect-non-literal-fs-filename
|
|
250
|
-
return ignoreFilePath
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
const ignoreFilePath = path.join( process.cwd(), '.gcloudignore' )
|
|
255
|
-
if ( fs.existsSync( ignoreFilePath ) ) {
|
|
256
|
-
return ignoreFilePath
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
return null
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
const copyFilesWithIgnoreConfiguration = async ( sourcePath, destinationPath, ignoreFilePath ) => {
|
|
263
|
-
// Ensure sourcePath ends with / so rsync copies contents (not the folder itself) and exclude patterns work correctly
|
|
264
|
-
const normalizedSourcePath = sourcePath.endsWith( '/' ) ? sourcePath : `${sourcePath}/`
|
|
265
|
-
const command = `rsync -av --delete --exclude-from='${ignoreFilePath}' ${normalizedSourcePath} ${destinationPath}`
|
|
266
|
-
await shellCmd( command )
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
export {
|
|
270
|
-
calculateHash,
|
|
271
|
-
getArtifactsSchema,
|
|
272
|
-
flattenArtifactsSchema,
|
|
273
|
-
parseGenericArtifactFileToRemoteRelativePath,
|
|
274
|
-
parseGenericArtifactSchemaToRemoteRelativePath,
|
|
275
|
-
parseGenericArtifactSchemaToLocalRelativePath,
|
|
276
|
-
parseGenericArtifactSchemaToArtifactNameBase,
|
|
277
|
-
parseGenericArtifactSchemaToArtifactNameFile,
|
|
278
|
-
parseGenericArtifactSchemaToArtifactName,
|
|
279
|
-
getMissingRemoteFiles,
|
|
280
|
-
listGenericArtifactFiles,
|
|
281
|
-
shouldUseIgnoreConfiguration,
|
|
282
|
-
findIgnoreFilePath,
|
|
283
|
-
copyFilesWithIgnoreConfiguration
|
|
284
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import path from 'node:path'
|
|
4
|
-
|
|
5
|
-
import { program } from 'commander'
|
|
6
|
-
|
|
7
|
-
import { warning, log } from '../Utils.mjs'
|
|
8
|
-
|
|
9
|
-
import { getArtifactsSchema, flattenArtifactsSchema } from './Utils.mjs'
|
|
10
|
-
import { ArtifactTypeEnum } from './Structs.mjs'
|
|
11
|
-
import { GenericArtifactPuller } from './ArtifactPuller.mjs'
|
|
12
|
-
|
|
13
|
-
program
|
|
14
|
-
.name( 'pull-artifact' )
|
|
15
|
-
.description( 'Pull artifacts from GCP Artifact Registry' )
|
|
16
|
-
.option( '-f, --file-path <file-path>', 'Path to artifacts.yaml file', './artifacts.yaml' )
|
|
17
|
-
.option( '-a, --artifact-path <artifact-path>', 'GCP artifact path' )
|
|
18
|
-
.parse()
|
|
19
|
-
|
|
20
|
-
const options = program.opts()
|
|
21
|
-
|
|
22
|
-
async function main() {
|
|
23
|
-
const artifactsSchema = await getArtifactsSchema( options.filePath )
|
|
24
|
-
const flattenedArtifactsSchema = flattenArtifactsSchema( artifactsSchema )
|
|
25
|
-
|
|
26
|
-
let filteredArtifactsSchema = flattenedArtifactsSchema
|
|
27
|
-
|
|
28
|
-
if ( options.artifactPath ) {
|
|
29
|
-
const artifactPathElements = options.artifactPath.split( '/' )
|
|
30
|
-
|
|
31
|
-
if ( artifactPathElements.length !== 5 ) {
|
|
32
|
-
warning( 'Invalid artifact path, it must be in the format <project>/<location>/<repository>/<package>/<version>' )
|
|
33
|
-
return false
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const [ project, location, repository, packageName, version ] = artifactPathElements
|
|
37
|
-
|
|
38
|
-
filteredArtifactsSchema = flattenedArtifactsSchema.filter(
|
|
39
|
-
artifact => artifact.project === project &&
|
|
40
|
-
artifact.location === location &&
|
|
41
|
-
artifact.repository === repository &&
|
|
42
|
-
artifact.package === packageName &&
|
|
43
|
-
artifact.version === version )
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
let counter = 0
|
|
47
|
-
|
|
48
|
-
const pullResults = await Promise.all(
|
|
49
|
-
filteredArtifactsSchema.map( async ( artifactSchema ) => {
|
|
50
|
-
let puller
|
|
51
|
-
switch ( artifactSchema.type ) {
|
|
52
|
-
case ArtifactTypeEnum.GENERIC:
|
|
53
|
-
puller = new GenericArtifactPuller( path.dirname( options.filePath ), artifactSchema )
|
|
54
|
-
break
|
|
55
|
-
default:
|
|
56
|
-
warning( `Unsupported artifact type "${artifactSchema.type}"` )
|
|
57
|
-
return false
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if ( !puller ) {
|
|
61
|
-
warning( `Unsupported artifact type "${artifactSchema.type}"` )
|
|
62
|
-
return false
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
try {
|
|
66
|
-
return await puller.pull()
|
|
67
|
-
} catch ( error ) {
|
|
68
|
-
warning( `Error pulling artifact "${artifactSchema.name}": ${error.message}` )
|
|
69
|
-
return false
|
|
70
|
-
}
|
|
71
|
-
} )
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
counter = pullResults.filter( Boolean ).length
|
|
75
|
-
|
|
76
|
-
log( `Successfully pulled ${counter}/${filteredArtifactsSchema.length} artifacts` )
|
|
77
|
-
|
|
78
|
-
return counter === filteredArtifactsSchema.length
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
main()
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import path from 'node:path'
|
|
4
|
-
|
|
5
|
-
import { program } from 'commander'
|
|
6
|
-
|
|
7
|
-
import { warning, log } from '../Utils.mjs'
|
|
8
|
-
|
|
9
|
-
import { getArtifactsSchema, flattenArtifactsSchema } from './Utils.mjs'
|
|
10
|
-
import { ArtifactTypeEnum } from './Structs.mjs'
|
|
11
|
-
import { GenericArtifactPusher } from './ArtifactPusher.mjs'
|
|
12
|
-
|
|
13
|
-
program
|
|
14
|
-
.name( 'push-artifact' )
|
|
15
|
-
.description( 'Push artifacts to GCP Artifact Registry' )
|
|
16
|
-
.option( '-f, --file-path <file-path>', 'Path to artifacts.yaml file', './artifacts.yaml' )
|
|
17
|
-
.option( '-a, --artifact-path <artifact-path>', 'GCP artifact path' )
|
|
18
|
-
.parse()
|
|
19
|
-
|
|
20
|
-
const options = program.opts()
|
|
21
|
-
|
|
22
|
-
async function main() {
|
|
23
|
-
const artifactsSchema = await getArtifactsSchema( options.filePath )
|
|
24
|
-
const flattenedArtifactsSchema = flattenArtifactsSchema( artifactsSchema )
|
|
25
|
-
|
|
26
|
-
let filteredArtifactsSchema = flattenedArtifactsSchema
|
|
27
|
-
|
|
28
|
-
if ( options.artifactPath ) {
|
|
29
|
-
const artifactPathElements = options.artifactPath.split( '/' )
|
|
30
|
-
if ( artifactPathElements.length !== 5 ) {
|
|
31
|
-
warning( 'Invalid artifact path, it must be in the format <project>/<location>/<repository>/<package>/<version>' )
|
|
32
|
-
return false
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const [ project, location, repository, packageName, version ] = artifactPathElements
|
|
36
|
-
|
|
37
|
-
filteredArtifactsSchema = flattenedArtifactsSchema.filter(
|
|
38
|
-
artifact => artifact.project === project &&
|
|
39
|
-
artifact.location === location &&
|
|
40
|
-
artifact.repository === repository &&
|
|
41
|
-
artifact.package === packageName &&
|
|
42
|
-
artifact.version === version )
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
let counter = 0
|
|
46
|
-
|
|
47
|
-
const pushResults = await Promise.all(
|
|
48
|
-
filteredArtifactsSchema.map( async ( artifactSchema ) => {
|
|
49
|
-
let pusher
|
|
50
|
-
switch ( artifactSchema.type ) {
|
|
51
|
-
case ArtifactTypeEnum.GENERIC:
|
|
52
|
-
pusher = new GenericArtifactPusher( path.dirname( options.filePath ), artifactSchema )
|
|
53
|
-
break
|
|
54
|
-
default:
|
|
55
|
-
warning( `Unsupported artifact type "${artifactSchema.type}"` )
|
|
56
|
-
return false
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if ( !pusher ) {
|
|
60
|
-
warning( `Unsupported artifact type "${artifactSchema.type}"` )
|
|
61
|
-
return false
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
try {
|
|
65
|
-
return await pusher.push()
|
|
66
|
-
} catch ( error ) {
|
|
67
|
-
warning( `Error pushing artifact "${artifactSchema.name}": ${error.message}` )
|
|
68
|
-
return false
|
|
69
|
-
}
|
|
70
|
-
} )
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
counter = pushResults.filter( Boolean ).length
|
|
74
|
-
|
|
75
|
-
log( `Successfully pushed ${counter}/${filteredArtifactsSchema.length} artifacts` )
|
|
76
|
-
|
|
77
|
-
return counter === filteredArtifactsSchema.length
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
main()
|
package/src/change-up.sh
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
version="${1:-X.Y.Z}"
|
|
5
|
-
date_str=$(date +%F) # e.g., 2025-12-11
|
|
6
|
-
|
|
7
|
-
cat <<EOF
|
|
8
|
-
## [$version] - $date_str
|
|
9
|
-
|
|
10
|
-
### Added
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
### Changed
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
### Deprecated
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
### Removed
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
### Fixed
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
### Migration Notes
|
|
26
|
-
-
|
|
27
|
-
EOF
|