@companyhelm/cli 0.1.2 → 0.1.4

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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +40 -33
  3. package/dist/cli.js +11 -1
  4. package/dist/commands/dependencies.d.ts +18 -3
  5. package/dist/commands/dependencies.js +76 -13
  6. package/dist/commands/interactive.d.ts +6 -0
  7. package/dist/commands/interactive.js +22 -0
  8. package/dist/commands/logs.js +6 -1
  9. package/dist/commands/register-commands.js +4 -0
  10. package/dist/commands/reset.d.ts +4 -0
  11. package/dist/commands/reset.js +43 -4
  12. package/dist/commands/set-image-version.d.ts +31 -0
  13. package/dist/commands/set-image-version.js +87 -0
  14. package/dist/commands/setup-github-app.d.ts +10 -0
  15. package/dist/commands/setup-github-app.js +211 -0
  16. package/dist/commands/status.js +3 -1
  17. package/dist/commands/up.js +11 -2
  18. package/dist/core/bootstrap/DeploymentBootstrapper.d.ts +2 -2
  19. package/dist/core/bootstrap/DeploymentBootstrapper.js +5 -7
  20. package/dist/core/bootstrap/SeedSqlRenderer.js +23 -5
  21. package/dist/core/config/ApiEnvFileWriter.d.ts +6 -0
  22. package/dist/core/config/ApiEnvFileWriter.js +26 -0
  23. package/dist/core/config/GithubAppConfig.d.ts +6 -0
  24. package/dist/core/config/GithubAppConfig.js +26 -0
  25. package/dist/core/config/GithubAppConfigStore.d.ts +11 -0
  26. package/dist/core/config/GithubAppConfigStore.js +65 -0
  27. package/dist/core/docker/ComposeTemplateRenderer.d.ts +6 -1
  28. package/dist/core/docker/ComposeTemplateRenderer.js +22 -4
  29. package/dist/core/docker/DockerStackManager.d.ts +15 -3
  30. package/dist/core/docker/DockerStackManager.js +67 -8
  31. package/dist/core/runner/RunnerSupervisor.d.ts +4 -0
  32. package/dist/core/runner/RunnerSupervisor.js +19 -3
  33. package/dist/core/runtime/ImageCatalog.js +5 -2
  34. package/dist/core/runtime/LocalConfigStore.d.ts +16 -0
  35. package/dist/core/runtime/LocalConfigStore.js +59 -0
  36. package/dist/core/runtime/ManagedImages.d.ts +10 -0
  37. package/dist/core/runtime/ManagedImages.js +27 -0
  38. package/dist/core/runtime/ProjectPaths.d.ts +7 -0
  39. package/dist/core/runtime/ProjectPaths.js +16 -0
  40. package/dist/core/runtime/PublicImageTagRegistry.d.ts +16 -0
  41. package/dist/core/runtime/PublicImageTagRegistry.js +148 -0
  42. package/dist/core/runtime/RuntimeState.d.ts +1 -1
  43. package/dist/core/runtime/RuntimeStateStore.d.ts +1 -0
  44. package/dist/core/runtime/RuntimeStateStore.js +8 -2
  45. package/dist/core/runtime/VersionCatalog.d.ts +10 -0
  46. package/dist/core/runtime/VersionCatalog.js +21 -0
  47. package/dist/core/status/StatusService.d.ts +5 -1
  48. package/dist/core/status/StatusService.js +5 -2
  49. package/dist/core/ui/TerminalRenderer.d.ts +10 -0
  50. package/dist/core/ui/TerminalRenderer.js +48 -0
  51. package/dist/templates/docker-compose.yaml.tpl +4 -13
  52. package/dist/templates/seed.sql.tpl +32 -13
  53. package/package.json +7 -3
  54. package/src/templates/docker-compose.yaml.tpl +4 -13
  55. package/src/templates/seed.sql.tpl +32 -13
@@ -2,6 +2,8 @@ import chalk from "chalk";
2
2
  import figlet from "figlet";
