@akash-chowdhury-24/deployhub 2.0.14 → 2.0.16
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 +98 -25
- package/package.json +1 -1
- package/src/artifact/engine.js +11 -4
- package/src/cli/index.js +4 -0
- package/src/commands/deploy.js +61 -16
- package/src/commands/doctor.js +212 -26
- package/src/commands/env.js +326 -0
- package/src/commands/init.js +97 -64
- package/src/commands/rollback.js +84 -24
- package/src/commands/sync-k8s-ports.js +71 -0
- package/src/commands/verify.js +97 -33
- package/src/core/config.js +371 -33
- package/src/core/environments.js +300 -0
- package/src/core/stages.js +55 -19
- package/src/deployment/deployment-env.js +210 -0
- package/src/deployment/index.js +58 -7
- package/src/deployment/init-prompts.js +151 -46
- package/src/deployment/providers/azure-vm.js +8 -10
- package/src/deployment/providers/docker.js +10 -2
- package/src/deployment/providers/ec2.js +7 -9
- package/src/deployment/providers/gcp-vm.js +8 -10
- package/src/deployment/providers/kubernetes.js +15 -6
- package/src/deployment/providers/ssh.js +18 -13
- package/src/storage/index.js +230 -3
- package/src/utils/build-id.js +23 -0
- package/src/utils/dockerfile-expose.js +117 -0
- package/src/utils/github-actions.js +344 -31
- package/src/utils/health-check.js +158 -0
- package/src/utils/kubernetes-manifests.js +105 -10
- package/src/utils/nginx.js +66 -15
- package/src/utils/rollback/engine.js +147 -40
- package/src/utils/scaffold.js +8 -3
package/README.md
CHANGED
|
@@ -86,7 +86,7 @@ This interactive wizard will:
|
|
|
86
86
|
- Set up storage providers (AWS, Google Drive, Azure, GCP, Dropbox, Local)
|
|
87
87
|
- Optionally configure deployment targets (SSH, Docker, EC2, Azure VM, GCP VM, Kubernetes)
|
|
88
88
|
- Generate `deployhub.config.json`
|
|
89
|
-
- Generate `.github/workflows/deployhub.yml`
|
|
89
|
+
- Generate `.github/workflows/deployhub.yml` and `.github/workflows/deployhub-rollback.yml`
|
|
90
90
|
- Generate `.env.example`
|
|
91
91
|
|
|
92
92
|
### 2. Configure credentials
|
|
@@ -182,7 +182,8 @@ The wizard asks the same core questions for every setup:
|
|
|
182
182
|
**Generated files:**
|
|
183
183
|
|
|
184
184
|
- `deployhub.config.json` — project settings (no secrets)
|
|
185
|
-
- `.github/workflows/deployhub.yml` — CI pipeline
|
|
185
|
+
- `.github/workflows/deployhub.yml` — CI deploy pipeline (push to main)
|
|
186
|
+
- `.github/workflows/deployhub-rollback.yml` — manual CI rollback (`workflow_dispatch`)
|
|
186
187
|
- `.env.example` — list of env vars you may need
|
|
187
188
|
- `nginx.conf` — auto-generated if frontend deploys to SSH
|
|
188
189
|
- `Dockerfile` — auto-generated if missing and you chose Docker or Kubernetes deploy (your existing `Dockerfile` is never overwritten)
|
|
@@ -228,12 +229,41 @@ Or push to `main` / `master` — the generated workflow runs the same command.
|
|
|
228
229
|
deployhub artifact list # local artifacts
|
|
229
230
|
deployhub artifact list --remote # include storage history.json
|
|
230
231
|
deployhub artifact restore <buildId> # download a past build
|
|
231
|
-
|
|
232
|
-
deployhub
|
|
233
|
-
deployhub
|
|
232
|
+
|
|
233
|
+
deployhub deploy # deploy latest artifact to defaultEnvironment
|
|
234
|
+
deployhub deploy --env staging # deploy one named environment
|
|
235
|
+
deployhub deploy --env all # every enabled environment (skips disabled)
|
|
236
|
+
|
|
237
|
+
deployhub rollback # previous build for defaultEnvironment
|
|
238
|
+
deployhub rollback --env production # roll back one env using its own history
|
|
239
|
+
deployhub rollback 1.0.6-a1b2c3d --env staging
|
|
240
|
+
deployhub rollback --env all # continue-on-error across enabled envs
|
|
241
|
+
|
|
242
|
+
deployhub env list # list environments (method, status, last deploy)
|
|
243
|
+
deployhub env add staging # add an environment (interactive method prompts)
|
|
244
|
+
deployhub env enable staging # include in deploy / --env all
|
|
245
|
+
deployhub env disable staging # exclude without deleting config
|
|
246
|
+
deployhub env remove staging # remove env (re-point defaultEnvironment first if needed)
|
|
247
|
+
|
|
248
|
+
deployhub sync-workflows # regenerate deploy + rollback GitHub Actions YAML
|
|
249
|
+
deployhub sync-k8s-ports # fix containerPort/targetPort in existing k8s manifests
|
|
234
250
|
deployhub logs # last deployment logs
|
|
235
251
|
```
|
|
236
252
|
|
|
253
|
+
### Rollback behavior
|
|
254
|
+
|
|
255
|
+
`deployhub rollback` restores a previous artifact from **that environment's** `envs/{env}/history.json` (legacy project `history.json` is treated as the default env's history) and redeploys it:
|
|
256
|
+
|
|
257
|
+
| Argument | Behavior |
|
|
258
|
+
|----------|----------|
|
|
259
|
+
| *(none)* | Rolls back to the **previous** build (second entry in newest-first history) |
|
|
260
|
+
| Exact `buildId` | Rolls back to that specific build |
|
|
261
|
+
| Semver / version string matching **multiple** builds | Does **not** guess — prints the matching `buildId`s and exits; re-run with an exact one |
|
|
262
|
+
|
|
263
|
+
`buildId` looks like `{semver}-{stamp}` where the stamp is a short git SHA when available, otherwise a CI run id, otherwise a high-resolution timestamp. When `DOCKER_IMAGE_TAG` is left unset, Docker and Kubernetes use that same `buildId` as the image tag — so you can correlate an artifact in storage with the image that was pushed.
|
|
264
|
+
|
|
265
|
+
For CI-triggered rollback, see [CI rollback](#ci-rollback-deployhub-rollbackyml).
|
|
266
|
+
|
|
237
267
|
---
|
|
238
268
|
|
|
239
269
|
## Walkthrough: Storage only
|
|
@@ -276,12 +306,14 @@ Artifacts appear under `artifact/{projectName}/{date}/v{buildId}/` locally.
|
|
|
276
306
|
**Remote storage** (S3 and other providers) uses a different layout:
|
|
277
307
|
|
|
278
308
|
```text
|
|
279
|
-
{project}/builds/{buildId}/artifact.zip
|
|
280
|
-
{project}/history.json
|
|
281
|
-
{project}/latest/artifact.zip
|
|
309
|
+
{project}/builds/{buildId}/artifact.zip # immutable per CI/build (shared across envs)
|
|
310
|
+
{project}/history.json # build catalog for artifact list --remote
|
|
311
|
+
{project}/latest/artifact.zip # last uploaded build (NOT a backup)
|
|
312
|
+
{project}/envs/{env}/history.json # per-environment deploy history (rollback)
|
|
313
|
+
{project}/envs/{env}/latest/artifact.zip # last deploy to that env (NOT a backup)
|
|
282
314
|
```
|
|
283
315
|
|
|
284
|
-
`buildId` is unique per pipeline run (e.g. `1.0.6-a1b2c3d`) even if `package.json` semver is unchanged. Legacy keys `{project}/v{semver}/artifact.zip` are no longer written; they remain readable for older uploads only.
|
|
316
|
+
`buildId` is unique per pipeline run (e.g. `1.0.6-a1b2c3d`) even if `package.json` semver is unchanged. Legacy keys `{project}/v{semver}/artifact.zip` are no longer written; they remain readable for older uploads only. Build once, then promote the same `buildId` to any environment with `deployhub deploy --env`.
|
|
285
317
|
|
|
286
318
|
### Same steps for other languages
|
|
287
319
|
|
|
@@ -555,17 +587,27 @@ All JS frontends share the same install/build flow: `npm ci` → `npm run build`
|
|
|
555
587
|
After `init`, commit these files:
|
|
556
588
|
|
|
557
589
|
```bash
|
|
558
|
-
git add deployhub.config.json .github/workflows/deployhub.yml .env.example
|
|
590
|
+
git add deployhub.config.json .github/workflows/deployhub.yml .github/workflows/deployhub-rollback.yml .env.example
|
|
559
591
|
git commit -m "Add DeployHub CI"
|
|
560
592
|
```
|
|
561
593
|
|
|
562
594
|
1. Open **Settings → Secrets and variables → Actions** in your GitHub repo.
|
|
563
595
|
2. Add every secret listed at the end of `deployhub init` (storage + deployment).
|
|
564
|
-
3. Push to `main` or `master` — the workflow triggers on push.
|
|
596
|
+
3. Push to `main` or `master` — the deploy workflow triggers on push.
|
|
597
|
+
|
|
598
|
+
The deploy workflow (`deployhub.yml`) installs the correct language runtime (Node, Python, Java, Go, .NET, Ruby) based on your `deployhub.config.json`, installs DeployHub, runs `deployhub build`, and uses your secrets.
|
|
599
|
+
|
|
600
|
+
To run a deploy manually: **Actions → DeployHub → Run workflow**.
|
|
565
601
|
|
|
566
|
-
|
|
602
|
+
### CI rollback (`deployhub-rollback.yml`)
|
|
567
603
|
|
|
568
|
-
|
|
604
|
+
`init` also generates a separate **DeployHub Rollback** workflow (`deployhub-rollback.yml`). It is triggered only via GitHub Actions' **Run workflow** button (not on push):
|
|
605
|
+
|
|
606
|
+
1. Open **Actions → DeployHub Rollback → Run workflow**.
|
|
607
|
+
2. Optionally enter an exact `buildId` (leave blank to roll back to the previous build).
|
|
608
|
+
3. Run the workflow.
|
|
609
|
+
|
|
610
|
+
Already-initialized projects that only have `deployhub.yml` will not get the rollback workflow from a re-run of unrelated commands — run **`deployhub sync-workflows`** once to regenerate both workflow files from your current `deployhub.config.json`, then commit and push.
|
|
569
611
|
|
|
570
612
|
---
|
|
571
613
|
|
|
@@ -648,6 +690,8 @@ DeployHub detects whether the server uses Debian-style `sites-available` or RHEL
|
|
|
648
690
|
|
|
649
691
|
### SSH
|
|
650
692
|
|
|
693
|
+
**Verification:** Real-world verified DEPLOY and ROLLBACK.
|
|
694
|
+
|
|
651
695
|
**Prerequisites (before `deployhub init`):**
|
|
652
696
|
- [ ] Complete **[one-time server setup](#one-time-server-setup-before-your-first-deploy)** (deploy path ownership + Nginx/sudo for frontends)
|
|
653
697
|
- [ ] A Linux server with SSH enabled
|
|
@@ -687,7 +731,7 @@ DeployHub detects whether the server uses Debian-style `sites-available` or RHEL
|
|
|
687
731
|
|
|
688
732
|
### Docker
|
|
689
733
|
|
|
690
|
-
**Verification:** Real-world verified (local and CI
|
|
734
|
+
**Verification:** Real-world verified DEPLOY and ROLLBACK (local and CI).
|
|
691
735
|
|
|
692
736
|
**Prerequisites:**
|
|
693
737
|
- [ ] Docker installed (`docker --version` works)
|
|
@@ -722,6 +766,8 @@ DeployHub detects whether the server uses Debian-style `sites-available` or RHEL
|
|
|
722
766
|
|
|
723
767
|
### AWS EC2
|
|
724
768
|
|
|
769
|
+
**Verification:** Real-world verified DEPLOY and ROLLBACK.
|
|
770
|
+
|
|
725
771
|
**Prerequisites:**
|
|
726
772
|
- [ ] Complete **[one-time server setup](#one-time-server-setup-before-your-first-deploy)** (`ec2-user` on Amazon Linux)
|
|
727
773
|
- [ ] EC2 instance launched in AWS Console (DeployHub does not create it)
|
|
@@ -758,6 +804,8 @@ DeployHub detects whether the server uses Debian-style `sites-available` or RHEL
|
|
|
758
804
|
|
|
759
805
|
### Azure VM
|
|
760
806
|
|
|
807
|
+
**Verification:** Real-world verified DEPLOY. Rollback logic confirmed via shared-SSH-path audit; not yet live-tested independently.
|
|
808
|
+
|
|
761
809
|
**Prerequisites:**
|
|
762
810
|
- [ ] Complete **[one-time server setup](#one-time-server-setup-before-your-first-deploy)** (`azureuser` or your VM login user)
|
|
763
811
|
- [ ] Azure VM created in Portal (DeployHub does not provision it)
|
|
@@ -792,6 +840,8 @@ DeployHub detects whether the server uses Debian-style `sites-available` or RHEL
|
|
|
792
840
|
|
|
793
841
|
### GCP VM
|
|
794
842
|
|
|
843
|
+
**Verification:** Real-world verified DEPLOY. Rollback logic confirmed via shared-SSH-path audit; not yet live-tested independently.
|
|
844
|
+
|
|
795
845
|
**Prerequisites:**
|
|
796
846
|
- [ ] Complete **[one-time server setup](#one-time-server-setup-before-your-first-deploy)** (your GCP SSH username)
|
|
797
847
|
- [ ] Compute Engine VM created (DeployHub does not create it)
|
|
@@ -832,7 +882,7 @@ DeployHub detects whether the server uses Debian-style `sites-available` or RHEL
|
|
|
832
882
|
|
|
833
883
|
### Kubernetes
|
|
834
884
|
|
|
835
|
-
**Verification:** Real-world verified (including k3s and CI
|
|
885
|
+
**Verification:** Real-world verified DEPLOY and ROLLBACK (including k3s and CI).
|
|
836
886
|
|
|
837
887
|
**Prerequisites:**
|
|
838
888
|
- [ ] Existing Kubernetes cluster (DeployHub does not provision clusters)
|
|
@@ -868,7 +918,7 @@ DeployHub detects whether the server uses Debian-style `sites-available` or RHEL
|
|
|
868
918
|
6. Add GitHub Secrets for CI (see table — **`KUBECONFIG` must be the file contents, not a path**)
|
|
869
919
|
7. Run `deployhub doctor`, then `git push origin main`
|
|
870
920
|
|
|
871
|
-
> **
|
|
921
|
+
> **Ports in generated Kubernetes manifests:** `containerPort` and `targetPort` are derived from your project's Dockerfile `EXPOSE` line (frontend / nginx images correctly get **80**; backends get their real exposed port). If no Dockerfile or usable `EXPOSE` exists yet, DeployHub falls back to a per-project-type default that matches its Dockerfile templates. Fresh `init` does **not** require a manual port edit. The Service's external `port:` stays **80** for all project types by design (Ingress-friendly); only the internal `targetPort` / `containerPort` track the container. Already-initialized projects with stale `3000` values can run `deployhub sync-k8s-ports` to patch just those fields.
|
|
872
922
|
|
|
873
923
|
| Variable | Description | Example | Where to get it |
|
|
874
924
|
|----------|-------------|---------|-----------------|
|
|
@@ -952,21 +1002,35 @@ Run `deployhub doctor` after any config change.
|
|
|
952
1002
|
|
|
953
1003
|
| Command | Description |
|
|
954
1004
|
|---------|-------------|
|
|
955
|
-
| `deployhub init` | Interactive project setup |
|
|
956
|
-
| `deployhub build` | Full pipeline: detect → install → test → build → artifact → storage → deploy |
|
|
1005
|
+
| `deployhub init` | Interactive project setup (one or multiple environments) |
|
|
1006
|
+
| `deployhub build` | Full pipeline: detect → install → test → build → artifact → storage → deploy (default / push-triggered envs) |
|
|
957
1007
|
| `deployhub artifact create` | Create artifact from current build |
|
|
958
1008
|
| `deployhub artifact list [--remote]` | List local artifacts; `--remote` merges storage `history.json` |
|
|
959
1009
|
| `deployhub artifact restore <buildId\|semver>` | Download and extract an artifact |
|
|
960
1010
|
| `deployhub storage add <provider>` | Add storage provider credentials |
|
|
961
1011
|
| `deployhub storage list` | List storage providers and connection status |
|
|
962
|
-
| `deployhub deploy` | Deploy latest artifact |
|
|
963
|
-
| `deployhub
|
|
1012
|
+
| `deployhub deploy` | Deploy latest artifact to `defaultEnvironment` |
|
|
1013
|
+
| `deployhub deploy --env staging` | Deploy to one named environment |
|
|
1014
|
+
| `deployhub deploy --env all` | Deploy to every enabled environment (skips disabled) |
|
|
1015
|
+
| `deployhub rollback` | Roll back `defaultEnvironment` to its previous build |
|
|
1016
|
+
| `deployhub rollback --env production` | Roll back one env from `envs/{env}/history.json` |
|
|
1017
|
+
| `deployhub rollback <buildId> --env staging` | Restore an exact `buildId` to that environment |
|
|
1018
|
+
| `deployhub rollback --env all` | Roll back each enabled env (continue-on-error + summary) |
|
|
1019
|
+
| `deployhub env list` | List environments (method, enabled, trigger, last deploy) |
|
|
1020
|
+
| `deployhub env add <name>` | Add an environment (interactive method prompts; regenerates workflows) |
|
|
1021
|
+
| `deployhub env enable <name>` | Enable an environment for deploy / `--env all` |
|
|
1022
|
+
| `deployhub env disable <name>` | Disable without deleting config |
|
|
1023
|
+
| `deployhub env remove <name>` | Remove an environment (re-point `defaultEnvironment` first if needed) |
|
|
1024
|
+
| `deployhub sync-workflows` | Regenerate `.github/workflows/deployhub.yml` and `deployhub-rollback.yml` from config |
|
|
1025
|
+
| `deployhub sync-k8s-ports` | Update only `containerPort` / `targetPort` in `k8s/deployment.yaml` and `k8s/service.yaml` from Dockerfile `EXPOSE` (or config/fallback). Does **not** change replicas, resources, env, or probes. Heavily customized / multi-container manifests may need a manual review |
|
|
964
1026
|
| `deployhub logs` | Show logs from last deployment |
|
|
965
|
-
| `deployhub doctor` | Pre-flight checks |
|
|
1027
|
+
| `deployhub doctor [--all]` | Pre-flight checks per environment (`--all` includes disabled envs as informational) |
|
|
966
1028
|
| `deployhub verify` | Health check on configured endpoint |
|
|
967
1029
|
| `deployhub clean` | Remove old local artifacts |
|
|
968
1030
|
| `deployhub update` | Check for CLI updates |
|
|
969
1031
|
|
|
1032
|
+
**Tests:** `npm test` — currently **270 passing** across the Jest suites.
|
|
1033
|
+
|
|
970
1034
|
## GitHub Secrets
|
|
971
1035
|
|
|
972
1036
|
Add these secrets in your repository (Settings → Secrets and variables → Actions). Only add secrets for providers you selected during `init`. At the end of `deployhub init`, DeployHub prints the exact list for your project.
|
|
@@ -1009,6 +1073,8 @@ Add these secrets in your repository (Settings → Secrets and variables → Act
|
|
|
1009
1073
|
| `DOCKER_IMAGE_NAME`, `DOCKER_REGISTRY_USERNAME`, `DOCKER_REGISTRY_TOKEN`, `DOCKER_REGISTRY_URL`, `DOCKER_HOST` | Docker deployment (`DOCKER_IMAGE_TAG` optional) |
|
|
1010
1074
|
| `KUBECONFIG`, `KUBE_CONTEXT`, `KUBE_NAMESPACE`, `DOCKER_IMAGE_NAME`, `DOCKER_REGISTRY_USERNAME`, `DOCKER_REGISTRY_TOKEN`, `DOCKER_REGISTRY_URL`, `DOCKER_IMAGE_TAG`, `KUBE_IMAGE_PULL_SECRET` | Kubernetes — **`KUBECONFIG` in GitHub Secrets must be the kubeconfig file contents (or base64), not a filesystem path**. `DOCKER_IMAGE_TAG`, `KUBE_NAMESPACE`, `DOCKER_REGISTRY_URL`, and `KUBE_IMAGE_PULL_SECRET` are optional |
|
|
1011
1075
|
|
|
1076
|
+
**Kubernetes rollback vs deploy — registry credentials:** Kubernetes **rollback** specifically **requires** `DOCKER_REGISTRY_USERNAME` and `DOCKER_REGISTRY_TOKEN`. Rollback rebuilds and must push a fresh image tagged with the restored `buildId`; without registry credentials it fails loudly and early (a rollback that cannot push can never succeed against a real cluster). This is stricter than a normal Kubernetes **deploy**, which may still allow local-only / no-push flows in some setups. If deploy worked without those secrets but rollback fails asking for them, that asymmetry is intentional.
|
|
1077
|
+
|
|
1012
1078
|
See [Deployment method guides](#deployment-method-guides) for full per-method variable tables with examples.
|
|
1013
1079
|
|
|
1014
1080
|
## `deployhub doctor` Output
|
|
@@ -1025,11 +1091,16 @@ The doctor command runs independent checks and always completes without crashing
|
|
|
1025
1091
|
Checking Health endpoint... ✓ URL reachable (HTTP 200)
|
|
1026
1092
|
Checking Secrets... ✓ All required env vars present
|
|
1027
1093
|
Checking GitHub Actions... ✓ Workflow file exists at .github/workflows/deployhub.yml
|
|
1094
|
+
Checking Rollback workflow... ✓ Missing .github/workflows/deployhub-rollback.yml — run deployhub sync-workflows to add CI rollback (workflow_dispatch)
|
|
1028
1095
|
Checking Storage write... ✓ Test upload succeeded
|
|
1029
1096
|
|
|
1030
|
-
✓ Ready to deploy (
|
|
1097
|
+
✓ Ready to deploy (11/11 checks passed)
|
|
1031
1098
|
```
|
|
1032
1099
|
|
|
1100
|
+
The **Rollback workflow** check is informational and non-blocking (`✓` even when the file is missing). It suggests `deployhub sync-workflows` so already-initialized projects can pick up `deployhub-rollback.yml` without a full re-init. When the file exists, the message confirms the path instead.
|
|
1101
|
+
|
|
1102
|
+
If checked-in workflow files exist but are **out of date** with `deployhub.config.json` (e.g. you ran `env add` or a silent migration and forgot `sync-workflows`), doctor also reports an informational **Workflow sync** nudge naming the missing environment or secret and suggesting `deployhub sync-workflows`. That check never fails the doctor exit code.
|
|
1103
|
+
|
|
1033
1104
|
If checks fail:
|
|
1034
1105
|
|
|
1035
1106
|
```
|
|
@@ -1062,9 +1133,11 @@ artifact/
|
|
|
1062
1133
|
**Remote keys** (all storage providers):
|
|
1063
1134
|
|
|
1064
1135
|
```
|
|
1065
|
-
{project}/builds/{buildId}/artifact.zip
|
|
1066
|
-
{project}/history.json
|
|
1067
|
-
{project}/latest/artifact.zip
|
|
1136
|
+
{project}/builds/{buildId}/artifact.zip # immutable per CI/build (shared across envs)
|
|
1137
|
+
{project}/history.json # build catalog for artifact list --remote
|
|
1138
|
+
{project}/latest/artifact.zip # overwritten every build — convenience pointer only
|
|
1139
|
+
{project}/envs/{env}/history.json # per-environment deploy history (rollback)
|
|
1140
|
+
{project}/envs/{env}/latest/artifact.zip # last deploy to that env (NOT a backup)
|
|
1068
1141
|
```
|
|
1069
1142
|
|
|
1070
1143
|
Legacy (read-only fallback, no longer written): `{project}/v{semver}/artifact.zip`
|
package/package.json
CHANGED
package/src/artifact/engine.js
CHANGED
|
@@ -13,6 +13,12 @@ import {
|
|
|
13
13
|
copyDeployAssetsToArtifactDir,
|
|
14
14
|
} from '../utils/scaffold.js';
|
|
15
15
|
import { getGeneratedByMetadata, getArtifactReadmeFooter } from '../utils/author.js';
|
|
16
|
+
import {
|
|
17
|
+
getEnabledEnvironmentNames,
|
|
18
|
+
getEnvMethod,
|
|
19
|
+
getEnvSettings,
|
|
20
|
+
resolveDefaultEnvironmentName,
|
|
21
|
+
} from '../core/config.js';
|
|
16
22
|
|
|
17
23
|
/**
|
|
18
24
|
* @param {string} cwd
|
|
@@ -151,13 +157,14 @@ async function stageFrontendArtifact(cwd, stagingDir, config) {
|
|
|
151
157
|
|
|
152
158
|
await copyKubernetesManifestsIfPresent(cwd, stagingDir);
|
|
153
159
|
|
|
154
|
-
const
|
|
155
|
-
|
|
160
|
+
const deployTargets = getEnabledEnvironmentNames(config);
|
|
161
|
+
const hasSshDeploy = deployTargets.some(
|
|
162
|
+
(envName) => getEnvMethod(config.environments[envName]) === 'ssh'
|
|
156
163
|
);
|
|
157
164
|
|
|
158
165
|
if (hasSshDeploy && !fs.existsSync(path.join(stagingDir, 'nginx.conf'))) {
|
|
159
|
-
const envName = config
|
|
160
|
-
const env = envName ? config.environments[envName] : null;
|
|
166
|
+
const envName = resolveDefaultEnvironmentName(config) || deployTargets[0];
|
|
167
|
+
const env = envName ? getEnvSettings(config.environments[envName]) : null;
|
|
161
168
|
const deployPath =
|
|
162
169
|
env?.frontendDeployPath || env?.deployPath || env?.path || `/var/www/${config.project}`;
|
|
163
170
|
const nginxConf = generateNginxConfig(config.project, deployPath, outputName);
|
package/src/cli/index.js
CHANGED
|
@@ -14,6 +14,8 @@ import { registerVerifyCommand } from '../commands/verify.js';
|
|
|
14
14
|
import { registerCleanCommand } from '../commands/clean.js';
|
|
15
15
|
import { registerUpdateCommand } from '../commands/update.js';
|
|
16
16
|
import { registerSyncWorkflowsCommand } from '../commands/sync-workflows.js';
|
|
17
|
+
import { registerSyncK8sPortsCommand } from '../commands/sync-k8s-ports.js';
|
|
18
|
+
import { registerEnvCommand } from '../commands/env.js';
|
|
17
19
|
import { formatVersionOutput, printBanner, shouldShowBanner } from '../utils/author.js';
|
|
18
20
|
|
|
19
21
|
loadEnv();
|
|
@@ -43,5 +45,7 @@ registerVerifyCommand(program);
|
|
|
43
45
|
registerCleanCommand(program);
|
|
44
46
|
registerUpdateCommand(program);
|
|
45
47
|
registerSyncWorkflowsCommand(program);
|
|
48
|
+
registerSyncK8sPortsCommand(program);
|
|
49
|
+
registerEnvCommand(program);
|
|
46
50
|
|
|
47
51
|
program.parse();
|
package/src/commands/deploy.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { loadConfig, loadEnv } from '../core/config.js';
|
|
3
|
+
import { resolveEnvTargets } from '../core/environments.js';
|
|
3
4
|
import { runPipeline } from '../core/pipeline.js';
|
|
4
5
|
import { listLocalArtifacts } from '../artifact/engine.js';
|
|
5
6
|
import { deployToAll } from '../deployment/index.js';
|
|
6
7
|
import { sendNotifications } from '../notifications/index.js';
|
|
7
|
-
import
|
|
8
|
+
import {
|
|
9
|
+
anyEnvHasResolvableHealthCheckUrl,
|
|
10
|
+
runHealthChecksForEnvs,
|
|
11
|
+
formatHealthCheckAllSummary,
|
|
12
|
+
} from '../utils/health-check.js';
|
|
13
|
+
import { createLogger } from '../logger/index.js';
|
|
8
14
|
|
|
9
15
|
/**
|
|
10
16
|
* @param {import('commander').Command} program
|
|
@@ -12,11 +18,34 @@ import axios from 'axios';
|
|
|
12
18
|
export function registerDeployCommand(program) {
|
|
13
19
|
program
|
|
14
20
|
.command('deploy')
|
|
15
|
-
.description('Deploy the latest artifact')
|
|
16
|
-
.
|
|
21
|
+
.description('Deploy the latest artifact (default environment, or --env)')
|
|
22
|
+
.option(
|
|
23
|
+
'--env <name>',
|
|
24
|
+
'Environment to deploy (name, or "all" for every enabled environment)'
|
|
25
|
+
)
|
|
26
|
+
.action(async (opts) => {
|
|
17
27
|
loadEnv();
|
|
18
28
|
const cwd = process.cwd();
|
|
19
29
|
const config = await loadConfig(cwd);
|
|
30
|
+
const log = createLogger('deploy');
|
|
31
|
+
|
|
32
|
+
let targets;
|
|
33
|
+
let skippedDisabled;
|
|
34
|
+
try {
|
|
35
|
+
({ targets, skippedDisabled } = resolveEnvTargets(config, opts.env));
|
|
36
|
+
} catch (err) {
|
|
37
|
+
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
for (const name of skippedDisabled) {
|
|
42
|
+
log.info(`Skipping disabled environment "${name}"`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (targets.length === 0) {
|
|
46
|
+
console.error(chalk.red('No enabled environments to deploy.'));
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
20
49
|
|
|
21
50
|
const artifacts = await listLocalArtifacts(cwd);
|
|
22
51
|
if (artifacts.length === 0) {
|
|
@@ -34,27 +63,43 @@ export function registerDeployCommand(program) {
|
|
|
34
63
|
async run(ctx) {
|
|
35
64
|
const deployed = await deployToAll(
|
|
36
65
|
ctx.config,
|
|
37
|
-
/** @type {string} */ (ctx.state.artifactDir)
|
|
66
|
+
/** @type {string} */ (ctx.state.artifactDir),
|
|
67
|
+
targets
|
|
38
68
|
);
|
|
39
69
|
ctx.state.deployedTargets = deployed;
|
|
40
70
|
},
|
|
41
71
|
},
|
|
42
72
|
{
|
|
43
73
|
name: 'verify',
|
|
44
|
-
enabled: (ctx) =>
|
|
74
|
+
enabled: (ctx) => {
|
|
75
|
+
const deployed = /** @type {string[]} */ (
|
|
76
|
+
ctx.state.deployedTargets || targets
|
|
77
|
+
);
|
|
78
|
+
return anyEnvHasResolvableHealthCheckUrl(ctx.config, deployed);
|
|
79
|
+
},
|
|
45
80
|
async run(ctx) {
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (
|
|
55
|
-
|
|
81
|
+
const deployed = /** @type {string[]} */ (
|
|
82
|
+
ctx.state.deployedTargets || targets
|
|
83
|
+
);
|
|
84
|
+
const { results, failures } = await runHealthChecksForEnvs(
|
|
85
|
+
ctx.config,
|
|
86
|
+
deployed
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
if (deployed.length > 1 || failures.length > 0) {
|
|
90
|
+
console.log('');
|
|
91
|
+
console.log(formatHealthCheckAllSummary(results, failures));
|
|
92
|
+
} else if (results[0]) {
|
|
93
|
+
console.log(
|
|
94
|
+
chalk.green(
|
|
95
|
+
`Health check passed (${results[0].envName}): HTTP ${results[0].status} (${results[0].elapsed}ms)`
|
|
96
|
+
)
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (failures.length > 0) {
|
|
101
|
+
throw new Error(failures[0].error);
|
|
56
102
|
}
|
|
57
|
-
console.log(chalk.green(`Health check passed: ${response.status} (${elapsed}ms)`));
|
|
58
103
|
},
|
|
59
104
|
},
|
|
60
105
|
{
|