@payfit/nx-core 4.9.2-ephemeral.0 → 4.10.0-ephemeral.0
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/.env.test +0 -0
- package/README.md +0 -1
- package/eslint.config.mjs +31 -0
- package/package.json +6 -18
- package/project.json +43 -0
- package/src/executors/publisher/docker.ts +34 -0
- package/src/executors/publisher/executor.ts +30 -0
- package/src/executors/publisher/helm.ts +55 -0
- package/src/index.ts +77 -0
- package/src/scripts/version-action.ts +89 -0
- package/src/utils/aws-auth.ts +100 -0
- package/{dist/src/utils/docker.d.ts → src/utils/docker.ts} +22 -6
- package/src/utils/exec.spec.ts +16 -0
- package/src/utils/exec.ts +31 -0
- package/src/utils/get-version.ts +11 -0
- package/src/utils/github.ts +14 -0
- package/src/utils/helm.ts +125 -0
- package/src/utils/import-esm.ts +10 -0
- package/src/utils/tsh.ts +127 -0
- package/tsconfig.json +19 -0
- package/tsconfig.lib.json +22 -0
- package/tsconfig.spec.json +28 -0
- package/vite.config.ts +28 -0
- package/dist/src/executors/publisher/docker.d.ts +0 -5
- package/dist/src/executors/publisher/docker.js +0 -21
- package/dist/src/executors/publisher/docker.js.map +0 -1
- package/dist/src/executors/publisher/executor.d.ts +0 -4
- package/dist/src/executors/publisher/executor.js +0 -23
- package/dist/src/executors/publisher/executor.js.map +0 -1
- package/dist/src/executors/publisher/helm.d.ts +0 -7
- package/dist/src/executors/publisher/helm.js +0 -40
- package/dist/src/executors/publisher/helm.js.map +0 -1
- package/dist/src/index.d.ts +0 -4
- package/dist/src/index.js +0 -53
- package/dist/src/index.js.map +0 -1
- package/dist/src/scripts/version-action.d.ts +0 -25
- package/dist/src/scripts/version-action.js +0 -58
- package/dist/src/scripts/version-action.js.map +0 -1
- package/dist/src/utils/aws-auth.d.ts +0 -39
- package/dist/src/utils/aws-auth.js +0 -84
- package/dist/src/utils/aws-auth.js.map +0 -1
- package/dist/src/utils/docker.js +0 -33
- package/dist/src/utils/docker.js.map +0 -1
- package/dist/src/utils/exec.d.ts +0 -7
- package/dist/src/utils/exec.js +0 -25
- package/dist/src/utils/exec.js.map +0 -1
- package/dist/src/utils/get-version.d.ts +0 -6
- package/dist/src/utils/get-version.js +0 -14
- package/dist/src/utils/get-version.js.map +0 -1
- package/dist/src/utils/github.d.ts +0 -4
- package/dist/src/utils/github.js +0 -17
- package/dist/src/utils/github.js.map +0 -1
- package/dist/src/utils/helm.d.ts +0 -48
- package/dist/src/utils/helm.js +0 -91
- package/dist/src/utils/helm.js.map +0 -1
- package/dist/src/utils/import-esm.d.ts +0 -2
- package/dist/src/utils/import-esm.js +0 -12
- package/dist/src/utils/import-esm.js.map +0 -1
- package/dist/src/utils/tsh.d.ts +0 -10
- package/dist/src/utils/tsh.js +0 -107
- package/dist/src/utils/tsh.js.map +0 -1
- /package/{dist/src → src}/executors/publisher/schema.d.ts +0 -0
- /package/{dist/src → src}/executors/publisher/schema.json +0 -0
package/.env.test
ADDED
|
File without changes
|
package/README.md
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import baseConfig from '../../eslint.config.mjs'
|
|
2
|
+
|
|
3
|
+
export default [
|
|
4
|
+
...baseConfig,
|
|
5
|
+
{
|
|
6
|
+
files: ['**/*.json'],
|
|
7
|
+
rules: {
|
|
8
|
+
'@nx/dependency-checks': [
|
|
9
|
+
'error',
|
|
10
|
+
{
|
|
11
|
+
ignoredFiles: [
|
|
12
|
+
'{projectRoot}/eslint.config.{js,cjs,mjs}',
|
|
13
|
+
'{projectRoot}/vite.config.{js,ts,mjs,mts}',
|
|
14
|
+
],
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
},
|
|
18
|
+
languageOptions: {
|
|
19
|
+
parser: await import('jsonc-eslint-parser'),
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
files: ['**/package.json', '**/executors.json'],
|
|
24
|
+
rules: {
|
|
25
|
+
'@nx/nx-plugin-checks': 'error',
|
|
26
|
+
},
|
|
27
|
+
languageOptions: {
|
|
28
|
+
parser: await import('jsonc-eslint-parser'),
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
]
|
package/package.json
CHANGED
|
@@ -1,31 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@payfit/nx-core",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.10.0-ephemeral.0",
|
|
4
4
|
"type": "commonjs",
|
|
5
|
-
"main": "
|
|
6
|
-
"types": "
|
|
7
|
-
"typings": "dist/src/index.d.ts",
|
|
8
|
-
"repository": {
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "https://github.com/payfit/nx-common-packages.git",
|
|
11
|
-
"directory": "packages/nx-core"
|
|
12
|
-
},
|
|
5
|
+
"main": "./src/index.js",
|
|
6
|
+
"types": "./src/index.d.ts",
|
|
13
7
|
"dependencies": {
|
|
14
|
-
"@nx/devkit": "21.0.
|
|
8
|
+
"@nx/devkit": "21.0.1",
|
|
15
9
|
"get-port": "^7.1.0",
|
|
16
10
|
"ky": "^1.8.1",
|
|
17
|
-
"nx": "21.0.
|
|
11
|
+
"nx": "21.0.1",
|
|
18
12
|
"semver": "7.7.1",
|
|
19
13
|
"tinyexec": "0.3.2",
|
|
20
14
|
"tslib": "^2.8.1",
|
|
21
15
|
"yaml": "^2.7.0",
|
|
22
16
|
"zod": "^3.24.3"
|
|
23
17
|
},
|
|
24
|
-
"executors": "./executors.json"
|
|
25
|
-
"files": [
|
|
26
|
-
"dist",
|
|
27
|
-
"!**/*.tsbuildinfo",
|
|
28
|
-
"generators.json",
|
|
29
|
-
"executors.json"
|
|
30
|
-
]
|
|
18
|
+
"executors": "./executors.json"
|
|
31
19
|
}
|
package/project.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@payfit/nx-core",
|
|
3
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
+
"sourceRoot": "packages/nx-core/src",
|
|
5
|
+
"projectType": "library",
|
|
6
|
+
"tags": ["scope:tooling"],
|
|
7
|
+
"targets": {
|
|
8
|
+
"build": {
|
|
9
|
+
"executor": "@nx/js:tsc",
|
|
10
|
+
"outputs": ["{options.outputPath}"],
|
|
11
|
+
"options": {
|
|
12
|
+
"outputPath": "dist/packages/nx-core",
|
|
13
|
+
"main": "packages/nx-core/src/index.ts",
|
|
14
|
+
"tsConfig": "packages/nx-core/tsconfig.lib.json",
|
|
15
|
+
"assets": [
|
|
16
|
+
"./packages/nx-core/*.md",
|
|
17
|
+
{
|
|
18
|
+
"input": "./packages/nx-core/src",
|
|
19
|
+
"glob": "**/!(*.ts)",
|
|
20
|
+
"output": "./src"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"input": "./packages/nx-core/src",
|
|
24
|
+
"glob": "**/*.d.ts",
|
|
25
|
+
"output": "./src"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"input": "./packages/nx-core",
|
|
29
|
+
"glob": "executors.json",
|
|
30
|
+
"output": "."
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"test": {
|
|
36
|
+
"executor": "@nx/vite:test",
|
|
37
|
+
"outputs": ["{options.reportsDirectory}"],
|
|
38
|
+
"options": {
|
|
39
|
+
"reportsDirectory": "../../coverage/packages/nx-core"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as fs from 'node:fs'
|
|
2
|
+
import { join } from 'path'
|
|
3
|
+
|
|
4
|
+
import { ExecutorContext } from '@nx/devkit'
|
|
5
|
+
|
|
6
|
+
import { checkAwsAuth, loginToEcr, pushImageToEcr } from '../../utils/aws-auth'
|
|
7
|
+
import { buildDockerImage } from '../../utils/docker'
|
|
8
|
+
import { PublisherExecutorOptions } from './schema'
|
|
9
|
+
|
|
10
|
+
export async function publishDocker(
|
|
11
|
+
options: PublisherExecutorOptions,
|
|
12
|
+
context: ExecutorContext,
|
|
13
|
+
version: string,
|
|
14
|
+
): Promise<{
|
|
15
|
+
success: boolean
|
|
16
|
+
}> {
|
|
17
|
+
await checkAwsAuth()
|
|
18
|
+
await loginToEcr()
|
|
19
|
+
|
|
20
|
+
const projectRoot =
|
|
21
|
+
context.projectsConfigurations.projects[context.projectName].root
|
|
22
|
+
const projectDockerfile = join(projectRoot, 'Dockerfile')
|
|
23
|
+
|
|
24
|
+
if (!fs.existsSync(projectDockerfile)) {
|
|
25
|
+
throw new Error('Dockerfile not found in project root')
|
|
26
|
+
}
|
|
27
|
+
console.log('Building docker image with version ' + version)
|
|
28
|
+
await buildDockerImage(options.ecrRegistry, projectDockerfile, version)
|
|
29
|
+
|
|
30
|
+
console.log(
|
|
31
|
+
`Publishing docker image to ${options.ecrRegistry} with version ${version}`,
|
|
32
|
+
)
|
|
33
|
+
return await pushImageToEcr(options.ecrRegistry, version)
|
|
34
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ExecutorContext } from '@nx/devkit'
|
|
2
|
+
|
|
3
|
+
import { getVersion } from '../../utils/get-version'
|
|
4
|
+
import { publishDocker } from './docker'
|
|
5
|
+
import { publishHelm } from './helm'
|
|
6
|
+
import { PublisherExecutorOptions, PublisherExecutorSchema } from './schema'
|
|
7
|
+
|
|
8
|
+
const runExecutor: (
|
|
9
|
+
options: PublisherExecutorOptions,
|
|
10
|
+
context: ExecutorContext,
|
|
11
|
+
) => Promise<PublisherExecutorSchema> = async (
|
|
12
|
+
options: PublisherExecutorOptions,
|
|
13
|
+
context: ExecutorContext,
|
|
14
|
+
) => {
|
|
15
|
+
try {
|
|
16
|
+
const version = getVersion(context.projectName)
|
|
17
|
+
await publishDocker(options, context, version)
|
|
18
|
+
await publishHelm(options, context, version)
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.error(error)
|
|
21
|
+
return {
|
|
22
|
+
success: false,
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
success: true,
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default runExecutor
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as fs from 'node:fs'
|
|
2
|
+
|
|
3
|
+
import { ExecutorContext } from '@nx/devkit'
|
|
4
|
+
|
|
5
|
+
import { checkAwsAuth } from '../../utils/aws-auth'
|
|
6
|
+
import { getSanitizedCurrentGitBranch } from '../../utils/github'
|
|
7
|
+
import {
|
|
8
|
+
installHelmRepo,
|
|
9
|
+
packageHelm,
|
|
10
|
+
pushPackagedHelm,
|
|
11
|
+
resetTeleportProxyHelmChartFile,
|
|
12
|
+
setupTeleportProxyHelmChartFile,
|
|
13
|
+
} from '../../utils/helm'
|
|
14
|
+
import { getLocalPortForChartMuseum } from '../../utils/tsh'
|
|
15
|
+
import { PublisherExecutorOptions } from './schema'
|
|
16
|
+
|
|
17
|
+
export async function publishHelm(
|
|
18
|
+
options: PublisherExecutorOptions,
|
|
19
|
+
context: ExecutorContext,
|
|
20
|
+
version: string,
|
|
21
|
+
): Promise<{
|
|
22
|
+
success: boolean
|
|
23
|
+
stdout: any
|
|
24
|
+
stderr: any
|
|
25
|
+
}> {
|
|
26
|
+
const projectHelmFolder = `apps/${context.projectName}/.deploy`
|
|
27
|
+
const destinationHelmFolder = `dist/apps/${context.projectName}/chart/`
|
|
28
|
+
const gitBranchName = await getSanitizedCurrentGitBranch()
|
|
29
|
+
|
|
30
|
+
if (!gitBranchName) throw new Error('Unable to get current Git branch')
|
|
31
|
+
|
|
32
|
+
await checkAwsAuth()
|
|
33
|
+
|
|
34
|
+
if (!fs.existsSync(projectHelmFolder)) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`.deploy folder not found for project ${context.projectName}`,
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
console.log(
|
|
40
|
+
`Publishing Helm chart to ${options.chartRegistry}/${gitBranchName} with version ${version}`,
|
|
41
|
+
)
|
|
42
|
+
// connect to the chartmuseum through teleport
|
|
43
|
+
using proxyData = await getLocalPortForChartMuseum()
|
|
44
|
+
await proxyData.isReady()
|
|
45
|
+
|
|
46
|
+
await setupTeleportProxyHelmChartFile(projectHelmFolder, proxyData.port)
|
|
47
|
+
await installHelmRepo(projectHelmFolder)
|
|
48
|
+
await packageHelm(projectHelmFolder, version, destinationHelmFolder)
|
|
49
|
+
await resetTeleportProxyHelmChartFile(projectHelmFolder, proxyData.port)
|
|
50
|
+
return pushPackagedHelm(
|
|
51
|
+
`${destinationHelmFolder}${context.projectName}-${version}.tgz`,
|
|
52
|
+
options.chartRegistry,
|
|
53
|
+
gitBranchName,
|
|
54
|
+
)
|
|
55
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { existsSync } from 'fs'
|
|
2
|
+
import { dirname, join } from 'path'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
CreateNodesContextV2,
|
|
6
|
+
createNodesFromFiles,
|
|
7
|
+
CreateNodesV2,
|
|
8
|
+
readJsonFile,
|
|
9
|
+
} from '@nx/devkit'
|
|
10
|
+
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/no-empty-object-type
|
|
12
|
+
export interface MyPluginOptions {}
|
|
13
|
+
|
|
14
|
+
export const createNodesV2: CreateNodesV2<MyPluginOptions> = [
|
|
15
|
+
'**/project.json',
|
|
16
|
+
async (configFiles, options, context) => {
|
|
17
|
+
return await createNodesFromFiles(
|
|
18
|
+
(configFile, options, context) =>
|
|
19
|
+
createNodesInternal(configFile, options, context),
|
|
20
|
+
configFiles,
|
|
21
|
+
options,
|
|
22
|
+
context,
|
|
23
|
+
)
|
|
24
|
+
},
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
async function createNodesInternal(
|
|
28
|
+
configFilePath: string,
|
|
29
|
+
options: MyPluginOptions,
|
|
30
|
+
context: CreateNodesContextV2,
|
|
31
|
+
) {
|
|
32
|
+
const projectConfiguration = readJsonFile(configFilePath)
|
|
33
|
+
const projectRoot = dirname(configFilePath)
|
|
34
|
+
|
|
35
|
+
const isDockerProject = existsSync(join(projectRoot, 'Dockerfile'))
|
|
36
|
+
const isHelmProject = existsSync(join(projectRoot, '.deploy/Chart.yaml'))
|
|
37
|
+
|
|
38
|
+
const targets = {}
|
|
39
|
+
|
|
40
|
+
const ecrRegistry = isDockerProject
|
|
41
|
+
? projectConfiguration.metadata &&
|
|
42
|
+
projectConfiguration.metadata['ecrRepository']
|
|
43
|
+
: undefined
|
|
44
|
+
const chartRegistry = isHelmProject
|
|
45
|
+
? projectConfiguration.metadata &&
|
|
46
|
+
projectConfiguration.metadata['chartRegistry']
|
|
47
|
+
: undefined
|
|
48
|
+
|
|
49
|
+
if (isHelmProject || isDockerProject) {
|
|
50
|
+
const publisherConfig = readJsonFile(
|
|
51
|
+
join(__dirname, '/executors/publisher/schema.json'),
|
|
52
|
+
)
|
|
53
|
+
targets['nx-release-publish'] = {
|
|
54
|
+
executor: '@payfit/nx-core:publisher',
|
|
55
|
+
options: {
|
|
56
|
+
ecrRegistry,
|
|
57
|
+
chartRegistry,
|
|
58
|
+
},
|
|
59
|
+
cache: true,
|
|
60
|
+
inputs: ['production', '^production'],
|
|
61
|
+
outputs: [`{workspaceRoot}/dist/apps/${projectConfiguration.name}/chart`],
|
|
62
|
+
metadata: {
|
|
63
|
+
technologies: ['helm', 'docker'],
|
|
64
|
+
description: publisherConfig.description,
|
|
65
|
+
},
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
projects: {
|
|
71
|
+
[projectRoot]: {
|
|
72
|
+
...projectConfiguration,
|
|
73
|
+
targets,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { ProjectGraph, Tree } from '@nx/devkit'
|
|
2
|
+
import { VersionActions } from 'nx/release'
|
|
3
|
+
import { NxReleaseVersionConfiguration } from 'nx/src/config/nx-json'
|
|
4
|
+
import { inc } from 'semver'
|
|
5
|
+
|
|
6
|
+
export default class customVersionAction extends VersionActions {
|
|
7
|
+
validManifestFilenames: string[]
|
|
8
|
+
async readCurrentVersionFromSourceManifest(
|
|
9
|
+
tree: Tree,
|
|
10
|
+
): Promise<{ currentVersion: string; manifestPath: string } | null> {
|
|
11
|
+
return {
|
|
12
|
+
currentVersion: '0.0.0',
|
|
13
|
+
manifestPath: 'apps/my-nest-app/project.json',
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
async readCurrentVersionFromRegistry(
|
|
17
|
+
tree: Tree,
|
|
18
|
+
currentVersionResolverMetadata: NxReleaseVersionConfiguration['currentVersionResolverMetadata'],
|
|
19
|
+
): Promise<{ currentVersion: string | null; logText: string } | null> {
|
|
20
|
+
return {
|
|
21
|
+
currentVersion: '0.0.0',
|
|
22
|
+
logText: 'Current version from registry',
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async readCurrentVersionOfDependency(
|
|
26
|
+
tree: Tree,
|
|
27
|
+
projectGraph: ProjectGraph,
|
|
28
|
+
dependencyProjectName: string,
|
|
29
|
+
): Promise<{
|
|
30
|
+
currentVersion: string | null
|
|
31
|
+
dependencyCollection: string | null
|
|
32
|
+
}> {
|
|
33
|
+
return {
|
|
34
|
+
currentVersion: '0.0.0',
|
|
35
|
+
dependencyCollection: '0.0.0',
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async isLocalDependencyProtocol(versionSpecifier: string): Promise<boolean> {
|
|
39
|
+
return false
|
|
40
|
+
}
|
|
41
|
+
async updateProjectVersion(
|
|
42
|
+
tree: Tree,
|
|
43
|
+
newVersion: string,
|
|
44
|
+
): Promise<string[]> {
|
|
45
|
+
// Update the version in the VERSION file
|
|
46
|
+
const currentProject = this.projectGraphNode.name
|
|
47
|
+
const versionFilePath = `dist/apps/${currentProject}/VERSION`
|
|
48
|
+
tree.write(versionFilePath, newVersion)
|
|
49
|
+
return []
|
|
50
|
+
}
|
|
51
|
+
async updateProjectDependencies(
|
|
52
|
+
tree: Tree,
|
|
53
|
+
projectGraph: ProjectGraph,
|
|
54
|
+
dependenciesToUpdate: Record<string, string>,
|
|
55
|
+
): Promise<string[]> {
|
|
56
|
+
return []
|
|
57
|
+
}
|
|
58
|
+
async calculateNewVersion(
|
|
59
|
+
currentVersion: string | null,
|
|
60
|
+
newVersionInput: string,
|
|
61
|
+
newVersionInputReason: string,
|
|
62
|
+
newVersionInputReasonData: Record<string, unknown>,
|
|
63
|
+
preid: string,
|
|
64
|
+
): Promise<{
|
|
65
|
+
newVersion: string
|
|
66
|
+
logText: string
|
|
67
|
+
}> {
|
|
68
|
+
function formatDate() {
|
|
69
|
+
const date = new Date()
|
|
70
|
+
const year = date.getFullYear()
|
|
71
|
+
const month = String(date.getMonth() + 1).padStart(2, '0') // getMonth() returns 0-11
|
|
72
|
+
const day = date.getDate()
|
|
73
|
+
|
|
74
|
+
return `${year}${month}.${day}.`
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function getNewVersionFromCurrentVersion(currentVersion: string) {
|
|
78
|
+
const expectedPattern = formatDate()
|
|
79
|
+
return !currentVersion.startsWith(expectedPattern)
|
|
80
|
+
? `${expectedPattern}0`
|
|
81
|
+
: inc(currentVersion, 'patch')
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
newVersion: getNewVersionFromCurrentVersion(currentVersion),
|
|
86
|
+
logText: `New version: ${getNewVersionFromCurrentVersion(currentVersion)}`,
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { getDockerOrPodman } from './docker'
|
|
2
|
+
import { exec_command } from './exec'
|
|
3
|
+
|
|
4
|
+
let profileName = 'OIDC-PROFILE'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Return the AWS profile name to use in AWS cli commands
|
|
8
|
+
*/
|
|
9
|
+
export function getProfileName() {
|
|
10
|
+
return profileName
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Retrieves the AWS credentials from environment variables.
|
|
15
|
+
* Ensures that `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_DEFAULT_REGION` are properly set.
|
|
16
|
+
* Throws an error if credentials or region are missing.
|
|
17
|
+
*
|
|
18
|
+
* @return {Object} An object containing AWS credentials.
|
|
19
|
+
* @return {string} return.accessKeyId The AWS Access Key ID.
|
|
20
|
+
* @return {string} return.secretAccessKey The AWS Secret Access Key.
|
|
21
|
+
* @return {string} return.region The AWS Region.
|
|
22
|
+
*/
|
|
23
|
+
export function getAwsCredentialsSet(): {
|
|
24
|
+
accessKeyId: string
|
|
25
|
+
secretAccessKey: string
|
|
26
|
+
region: string
|
|
27
|
+
} {
|
|
28
|
+
const accessKeyId = process.env.AWS_ACCESS_KEY_ID
|
|
29
|
+
const secretAccessKey = process.env.AWS_SECRET_ACCESS_KEY
|
|
30
|
+
const region = process.env.AWS_DEFAULT_REGION
|
|
31
|
+
if (!accessKeyId || !secretAccessKey) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
'AWS credentials not found, please set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables (or attach GLOBAL_ORG context if you are using CircleCI)',
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
if (!region) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
'AWS region not found, please set AWS_DEFAULT_REGION environment variable (or attach GLOBAL_ORG context if you are using CircleCI)',
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
return { accessKeyId, secretAccessKey, region }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Retrieves the authentication information for a given OIDC profile.
|
|
46
|
+
* If the specified profile exists, it fetches the configuration; otherwise, it returns false.
|
|
47
|
+
*
|
|
48
|
+
* @return {Promise<string | boolean>} The authentication details if the profile exists, or false if the profile does not exist.
|
|
49
|
+
*/
|
|
50
|
+
export async function getAuthWithOidcProfile(): Promise<string | boolean> {
|
|
51
|
+
try {
|
|
52
|
+
const profileExist = await exec_command(
|
|
53
|
+
`aws configure list-profiles | grep ${profileName}`,
|
|
54
|
+
)
|
|
55
|
+
if (profileExist.success) {
|
|
56
|
+
return profileExist.stdout
|
|
57
|
+
}
|
|
58
|
+
return false
|
|
59
|
+
} catch (e) {
|
|
60
|
+
console.error(e)
|
|
61
|
+
return false
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function loginToEcr() {
|
|
66
|
+
return exec_command(
|
|
67
|
+
`aws ecr get-login-password --profile ${profileName} --region eu-west-3 | ${await getDockerOrPodman()} login --username AWS --password-stdin ${process.env.AWS_ECR_REGISTRY}`,
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Check AWS CLI with the OIDC profile otherwise use the default credentials
|
|
73
|
+
* @returns {string} the profile's name
|
|
74
|
+
*/
|
|
75
|
+
export async function checkAwsAuth(): Promise<string> {
|
|
76
|
+
const profileExist = await getAuthWithOidcProfile()
|
|
77
|
+
if (profileExist) {
|
|
78
|
+
console.log('OIDC profile found, using it')
|
|
79
|
+
profileName = 'OIDC-PROFILE'
|
|
80
|
+
} else if (getAwsCredentialsSet()) {
|
|
81
|
+
console.log(
|
|
82
|
+
'OIDC profile not found, using AWS_KEY_ID and AWS_SECRET_ACCESS_KEY',
|
|
83
|
+
)
|
|
84
|
+
profileName = 'default'
|
|
85
|
+
} else {
|
|
86
|
+
throw new Error(
|
|
87
|
+
'AWS credentials not found, please attach CORE-PLATFORM_SHARED_ENV context if you are using CircleCI or export AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables',
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
return profileName
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function pushImageToEcr(
|
|
94
|
+
repositoryName: string,
|
|
95
|
+
version: string,
|
|
96
|
+
): Promise<{ success: boolean }> {
|
|
97
|
+
return exec_command(
|
|
98
|
+
`docker push ${process.env.AWS_ECR_REGISTRY}/${repositoryName}:${version}`,
|
|
99
|
+
)
|
|
100
|
+
}
|
|
@@ -1,9 +1,20 @@
|
|
|
1
|
+
import { exec_command } from './exec'
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Determines the available container management tool by checking for Docker and fallback to Podman if Docker is unavailable.
|
|
3
5
|
*
|
|
4
6
|
* @return {Promise<string>} A promise that resolves to the string 'docker' if Docker is available, or 'podman' if Podman is used as a fallback.
|
|
5
7
|
*/
|
|
6
|
-
export
|
|
8
|
+
export async function getDockerOrPodman(): Promise<string> {
|
|
9
|
+
try {
|
|
10
|
+
await exec_command('docker --version')
|
|
11
|
+
return 'docker'
|
|
12
|
+
} catch (e) {
|
|
13
|
+
console.log('docker not found, trying podman')
|
|
14
|
+
return 'podman'
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
7
18
|
/**
|
|
8
19
|
* Builds a Docker image using the provided Dockerfile.
|
|
9
20
|
*
|
|
@@ -12,8 +23,13 @@ export declare function getDockerOrPodman(): Promise<string>;
|
|
|
12
23
|
* @param version The version of the image to build.
|
|
13
24
|
* @return {Promise<{success: boolean, stdout: string, stderr: string}>} A promise that resolves to an object containing the success status, stdout, and stderr of the command.
|
|
14
25
|
*/
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
26
|
+
export async function buildDockerImage(
|
|
27
|
+
imageName: string,
|
|
28
|
+
dockerfilePath: string,
|
|
29
|
+
version: string,
|
|
30
|
+
): Promise<{ success: boolean; stdout: string; stderr: string }> {
|
|
31
|
+
const dockerOrPodman = await getDockerOrPodman()
|
|
32
|
+
return exec_command(
|
|
33
|
+
`${dockerOrPodman} buildx build -t ${process.env.AWS_ECR_REGISTRY}/${imageName}:${version} -f ${dockerfilePath} --secret id=NPM_TOKEN .`,
|
|
34
|
+
)
|
|
35
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { exec_command } from './exec'
|
|
2
|
+
|
|
3
|
+
describe('exec', () => {
|
|
4
|
+
it('can run', async () => {
|
|
5
|
+
const output = await exec_command('echo "Hello World"')
|
|
6
|
+
expect(output.success).toBe(true)
|
|
7
|
+
expect(output.stdout).toBe('Hello World\n')
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
it('can run with stderr', async () => {
|
|
11
|
+
const output = await exec_command('echo "Hello World" 1>&2')
|
|
12
|
+
expect(output.success).toBe(false)
|
|
13
|
+
expect(output.stdout).toBe('')
|
|
14
|
+
expect(output.stderr).toBe('Hello World\n')
|
|
15
|
+
})
|
|
16
|
+
})
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { exec } from 'child_process'
|
|
2
|
+
import { promisify } from 'util'
|
|
3
|
+
|
|
4
|
+
import type { Options, TinyExec } from 'tinyexec'
|
|
5
|
+
|
|
6
|
+
import { x } from 'tinyexec'
|
|
7
|
+
|
|
8
|
+
export async function exec_command(command: string) {
|
|
9
|
+
const { stdout, stderr } = await promisify(exec)(command)
|
|
10
|
+
console.log(stdout)
|
|
11
|
+
console.error(stderr)
|
|
12
|
+
|
|
13
|
+
const success = !stderr
|
|
14
|
+
return { success, stdout, stderr }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function createLoggingExecWrapper(execFn: TinyExec): TinyExec {
|
|
18
|
+
return (
|
|
19
|
+
command: string,
|
|
20
|
+
args: string[] = [],
|
|
21
|
+
options: Partial<Options> = {},
|
|
22
|
+
) => {
|
|
23
|
+
console.log(`Running '${command} ${args.join(' ')}'...`)
|
|
24
|
+
return execFn(command, args, {
|
|
25
|
+
throwOnError: true,
|
|
26
|
+
...options,
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const execTiny = createLoggingExecWrapper(x)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as fs from 'node:fs'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Get the version of a project
|
|
5
|
+
* @param projectName
|
|
6
|
+
* @returns {string}
|
|
7
|
+
*/
|
|
8
|
+
export function getVersion(projectName: string): string {
|
|
9
|
+
const versionFilePath = `dist/apps/${projectName}/VERSION`
|
|
10
|
+
return fs.readFileSync(versionFilePath, 'utf8')
|
|
11
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { exec_command } from './exec'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Get sanitized current git branch name
|
|
5
|
+
*/
|
|
6
|
+
export async function getSanitizedCurrentGitBranch() {
|
|
7
|
+
const branchName = await exec_command(`git branch --show-current`)
|
|
8
|
+
return branchName.success
|
|
9
|
+
? branchName.stdout
|
|
10
|
+
.trim()
|
|
11
|
+
.toLowerCase()
|
|
12
|
+
.replace(/[^a-z0-9]/g, '')
|
|
13
|
+
: ''
|
|
14
|
+
}
|