3
3
  export class TerminalRenderer {
4
4
  useColor;
5
+ static OSC = "\u001B]";
6
+ static BEL = "\u0007";
5
7
  constructor(useColor = true) {
6
8
  this.useColor = useColor;
7
9
  }
@@ -14,6 +16,52 @@ export class TerminalRenderer {
14
16
  success(message) {
15
17
  return `${this.colorize("[ok]", "green")} ${message}`;
16
18
  }
19
+ progress(message) {
20
+ return this.colorize(`... ${message}`, "cyan");
21
+ }
22
+ successHighlight(message) {
23
+ if (!this.useColor) {
24
+ return message;
25
+ }
26
+ return chalk.green.bold(message);
27
+ }
28
+ clickableUrl(url) {
29
+ if (!this.useColor) {
30
+ return url;
31
+ }
32
+ const display = this.successHighlight(url);
33
+ return `${TerminalRenderer.OSC}8;;${url}${TerminalRenderer.BEL}${display}${TerminalRenderer.OSC}8;;${TerminalRenderer.BEL}`;
34
+ }
35
+ renderStatus(report) {
36
+ const lines = ["Status"];
37
+ lines.push(this.renderServiceLine("Postgres", report.services.postgres));
38
+ lines.push(this.renderServiceLine("API", report.services.api, report.apiUrl));
39
+ lines.push(this.renderServiceLine("Frontend", report.services.frontend, report.uiUrl));
40
+ lines.push(this.renderServiceLine("Runner", report.services.runner));
41
+ if (report.versions) {
42
+ lines.push(`CompanyHelm CLI: ${report.versions.cliPackage}`);
43
+ lines.push(`Runner package: ${report.versions.runnerPackage}`);
44
+ lines.push(`API image: ${report.versions.images.api}`);
45
+ lines.push(`Frontend image: ${report.versions.images.frontend}`);
46
+ lines.push(`Postgres image: ${report.versions.images.postgres}`);
47
+ }
48
+ if (report.username) {
49
+ lines.push(`username: ${report.username}`);
50
+ }
51
+ return lines.join("\n");
52
+ }
53
+ renderServiceLine(label, status, detail) {
54
+ const statusLabel = status === "running" ? this.success("running") : this.warn("stopped");
55
+ return detail && status === "running"
56
+ ? `${label}: ${statusLabel} (${this.formatDetail(detail)})`
57
+ : `${label}: ${statusLabel}`;
58
+ }
59
+ warn(message) {
60
+ return `${this.colorize("[!]", "yellow")} ${message}`;
61
+ }
62
+ formatDetail(detail) {
63
+ return detail.startsWith("http://") || detail.startsWith("https://") ? this.clickableUrl(detail) : detail;
64
+ }
17
65
  colorize(text, color) {
18
66
  if (!this.useColor) {
19
67
  return text;
@@ -13,8 +13,11 @@ services:
13
13
 
14
14
  api:
15
15
  image: {{API_IMAGE}}
16
+ platform: linux/amd64
16
17
  depends_on:
17
18
  - postgres
19
+ env_file:
20
+ - "{{API_ENV_PATH}}"
18
21
  environment:
19
22
  COMPANYHELM_CONFIG_PATH: /run/companyhelm/config.yaml
20
23
  ports:
@@ -26,19 +29,7 @@ services:
26
29
  networks:
27
30
  - companyhelm
28
31
 
29
- frontend:
30
- image: {{FRONTEND_IMAGE}}
31
- depends_on:
32
- - api
33
- environment:
34
- COMPANYHELM_CONFIG_PATH: /run/companyhelm/config.yaml
35
- PORT: "{{UI_PORT}}"
36
- ports:
37
- - "{{UI_PORT}}:{{UI_PORT}}"
38
- volumes:
39
- - "{{FRONTEND_CONFIG_PATH}}:/run/companyhelm/config.yaml:ro"
40
- networks:
41
- - companyhelm
32
+ {{FRONTEND_SERVICE_BLOCK}}
42
33
 
43
34
  networks:
44
35
  companyhelm:
@@ -5,8 +5,17 @@ VALUES ('{{COMPANY_ID}}', '{{COMPANY_NAME}}')
5
5
  ON CONFLICT (id) DO UPDATE
6
6
  SET name = EXCLUDED.name;
7
7
 
8
+ UPDATE users
9
+ SET first_name = '{{USER_FIRST_NAME}}',
10
+ last_name = NULL,
11
+ email = '{{USER_EMAIL}}',
12
+ auth_provider = 'companyhelm',
13
+ updated_at = NOW()
14
+ WHERE id = '{{USER_ID}}'
15
+ OR email = '{{USER_EMAIL}}';
16
+
8
17
  INSERT INTO users (id, first_name, last_name, email, auth_provider, created_at, updated_at)
9
- VALUES (
18
+ SELECT
10
19
  '{{USER_ID}}',
11
20
  '{{USER_FIRST_NAME}}',
12
21
  NULL,
@@ -14,14 +23,24 @@ VALUES (
14
23
  'companyhelm',
15
24
  NOW(),
16
25
  NOW()
17
- )
18
- ON CONFLICT (email) DO UPDATE
19
- SET first_name = EXCLUDED.first_name,
20
- auth_provider = EXCLUDED.auth_provider,
21
- updated_at = NOW();
26
+ WHERE NOT EXISTS (
27
+ SELECT 1
28
+ FROM users
29
+ WHERE id = '{{USER_ID}}'
30
+ OR email = '{{USER_EMAIL}}'
31
+ );
32
+
33
+ UPDATE user_auths
34
+ SET user_id = '{{USER_ID}}',
35
+ email = '{{USER_EMAIL}}',
36
+ password_salt = '{{PASSWORD_SALT}}',
37
+ password_hash = '{{PASSWORD_HASH}}',
38
+ updated_at = NOW()
39
+ WHERE user_id = '{{USER_ID}}'
40
+ OR email = '{{USER_EMAIL}}';
22
41
 
23
42
  INSERT INTO user_auths (id, user_id, email, password_salt, password_hash, created_at, updated_at)
24
- VALUES (
43
+ SELECT
25
44
  '{{USER_AUTH_ID}}',
26
45
  '{{USER_ID}}',
27
46
  '{{USER_EMAIL}}',
@@ -29,12 +48,12 @@ VALUES (
29
48
  '{{PASSWORD_HASH}}',
30
49
  NOW(),
31
50
  NOW()
32
- )
33
- ON CONFLICT (user_id) DO UPDATE
34
- SET email = EXCLUDED.email,
35
- password_salt = EXCLUDED.password_salt,
36
- password_hash = EXCLUDED.password_hash,
37
- updated_at = NOW();
51
+ WHERE NOT EXISTS (
52
+ SELECT 1
53
+ FROM user_auths
54
+ WHERE user_id = '{{USER_ID}}'
55
+ OR email = '{{USER_EMAIL}}'
56
+ );
38
57
 
39
58
  INSERT INTO company_members (company_id, user_id)
40
59
  VALUES ('{{COMPANY_ID}}', '{{USER_ID}}')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@companyhelm/cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Bootstrap and manage a local CompanyHelm deployment.",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -21,14 +21,18 @@
21
21
  ],
22
22
  "scripts": {
23
23
  "build": "tsc -p tsconfig.json && node scripts/copy-templates.cjs",
24
+ "set-image-version": "npm run build && node dist/cli.js set-image-version",
25
+ "start": "npm run build && node dist/cli.js",
24
26
  "test": "npm run build && vitest run"
25
27
  },
26
28
  "dependencies": {
27
- "@companyhelm/runner": "^0.0.13",
29
+ "@clack/prompts": "^1.1.0",
30
+ "@companyhelm/runner": "^0.1.1",
28
31
  "chalk": "^5.6.2",
29
32
  "commander": "^14.0.1",
30
33
  "dockerode": "^4.0.9",
31
- "figlet": "^1.9.4"
34
+ "figlet": "^1.9.4",
35
+ "yaml": "^2.8.1"
32
36
  },
33
37
  "devDependencies": {
34
38
  "@types/dockerode": "^3.3.44",
@@ -13,8 +13,11 @@ services:
13
13
 
14
14
  api:
15
15
  image: {{API_IMAGE}}
16
+ platform: linux/amd64
16
17
  depends_on:
17
18
  - postgres
19
+ env_file:
20
+ - "{{API_ENV_PATH}}"
18
21
  environment:
19
22
  COMPANYHELM_CONFIG_PATH: /run/companyhelm/config.yaml
20
23
  ports:
@@ -26,19 +29,7 @@ services:
26
29
  networks:
27
30
  - companyhelm
28
31
 
29
- frontend:
30
- image: {{FRONTEND_IMAGE}}
31
- depends_on:
32
- - api
33
- environment:
34
- COMPANYHELM_CONFIG_PATH: /run/companyhelm/config.yaml
35
- PORT: "{{UI_PORT}}"
36
- ports:
37
- - "{{UI_PORT}}:{{UI_PORT}}"
38
- volumes:
39
- - "{{FRONTEND_CONFIG_PATH}}:/run/companyhelm/config.yaml:ro"
40
- networks:
41
- - companyhelm
32
+ {{FRONTEND_SERVICE_BLOCK}}
42
33
 
43
34
  networks:
44
35
  companyhelm:
@@ -5,8 +5,17 @@ VALUES ('{{COMPANY_ID}}', '{{COMPANY_NAME}}')
5
5
  ON CONFLICT (id) DO UPDATE
6
6
  SET name = EXCLUDED.name;
7
7
 
8
+ UPDATE users
9
+ SET first_name = '{{USER_FIRST_NAME}}',
10
+ last_name = NULL,
11
+ email = '{{USER_EMAIL}}',
12
+ auth_provider = 'companyhelm',
13
+ updated_at = NOW()
14
+ WHERE id = '{{USER_ID}}'
15
+ OR email = '{{USER_EMAIL}}';
16
+
8
17
  INSERT INTO users (id, first_name, last_name, email, auth_provider, created_at, updated_at)
9
- VALUES (
18
+ SELECT
10
19
  '{{USER_ID}}',
11
20
  '{{USER_FIRST_NAME}}',
12
21
  NULL,
@@ -14,14 +23,24 @@ VALUES (
14
23
  'companyhelm',
15
24
  NOW(),
16
25
  NOW()
17
- )
18
- ON CONFLICT (email) DO UPDATE
19
- SET first_name = EXCLUDED.first_name,
20
- auth_provider = EXCLUDED.auth_provider,
21
- updated_at = NOW();
26
+ WHERE NOT EXISTS (
27
+ SELECT 1
28
+ FROM users
29
+ WHERE id = '{{USER_ID}}'
30
+ OR email = '{{USER_EMAIL}}'
31
+ );
32
+
33
+ UPDATE user_auths
34
+ SET user_id = '{{USER_ID}}',
35
+ email = '{{USER_EMAIL}}',
36
+ password_salt = '{{PASSWORD_SALT}}',
37
+ password_hash = '{{PASSWORD_HASH}}',
38
+ updated_at = NOW()
39
+ WHERE user_id = '{{USER_ID}}'
40
+ OR email = '{{USER_EMAIL}}';
22
41
 
23
42
  INSERT INTO user_auths (id, user_id, email, password_salt, password_hash, created_at, updated_at)
24
- VALUES (
43
+ SELECT
25
44
  '{{USER_AUTH_ID}}',
26
45
  '{{USER_ID}}',
27
46
  '{{USER_EMAIL}}',
@@ -29,12 +48,12 @@ VALUES (
29
48
  '{{PASSWORD_HASH}}',
30
49
  NOW(),
31
50
  NOW()
32
- )
33
- ON CONFLICT (user_id) DO UPDATE
34
- SET email = EXCLUDED.email,
35
- password_salt = EXCLUDED.password_salt,
36
- password_hash = EXCLUDED.password_hash,
37
- updated_at = NOW();
51
+ WHERE NOT EXISTS (
52
+ SELECT 1
53
+ FROM user_auths
54
+ WHERE user_id = '{{USER_ID}}'
55
+ OR email = '{{USER_EMAIL}}'
56
+ );
38
57
 
39
58
  INSERT INTO company_members (company_id, user_id)
40
59
  VALUES ('{{COMPANY_ID}}', '{{USER_ID}}')