@forge/cli-shared 8.8.1 → 8.8.2-next.1
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/CHANGELOG.md +13 -0
- package/out/graphql/graphql-types.d.ts +27 -0
- package/out/graphql/graphql-types.d.ts.map +1 -1
- package/out/tunnel/docker-compose-lifecycle.d.ts +17 -0
- package/out/tunnel/docker-compose-lifecycle.d.ts.map +1 -0
- package/out/tunnel/docker-compose-lifecycle.js +160 -0
- package/out/tunnel/index.d.ts +1 -0
- package/out/tunnel/index.d.ts.map +1 -1
- package/out/tunnel/index.js +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { UserError } from '../shared';
|
|
2
|
+
import { ConfigFile } from '../config/config-file';
|
|
3
|
+
import { Services } from '@forge/manifest';
|
|
4
|
+
export declare class InvalidContainerServicePort extends UserError {
|
|
5
|
+
constructor(serviceKey: string);
|
|
6
|
+
}
|
|
7
|
+
export declare class DockerUnableToPullProxySidecarImage extends UserError {
|
|
8
|
+
constructor(err?: Error);
|
|
9
|
+
}
|
|
10
|
+
export declare class DockerUnableToStartError extends UserError {
|
|
11
|
+
constructor(err?: Error);
|
|
12
|
+
}
|
|
13
|
+
export declare const generateContainersDockerComposeFile: (services: Services, appId: string, envId: string) => Promise<Record<string, string>>;
|
|
14
|
+
export declare const deleteDockerComposeFile: (composeFile: string) => Promise<void>;
|
|
15
|
+
export declare const startDockerComposeStack: (dockerComposeFilePath: string, serviceKey: string) => Promise<void>;
|
|
16
|
+
export declare const stopDockerComposeStack: (configFile: ConfigFile, composeFiles?: Record<string, string>) => Promise<void>;
|
|
17
|
+
//# sourceMappingURL=docker-compose-lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docker-compose-lifecycle.d.ts","sourceRoot":"","sources":["../../src/tunnel/docker-compose-lifecycle.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAK3C,qBAAa,2BAA4B,SAAQ,SAAS;gBAC5C,UAAU,EAAE,MAAM;CAG/B;AAED,qBAAa,mCAAoC,SAAQ,SAAS;gBACpD,GAAG,CAAC,EAAE,KAAK;CAGxB;AAED,qBAAa,wBAAyB,SAAQ,SAAS;gBACzC,GAAG,CAAC,EAAE,KAAK;CAGxB;AAMD,eAAO,MAAM,mCAAmC,8BAAqC,MAAM,SAAS,MAAM,oCA6CzG,CAAC;AA0DF,eAAO,MAAM,uBAAuB,gBAAuB,MAAM,kBAYhE,CAAC;AAOF,eAAO,MAAM,uBAAuB,0BAAiC,MAAM,cAAc,MAAM,kBAuB9F,CAAC;AAMF,eAAO,MAAM,sBAAsB,eAAsB,UAAU,iBAAiB,OAAO,MAAM,EAAE,MAAM,CAAC,kBAyBzG,CAAC"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stopDockerComposeStack = exports.startDockerComposeStack = exports.deleteDockerComposeFile = exports.generateContainersDockerComposeFile = exports.DockerUnableToStartError = exports.DockerUnableToPullProxySidecarImage = exports.InvalidContainerServicePort = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const fs = tslib_1.__importStar(require("fs"));
|
|
6
|
+
const path = tslib_1.__importStar(require("path"));
|
|
7
|
+
const yaml = tslib_1.__importStar(require("yaml"));
|
|
8
|
+
const docker_compose_1 = require("docker-compose");
|
|
9
|
+
const shared_1 = require("../shared");
|
|
10
|
+
const text_1 = require("../ui/text");
|
|
11
|
+
const tunnel_options_1 = require("./tunnel-options");
|
|
12
|
+
const HIDDEN_DIR = '.services';
|
|
13
|
+
class InvalidContainerServicePort extends shared_1.UserError {
|
|
14
|
+
constructor(serviceKey) {
|
|
15
|
+
super(text_1.Text.error.invalidServicePort(serviceKey));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.InvalidContainerServicePort = InvalidContainerServicePort;
|
|
19
|
+
class DockerUnableToPullProxySidecarImage extends shared_1.UserError {
|
|
20
|
+
constructor(err) {
|
|
21
|
+
super(text_1.Text.tunnel.unableToPullProxySidecarImage(err?.message ?? 'Unknown Error Occurred.'));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.DockerUnableToPullProxySidecarImage = DockerUnableToPullProxySidecarImage;
|
|
25
|
+
class DockerUnableToStartError extends shared_1.UserError {
|
|
26
|
+
constructor(err) {
|
|
27
|
+
super(text_1.Text.tunnel.unableToStartDockerComposeStack(err?.message ?? 'Unknown Error Occurred.'));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.DockerUnableToStartError = DockerUnableToStartError;
|
|
31
|
+
const generateContainersDockerComposeFile = async (services, appId, envId) => {
|
|
32
|
+
const filesGenerated = {};
|
|
33
|
+
for (const service of services) {
|
|
34
|
+
const { key: serviceKey, containers } = service;
|
|
35
|
+
const containersWithTunnelConfig = containers.filter((container) => !!container.tunnel);
|
|
36
|
+
if (containersWithTunnelConfig.length > 0) {
|
|
37
|
+
const port = await (0, tunnel_options_1.getServicePort)(services, serviceKey);
|
|
38
|
+
if (!port || port < 1024 || port > 49152) {
|
|
39
|
+
throw new InvalidContainerServicePort(serviceKey);
|
|
40
|
+
}
|
|
41
|
+
const containerConfig = Object.fromEntries(containersWithTunnelConfig.map((container) => {
|
|
42
|
+
const config = {
|
|
43
|
+
container_name: container.key,
|
|
44
|
+
...container.tunnel?.docker
|
|
45
|
+
};
|
|
46
|
+
const envArray = container?.tunnel?.docker.environment ?? [];
|
|
47
|
+
const filteredEnvArray = envArray.filter((envVar) => !envVar.startsWith('FORGE_EGRESS_PROXY_URL='));
|
|
48
|
+
filteredEnvArray.push('FORGE_EGRESS_PROXY_URL=http://proxy-sidecar:7072');
|
|
49
|
+
config.environment = filteredEnvArray;
|
|
50
|
+
return [container.key, config];
|
|
51
|
+
}));
|
|
52
|
+
const dockerComposeConfig = {
|
|
53
|
+
services: {
|
|
54
|
+
...containerConfig,
|
|
55
|
+
...(await getProxySidecarConfig(serviceKey, Object.keys(containerConfig), port, appId, envId))
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const yamlString = yaml.stringify(dockerComposeConfig);
|
|
59
|
+
const filePath = getContainerDockerComposePath(serviceKey);
|
|
60
|
+
fs.writeFileSync(filePath, yamlString);
|
|
61
|
+
filesGenerated[serviceKey] = filePath;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return filesGenerated;
|
|
65
|
+
};
|
|
66
|
+
exports.generateContainersDockerComposeFile = generateContainersDockerComposeFile;
|
|
67
|
+
const getProxySidecarConfig = async (serviceKey, containerKeys, port, appId, envId) => {
|
|
68
|
+
let fopBaseUrl = 'https://forge-outbound-proxy.services.atlassian.com';
|
|
69
|
+
let jwksUrl = 'https://forge.cdn.prod.atlassian-dev.net/.well-known/jwks.json';
|
|
70
|
+
let proxySidecarImage = 'forge-ecr.services.atlassian.com/forge-platform/proxy-sidecar:latest';
|
|
71
|
+
if (process.env.FORGE_GRAPHQL_GATEWAY?.startsWith('https://api-private.stg.atlassian.com/graphql')) {
|
|
72
|
+
fopBaseUrl = 'https://forge-outbound-proxy.stg.services.atlassian.com';
|
|
73
|
+
jwksUrl = 'https://forge.cdn.stg.atlassian-dev.net/.well-known/jwks.json';
|
|
74
|
+
proxySidecarImage = 'forge-ecr.stg.services.atlassian.com/forge-platform/proxy-sidecar:latest';
|
|
75
|
+
}
|
|
76
|
+
let appIdShort = appId;
|
|
77
|
+
if (appId.startsWith('ari:cloud:ecosystem::app/')) {
|
|
78
|
+
appIdShort = appId.split('/')[1];
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
'proxy-sidecar': {
|
|
82
|
+
image: proxySidecarImage,
|
|
83
|
+
container_name: `proxy-sidecar-${serviceKey}`,
|
|
84
|
+
environment: [
|
|
85
|
+
`SERVICE_URL=http://${containerKeys[0]}:8080`,
|
|
86
|
+
`FOP_BASE_URL=${fopBaseUrl}`,
|
|
87
|
+
`APP_ID=ari:cloud:ecosystem::app/${appIdShort}`,
|
|
88
|
+
`ENV_ID=ari:cloud:ecosystem::environment/${appIdShort}/${envId}`,
|
|
89
|
+
`JWKS_URL=${jwksUrl}`,
|
|
90
|
+
`IS_LOCAL_DEV=true`
|
|
91
|
+
],
|
|
92
|
+
ports: [`${port}:${tunnel_options_1.DEFAULT_PROXY_INGRESS_PORT}`],
|
|
93
|
+
depends_on: containerKeys
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
const getContainerDockerComposePath = (serviceKey) => {
|
|
98
|
+
const hiddenDir = path.join(process.cwd(), HIDDEN_DIR);
|
|
99
|
+
if (!fs.existsSync(hiddenDir)) {
|
|
100
|
+
fs.mkdirSync(hiddenDir, { recursive: true });
|
|
101
|
+
}
|
|
102
|
+
return path.join(hiddenDir, `docker-compose-${serviceKey}.yml`);
|
|
103
|
+
};
|
|
104
|
+
const deleteDockerComposeFile = async (composeFile) => {
|
|
105
|
+
if (fs.existsSync(composeFile)) {
|
|
106
|
+
fs.unlinkSync(composeFile);
|
|
107
|
+
}
|
|
108
|
+
const hiddenDir = path.join(process.cwd(), HIDDEN_DIR);
|
|
109
|
+
if (fs.existsSync(hiddenDir)) {
|
|
110
|
+
const files = fs.readdirSync(hiddenDir);
|
|
111
|
+
if (files.length === 0) {
|
|
112
|
+
fs.rmdirSync(hiddenDir);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
exports.deleteDockerComposeFile = deleteDockerComposeFile;
|
|
117
|
+
const startDockerComposeStack = async (dockerComposeFilePath, serviceKey) => {
|
|
118
|
+
try {
|
|
119
|
+
await (0, docker_compose_1.pullOne)('proxy-sidecar', {
|
|
120
|
+
cwd: path.dirname(dockerComposeFilePath),
|
|
121
|
+
log: true,
|
|
122
|
+
config: dockerComposeFilePath
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
throw new DockerUnableToPullProxySidecarImage(err);
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
await (0, docker_compose_1.upAll)({
|
|
130
|
+
cwd: path.dirname(dockerComposeFilePath),
|
|
131
|
+
log: true,
|
|
132
|
+
config: dockerComposeFilePath,
|
|
133
|
+
composeOptions: [`-p${serviceKey}`]
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
throw new DockerUnableToStartError(err);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
exports.startDockerComposeStack = startDockerComposeStack;
|
|
141
|
+
const stopDockerComposeStack = async (configFile, composeFiles) => {
|
|
142
|
+
if (!composeFiles || Object.keys(composeFiles).length === 0)
|
|
143
|
+
return;
|
|
144
|
+
const { services } = await configFile.readConfig();
|
|
145
|
+
const serviceWithTunnelConfigExists = services?.some((service) => service.containers?.some((container) => {
|
|
146
|
+
return !!container.tunnel;
|
|
147
|
+
}));
|
|
148
|
+
if (!services || services.length === 0 || !serviceWithTunnelConfigExists)
|
|
149
|
+
return;
|
|
150
|
+
await Promise.all(Object.entries(composeFiles).map(async ([serviceKey, file]) => {
|
|
151
|
+
try {
|
|
152
|
+
await (0, docker_compose_1.downAll)({ cwd: '.', log: true, config: file, composeOptions: [`-p${serviceKey}`] });
|
|
153
|
+
await (0, exports.deleteDockerComposeFile)(file);
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
throw new Error(text_1.Text.tunnel.unableToStopDockerComposeStack(serviceKey, err.message ?? 'Unknown Error Occurred.'));
|
|
157
|
+
}
|
|
158
|
+
}));
|
|
159
|
+
};
|
|
160
|
+
exports.stopDockerComposeStack = stopDockerComposeStack;
|
package/out/tunnel/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tunnel/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tunnel/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,kBAAkB,CAAC"}
|
package/out/tunnel/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forge/cli-shared",
|
|
3
|
-
"version": "8.8.1",
|
|
3
|
+
"version": "8.8.2-next.1",
|
|
4
4
|
"description": "Common functionality for Forge CLI",
|
|
5
5
|
"author": "Atlassian",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"generate-graphql-types": "graphql-codegen --config src/graphql/codegen.yml"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@forge/manifest": "
|
|
15
|
+
"@forge/manifest": "11.0.0-next.0",
|
|
16
16
|
"@forge/util": "2.0.1",
|
|
17
17
|
"@forge/i18n": "0.0.7",
|
|
18
18
|
"@sentry/node": "7.106.0",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"cli-table3": "^0.6.5",
|
|
25
25
|
"conf": "^10.2.0",
|
|
26
26
|
"cross-spawn": "^7.0.6",
|
|
27
|
+
"docker-compose": "^1.3.0",
|
|
27
28
|
"env-paths": "^2.2.1",
|
|
28
29
|
"figures": "^3.2.0",
|
|
29
30
|
"fp-ts": "^2.16.2",
|